From 081fc03556708447610e9697a57235fa191a4f0d Mon Sep 17 00:00:00 2001 From: Kevin Smith Date: Thu, 6 May 2010 08:00:44 +0000 Subject: Rewrite of large amounts of roster code. Now keeps widgets out of Swiften, keeps sorting inside Swiften, and keeps track of presences to show the correct presence per roster item. Resolves: #316 Resolves: #81 Resolves: #239 diff --git a/Swift/Controllers/Chat/ChatController.cpp b/Swift/Controllers/Chat/ChatController.cpp index 6056fc5..2e1b1c8 100644 --- a/Swift/Controllers/Chat/ChatController.cpp +++ b/Swift/Controllers/Chat/ChatController.cpp @@ -21,8 +21,8 @@ namespace Swift { /** * The controller does not gain ownership of the stanzaChannel, nor the factory. */ -ChatController::ChatController(const JID& self, StanzaChannel* stanzaChannel, IQRouter* iqRouter, ChatWindowFactory* chatWindowFactory, const JID &contact, NickResolver* nickResolver, PresenceOracle* presenceOracle, AvatarManager* avatarManager, bool isInMUC, bool useDelayForLatency) - : ChatControllerBase(self, stanzaChannel, iqRouter, chatWindowFactory, contact, presenceOracle, avatarManager, useDelayForLatency) { +ChatController::ChatController(const JID& self, StanzaChannel* stanzaChannel, IQRouter* iqRouter, ChatWindowFactory* chatWindowFactory, const JID &contact, NickResolver* nickResolver, PresenceOracle* presenceOracle, AvatarManager* avatarManager, bool isInMUC, bool useDelayForLatency, UIEventStream* eventStream) + : ChatControllerBase(self, stanzaChannel, iqRouter, chatWindowFactory, contact, presenceOracle, avatarManager, useDelayForLatency, eventStream) { isInMUC_ = isInMUC; chatStateNotifier_ = new ChatStateNotifier(); chatStateMessageSender_ = new ChatStateMessageSender(chatStateNotifier_, stanzaChannel, contact); diff --git a/Swift/Controllers/Chat/ChatController.h b/Swift/Controllers/Chat/ChatController.h index 3821a6e..7d2072d 100644 --- a/Swift/Controllers/Chat/ChatController.h +++ b/Swift/Controllers/Chat/ChatController.h @@ -17,7 +17,7 @@ namespace Swift { class NickResolver; class ChatController : public ChatControllerBase { public: - ChatController(const JID& self, StanzaChannel* stanzaChannel, IQRouter* iqRouter, ChatWindowFactory* chatWindowFactory, const JID &contact, NickResolver* nickResolver, PresenceOracle* presenceOracle, AvatarManager* avatarManager, bool isInMUC, bool useDelayForLatency); + ChatController(const JID& self, StanzaChannel* stanzaChannel, IQRouter* iqRouter, ChatWindowFactory* chatWindowFactory, const JID &contact, NickResolver* nickResolver, PresenceOracle* presenceOracle, AvatarManager* avatarManager, bool isInMUC, bool useDelayForLatency, UIEventStream* eventStream); virtual void setToJID(const JID& jid); private: diff --git a/Swift/Controllers/Chat/ChatControllerBase.cpp b/Swift/Controllers/Chat/ChatControllerBase.cpp index f3e6bbe..5f27efb 100644 --- a/Swift/Controllers/Chat/ChatControllerBase.cpp +++ b/Swift/Controllers/Chat/ChatControllerBase.cpp @@ -22,8 +22,8 @@ namespace Swift { -ChatControllerBase::ChatControllerBase(const JID& self, StanzaChannel* stanzaChannel, IQRouter* iqRouter, ChatWindowFactory* chatWindowFactory, const JID &toJID, PresenceOracle* presenceOracle, AvatarManager* avatarManager, bool useDelayForLatency) : selfJID_(self), stanzaChannel_(stanzaChannel), iqRouter_(iqRouter), chatWindowFactory_(chatWindowFactory), toJID_(toJID), labelsEnabled_(false), presenceOracle_(presenceOracle), avatarManager_(avatarManager), useDelayForLatency_(useDelayForLatency) { - chatWindow_ = chatWindowFactory_->createChatWindow(toJID); +ChatControllerBase::ChatControllerBase(const JID& self, StanzaChannel* stanzaChannel, IQRouter* iqRouter, ChatWindowFactory* chatWindowFactory, const JID &toJID, PresenceOracle* presenceOracle, AvatarManager* avatarManager, bool useDelayForLatency, UIEventStream* eventStream) : selfJID_(self), stanzaChannel_(stanzaChannel), iqRouter_(iqRouter), chatWindowFactory_(chatWindowFactory), toJID_(toJID), labelsEnabled_(false), presenceOracle_(presenceOracle), avatarManager_(avatarManager), useDelayForLatency_(useDelayForLatency) { + chatWindow_ = chatWindowFactory_->createChatWindow(toJID, eventStream); chatWindow_->onAllMessagesRead.connect(boost::bind(&ChatControllerBase::handleAllMessagesRead, this)); chatWindow_->onSendMessageRequest.connect(boost::bind(&ChatControllerBase::handleSendMessageRequest, this, _1)); setEnabled(stanzaChannel->isAvailable() && iqRouter->isAvailable()); diff --git a/Swift/Controllers/Chat/ChatControllerBase.h b/Swift/Controllers/Chat/ChatControllerBase.h index 8317da8..f7cf087 100644 --- a/Swift/Controllers/Chat/ChatControllerBase.h +++ b/Swift/Controllers/Chat/ChatControllerBase.h @@ -28,6 +28,7 @@ namespace Swift { class ChatWindow; class ChatWindowFactory; class AvatarManager; + class UIEventStream; class ChatControllerBase { public: @@ -40,7 +41,7 @@ namespace Swift { void setEnabled(bool enabled); virtual void setToJID(const JID& jid) {toJID_ = jid;}; protected: - ChatControllerBase(const JID& self, StanzaChannel* stanzaChannel, IQRouter* iqRouter, ChatWindowFactory* chatWindowFactory, const JID &toJID, PresenceOracle* presenceOracle, AvatarManager* avatarManager, bool useDelayForLatency); + ChatControllerBase(const JID& self, StanzaChannel* stanzaChannel, IQRouter* iqRouter, ChatWindowFactory* chatWindowFactory, const JID &toJID, PresenceOracle* presenceOracle, AvatarManager* avatarManager, bool useDelayForLatency, UIEventStream* eventStream); virtual void postSendMessage(const String&) {}; virtual String senderDisplayNameFromMessage(const JID& from) = 0; diff --git a/Swift/Controllers/Chat/ChatsManager.cpp b/Swift/Controllers/Chat/ChatsManager.cpp index d0b4716..312af76 100644 --- a/Swift/Controllers/Chat/ChatsManager.cpp +++ b/Swift/Controllers/Chat/ChatsManager.cpp @@ -28,12 +28,11 @@ namespace Swift { typedef std::pair JIDChatControllerPair; typedef std::pair JIDMUCControllerPair; -ChatsManager::ChatsManager(JID jid, StanzaChannel* stanzaChannel, IQRouter* iqRouter, EventController* eventController, ChatWindowFactory* chatWindowFactory, TreeWidgetFactory* treeWidgetFactory, NickResolver* nickResolver, PresenceOracle* presenceOracle, boost::shared_ptr serverDiscoInfo, PresenceSender* presenceSender, UIEventStream* uiEventStream, ChatListWindowFactory* chatListWindowFactory, bool useDelayForLatency) : jid_(jid), useDelayForLatency_(useDelayForLatency) { +ChatsManager::ChatsManager(JID jid, StanzaChannel* stanzaChannel, IQRouter* iqRouter, EventController* eventController, ChatWindowFactory* chatWindowFactory, NickResolver* nickResolver, PresenceOracle* presenceOracle, boost::shared_ptr serverDiscoInfo, PresenceSender* presenceSender, UIEventStream* uiEventStream, ChatListWindowFactory* chatListWindowFactory, bool useDelayForLatency) : jid_(jid), useDelayForLatency_(useDelayForLatency) { eventController_ = eventController; stanzaChannel_ = stanzaChannel; iqRouter_ = iqRouter; chatWindowFactory_ = chatWindowFactory; - treeWidgetFactory_ = treeWidgetFactory; nickResolver_ = nickResolver; presenceOracle_ = presenceOracle; avatarManager_ = NULL; @@ -185,7 +184,7 @@ ChatController* ChatsManager::getChatControllerOrFindAnother(const JID &contact) } ChatController* ChatsManager::createNewChatController(const JID& contact) { - ChatController* controller = new ChatController(jid_, stanzaChannel_, iqRouter_, chatWindowFactory_, contact, nickResolver_, presenceOracle_, avatarManager_, isMUC(contact.toBare()), useDelayForLatency_); + ChatController* controller = new ChatController(jid_, stanzaChannel_, iqRouter_, chatWindowFactory_, contact, nickResolver_, presenceOracle_, avatarManager_, isMUC(contact.toBare()), useDelayForLatency_, uiEventStream_); chatControllers_[contact] = controller; controller->setAvailableServerFeatures(serverDiscoInfo_); return controller; @@ -221,7 +220,7 @@ void ChatsManager::handleJoinMUCRequest(const JID &muc, const boost::optionalsetAvailableServerFeatures(serverDiscoInfo_); controller->onUserLeft.connect(boost::bind(&ChatsManager::handleUserLeftMUC, this, controller)); diff --git a/Swift/Controllers/Chat/ChatsManager.h b/Swift/Controllers/Chat/ChatsManager.h index d45d81d..59d4ec3 100644 --- a/Swift/Controllers/Chat/ChatsManager.h +++ b/Swift/Controllers/Chat/ChatsManager.h @@ -24,7 +24,6 @@ namespace Swift { class ChatController; class MUCController; class ChatWindowFactory; - class TreeWidgetFactory; class NickResolver; class PresenceOracle; class AvatarManager; @@ -37,14 +36,14 @@ namespace Swift { class ChatsManager : public MUCRegistry { public: - ChatsManager(JID jid, StanzaChannel* stanzaChannel, IQRouter* iqRouter, EventController* eventController, ChatWindowFactory* chatWindowFactory, TreeWidgetFactory* treeWidgetFactory, NickResolver* nickResolver, PresenceOracle* presenceOracle, boost::shared_ptr serverDiscoInfo, PresenceSender* presenceSender, UIEventStream* uiEventStream, ChatListWindowFactory* chatListWindowFactory, bool useDelayForLatency); + ChatsManager(JID jid, StanzaChannel* stanzaChannel, IQRouter* iqRouter, EventController* eventController, ChatWindowFactory* chatWindowFactory, NickResolver* nickResolver, PresenceOracle* presenceOracle, boost::shared_ptr serverDiscoInfo, PresenceSender* presenceSender, UIEventStream* uiEventStream, ChatListWindowFactory* chatListWindowFactory, bool useDelayForLatency); ~ChatsManager(); void setAvatarManager(AvatarManager* avatarManager); void setEnabled(bool enabled); void setServerDiscoInfo(boost::shared_ptr info); void handleIncomingMessage(boost::shared_ptr message); - void handleChatRequest(const String& contact); private: + void handleChatRequest(const String& contact); void handleJoinMUCRequest(const JID& muc, const boost::optional& nick); void rebindControllerJID(const JID& from, const JID& to); void handlePresenceChange(boost::shared_ptr newPresence, boost::shared_ptr lastPresence); @@ -65,7 +64,6 @@ namespace Swift { StanzaChannel* stanzaChannel_; IQRouter* iqRouter_;; ChatWindowFactory* chatWindowFactory_; - TreeWidgetFactory* treeWidgetFactory_; NickResolver* nickResolver_; PresenceOracle* presenceOracle_; AvatarManager* avatarManager_; diff --git a/Swift/Controllers/Chat/MUCController.cpp b/Swift/Controllers/Chat/MUCController.cpp index 737ad82..7e9a9ea 100644 --- a/Swift/Controllers/Chat/MUCController.cpp +++ b/Swift/Controllers/Chat/MUCController.cpp @@ -17,10 +17,8 @@ #include "Swiften/MUC/MUC.h" #include "Swiften/Client/StanzaChannel.h" #include "Swiften/Roster/Roster.h" -#include "Swiften/Roster/OpenChatRosterAction.h" #include "Swiften/Roster/SetAvatar.h" #include "Swiften/Roster/SetPresence.h" -#include "Swiften/Roster/TreeWidgetFactory.h" namespace Swift { @@ -35,19 +33,17 @@ MUCController::MUCController ( PresenceSender* presenceSender, IQRouter* iqRouter, ChatWindowFactory* chatWindowFactory, - TreeWidgetFactory *treeWidgetFactory, PresenceOracle* presenceOracle, AvatarManager* avatarManager, UIEventStream* uiEventStream, bool useDelayForLatency) : - ChatControllerBase(self, stanzaChannel, iqRouter, chatWindowFactory, muc, presenceOracle, avatarManager, useDelayForLatency), + ChatControllerBase(self, stanzaChannel, iqRouter, chatWindowFactory, muc, presenceOracle, avatarManager, useDelayForLatency, uiEventStream), muc_(new MUC(stanzaChannel, presenceSender, muc)), - nick_(nick), - treeWidgetFactory_(treeWidgetFactory) { + nick_(nick) { parting_ = false; events_ = uiEventStream; - roster_ = new Roster(chatWindow_->getTreeWidget(), treeWidgetFactory_); - roster_->onUserAction.connect(boost::bind(&MUCController::handleUserAction, this, _1)); + roster_ = new Roster(); + chatWindow_->setRosterModel(roster_); chatWindow_->onClosed.connect(boost::bind(&MUCController::handleWindowClosed, this)); muc_->joinAs(nick); muc_->onOccupantJoined.connect(boost::bind(&MUCController::handleOccupantJoined, this, _1)); @@ -61,19 +57,10 @@ MUCController::MUCController ( MUCController::~MUCController() { delete muc_; + chatWindow_->setRosterModel(NULL); delete roster_; } -void MUCController::handleUserAction(boost::shared_ptr action) { - boost::shared_ptr chatAction = boost::dynamic_pointer_cast(action); - if (chatAction.get() != NULL) { - ContactRosterItem *contactItem = dynamic_cast(chatAction->getRosterItem()); - assert(contactItem); - events_->send(boost::shared_ptr(new RequestChatUIEvent(contactItem->getJID()))); - return; - } -} - void MUCController::handleAvatarChanged(const JID& jid, const String&) { if (parting_) { return; diff --git a/Swift/Controllers/Chat/MUCController.h b/Swift/Controllers/Chat/MUCController.h index 2252357..8e6e01b 100644 --- a/Swift/Controllers/Chat/MUCController.h +++ b/Swift/Controllers/Chat/MUCController.h @@ -15,7 +15,6 @@ #include "Swift/Controllers/Chat/ChatControllerBase.h" #include "Swiften/Elements/Message.h" #include "Swiften/Elements/DiscoInfo.h" -#include "Swiften/Roster/UserRosterAction.h" #include "Swiften/JID/JID.h" #include "Swiften/MUC/MUC.h" #include "Swiften/MUC/MUCOccupant.h" @@ -26,13 +25,12 @@ namespace Swift { class ChatWindow; class ChatWindowFactory; class Roster; - class TreeWidgetFactory; class AvatarManager; class UIEventStream; class MUCController : public ChatControllerBase { public: - MUCController(const JID& self, const JID &muc, const String &nick, StanzaChannel* stanzaChannel, PresenceSender* presenceSender, IQRouter* iqRouter, ChatWindowFactory* chatWindowFactory, TreeWidgetFactory *treeWidgetFactory, PresenceOracle* presenceOracle, AvatarManager* avatarManager, UIEventStream* events, bool useDelayForLatency); + MUCController(const JID& self, const JID &muc, const String &nick, StanzaChannel* stanzaChannel, PresenceSender* presenceSender, IQRouter* iqRouter, ChatWindowFactory* chatWindowFactory, PresenceOracle* presenceOracle, AvatarManager* avatarManager, UIEventStream* events, bool useDelayForLatency); ~MUCController(); boost::signal onUserLeft; @@ -47,13 +45,11 @@ namespace Swift { void handleOccupantJoined(const MUCOccupant& occupant); void handleOccupantLeft(const MUCOccupant& occupant, MUC::LeavingType type, const String& reason); void handleOccupantPresenceChange(boost::shared_ptr presence); - void handleUserAction(boost::shared_ptr action); private: MUC* muc_; UIEventStream* events_; String nick_; - TreeWidgetFactory* treeWidgetFactory_; Roster* roster_; bool parting_; boost::bsignals::scoped_connection avatarChangedConnection_; diff --git a/Swift/Controllers/Chat/UnitTest/ChatsManagerTest.cpp b/Swift/Controllers/Chat/UnitTest/ChatsManagerTest.cpp index 5caedab..f671fb1 100644 --- a/Swift/Controllers/Chat/UnitTest/ChatsManagerTest.cpp +++ b/Swift/Controllers/Chat/UnitTest/ChatsManagerTest.cpp @@ -13,7 +13,6 @@ #include "Swift/Controllers/UIInterfaces/ChatWindow.h" #include "Swift/Controllers/UIInterfaces/ChatWindowFactory.h" #include "Swift/Controllers/UIInterfaces/ChatListWindowFactory.h" -#include "Swiften/Roster/TreeWidgetFactory.h" #include "Swiften/Client/Client.h" #include "Swift/Controllers/Chat/ChatController.h" #include "Swift/Controllers/EventController.h" @@ -26,6 +25,7 @@ #include "Swiften/Client/DummyStanzaChannel.h" #include "Swiften/Queries/DummyIQChannel.h" #include "Swiften/Presence/PresenceOracle.h" +#include "Swift/Controllers/UIEvents/RequestChatUIEvent.h" #include "Swift/Controllers/UIEvents/UIEventStream.h" @@ -54,7 +54,6 @@ public: iqRouter_ = new IQRouter(iqChannel_); eventController_ = new EventController(); chatWindowFactory_ = mocks_->InterfaceMock(); - treeWidgetFactory_ = NULL; xmppRoster_ = boost::shared_ptr(new XMPPRoster()); nickResolver_ = new NickResolver(xmppRoster_); presenceOracle_ = new PresenceOracle(stanzaChannel_); @@ -63,7 +62,7 @@ public: uiEventStream_ = new UIEventStream(); chatListWindowFactory_ = mocks_->InterfaceMock(); mocks_->ExpectCall(chatListWindowFactory_, ChatListWindowFactory::createWindow).With(uiEventStream_).Return(NULL); - manager_ = new ChatsManager(jid_, stanzaChannel_, iqRouter_, eventController_, chatWindowFactory_, treeWidgetFactory_, nickResolver_, presenceOracle_, serverDiscoInfo_, presenceSender_, uiEventStream_, chatListWindowFactory_, true); + manager_ = new ChatsManager(jid_, stanzaChannel_, iqRouter_, eventController_, chatWindowFactory_, nickResolver_, presenceOracle_, serverDiscoInfo_, presenceSender_, uiEventStream_, chatListWindowFactory_, true); avatarManager_ = new MockAvatarManager(); manager_->setAvatarManager(avatarManager_); }; @@ -74,7 +73,6 @@ public: delete presenceSender_; delete presenceOracle_; delete nickResolver_; - delete treeWidgetFactory_; delete stanzaChannel_; delete eventController_; delete iqChannel_; @@ -87,7 +85,7 @@ public: JID messageJID("testling@test.com/resource1"); MockChatWindow* window = new MockChatWindow();//mocks_->InterfaceMock(); - mocks_->ExpectCall(chatWindowFactory_, ChatWindowFactory::createChatWindow).With(messageJID).Return(window); + mocks_->ExpectCall(chatWindowFactory_, ChatWindowFactory::createChatWindow).With(messageJID, uiEventStream_).Return(window); boost::shared_ptr message(new Message()); message->setFrom(messageJID); @@ -101,7 +99,7 @@ public: JID messageJID1("testling@test.com/resource1"); MockChatWindow* window1 = new MockChatWindow();//mocks_->InterfaceMock(); - mocks_->ExpectCall(chatWindowFactory_, ChatWindowFactory::createChatWindow).With(messageJID1).Return(window1); + mocks_->ExpectCall(chatWindowFactory_, ChatWindowFactory::createChatWindow).With(messageJID1, uiEventStream_).Return(window1); boost::shared_ptr message1(new Message()); message1->setFrom(messageJID1); @@ -113,7 +111,7 @@ public: JID messageJID2("testling@test.com/resource2"); MockChatWindow* window2 = new MockChatWindow();//mocks_->InterfaceMock(); - mocks_->ExpectCall(chatWindowFactory_, ChatWindowFactory::createChatWindow).With(messageJID2).Return(window2); + mocks_->ExpectCall(chatWindowFactory_, ChatWindowFactory::createChatWindow).With(messageJID2, uiEventStream_).Return(window2); boost::shared_ptr message2(new Message()); message2->setFrom(messageJID2); @@ -127,9 +125,9 @@ public: String messageJIDString("testling@test.com"); ChatWindow* window = new MockChatWindow();//mocks_->InterfaceMock(); - mocks_->ExpectCall(chatWindowFactory_, ChatWindowFactory::createChatWindow).With(JID(messageJIDString)).Return(window); - - manager_->handleChatRequest(messageJIDString); + mocks_->ExpectCall(chatWindowFactory_, ChatWindowFactory::createChatWindow).With(JID(messageJIDString), uiEventStream_).Return(window); + + uiEventStream_->send(boost::shared_ptr(new RequestChatUIEvent(JID(messageJIDString)))); } @@ -138,8 +136,8 @@ public: String fullJIDString("testling@test.com/resource1"); MockChatWindow* window = new MockChatWindow();//mocks_->InterfaceMock(); - mocks_->ExpectCall(chatWindowFactory_, ChatWindowFactory::createChatWindow).With(JID(bareJIDString)).Return(window); - manager_->handleChatRequest(bareJIDString); + mocks_->ExpectCall(chatWindowFactory_, ChatWindowFactory::createChatWindow).With(JID(bareJIDString), uiEventStream_).Return(window); + uiEventStream_->send(boost::shared_ptr(new RequestChatUIEvent(JID(bareJIDString)))); boost::shared_ptr message(new Message()); message->setFrom(JID(fullJIDString)); @@ -152,14 +150,14 @@ public: void testSecondWindow() { String messageJIDString1("testling1@test.com"); ChatWindow* window1 = new MockChatWindow();//mocks_->InterfaceMock(); - mocks_->ExpectCall(chatWindowFactory_, ChatWindowFactory::createChatWindow).With(JID(messageJIDString1)).Return(window1); - manager_->handleChatRequest(messageJIDString1); + mocks_->ExpectCall(chatWindowFactory_, ChatWindowFactory::createChatWindow).With(JID(messageJIDString1), uiEventStream_).Return(window1); + uiEventStream_->send(boost::shared_ptr(new RequestChatUIEvent(JID(messageJIDString1)))); String messageJIDString2("testling2@test.com"); ChatWindow* window2 = new MockChatWindow();//mocks_->InterfaceMock(); - mocks_->ExpectCall(chatWindowFactory_, ChatWindowFactory::createChatWindow).With(JID(messageJIDString2)).Return(window2); + mocks_->ExpectCall(chatWindowFactory_, ChatWindowFactory::createChatWindow).With(JID(messageJIDString2), uiEventStream_).Return(window2); - manager_->handleChatRequest(messageJIDString2); + uiEventStream_->send(boost::shared_ptr(new RequestChatUIEvent(JID(messageJIDString2)))); } /** Complete cycle. @@ -174,8 +172,8 @@ public: String fullJIDString2("testling@test.com/resource2"); MockChatWindow* window = new MockChatWindow();//mocks_->InterfaceMock(); - mocks_->ExpectCall(chatWindowFactory_, ChatWindowFactory::createChatWindow).With(JID(bareJIDString)).Return(window); - manager_->handleChatRequest(bareJIDString); + mocks_->ExpectCall(chatWindowFactory_, ChatWindowFactory::createChatWindow).With(JID(bareJIDString), uiEventStream_).Return(window); + uiEventStream_->send(boost::shared_ptr(new RequestChatUIEvent(JID(bareJIDString)))); boost::shared_ptr message1(new Message()); message1->setFrom(JID(fullJIDString1)); @@ -212,7 +210,7 @@ public: JID messageJID1("testling@test.com/resource1"); MockChatWindow* window1 = new MockChatWindow();//mocks_->InterfaceMock(); - mocks_->ExpectCall(chatWindowFactory_, ChatWindowFactory::createChatWindow).With(messageJID1).Return(window1); + mocks_->ExpectCall(chatWindowFactory_, ChatWindowFactory::createChatWindow).With(messageJID1, uiEventStream_).Return(window1); boost::shared_ptr message1(new Message()); message1->setFrom(messageJID1); @@ -222,7 +220,7 @@ public: JID messageJID2("testling@test.com/resource2"); MockChatWindow* window2 = new MockChatWindow();//mocks_->InterfaceMock(); - mocks_->ExpectCall(chatWindowFactory_, ChatWindowFactory::createChatWindow).With(messageJID2).Return(window2); + mocks_->ExpectCall(chatWindowFactory_, ChatWindowFactory::createChatWindow).With(messageJID2, uiEventStream_).Return(window2); boost::shared_ptr message2(new Message()); message2->setFrom(messageJID2); @@ -268,7 +266,6 @@ private: IQRouter* iqRouter_; EventController* eventController_; ChatWindowFactory* chatWindowFactory_; - TreeWidgetFactory* treeWidgetFactory_; NickResolver* nickResolver_; PresenceOracle* presenceOracle_; AvatarManager* avatarManager_; diff --git a/Swift/Controllers/MainController.cpp b/Swift/Controllers/MainController.cpp index 3656de3..e6dfe47 100644 --- a/Swift/Controllers/MainController.cpp +++ b/Swift/Controllers/MainController.cpp @@ -42,7 +42,6 @@ #include "Swiften/Elements/Presence.h" #include "Swiften/Elements/VCardUpdate.h" #include "Swiften/Queries/Responders/SoftwareVersionResponder.h" -#include "Swiften/Roster/TreeWidgetFactory.h" #include "Swiften/Settings/SettingsProvider.h" #include "Swiften/Elements/DiscoInfo.h" #include "Swiften/Queries/Responders/DiscoInfoResponder.h" @@ -61,8 +60,8 @@ static const String CLIENT_VERSION = "0.3"; static const String CLIENT_NODE = "http://swift.im"; -MainController::MainController(ChatWindowFactory* chatWindowFactory, MainWindowFactory *mainWindowFactory, LoginWindowFactory *loginWindowFactory, TreeWidgetFactory *treeWidgetFactory, EventWindowFactory* eventWindowFactory, SettingsProvider *settings, Application* application, SystemTray* systemTray, SoundPlayer* soundPlayer, XMLConsoleWidgetFactory* xmlConsoleWidgetFactory, ChatListWindowFactory* chatListWindowFactory, bool useDelayForLatency) - : timerFactory_(&boostIOServiceThread_.getIOService()), idleDetector_(&idleQuerier_, &timerFactory_, 100), chatWindowFactory_(chatWindowFactory), mainWindowFactory_(mainWindowFactory), loginWindowFactory_(loginWindowFactory), treeWidgetFactory_(treeWidgetFactory), settings_(settings), loginWindow_(NULL), useDelayForLatency_(useDelayForLatency) { +MainController::MainController(ChatWindowFactory* chatWindowFactory, MainWindowFactory *mainWindowFactory, LoginWindowFactory *loginWindowFactory, EventWindowFactory* eventWindowFactory, SettingsProvider *settings, Application* application, SystemTray* systemTray, SoundPlayer* soundPlayer, XMLConsoleWidgetFactory* xmlConsoleWidgetFactory, ChatListWindowFactory* chatListWindowFactory, 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; avatarManager_ = NULL; @@ -176,15 +175,14 @@ void MainController::handleConnected() { avatarManager_ = new AvatarManager(client_, client_, avatarStorage_); - rosterController_ = new RosterController(jid_, xmppRoster_, avatarManager_, mainWindowFactory_, treeWidgetFactory_, nickResolver_, presenceOracle_, eventController_, uiEventStream_, client_); + rosterController_ = new RosterController(jid_, xmppRoster_, avatarManager_, mainWindowFactory_, nickResolver_, presenceOracle_, eventController_, uiEventStream_, client_); rosterController_->onChangeStatusRequest.connect(boost::bind(&MainController::handleChangeStatusRequest, this, _1, _2)); rosterController_->onSignOutRequest.connect(boost::bind(&MainController::signOut, this)); - chatsManager_ = new ChatsManager(jid_, client_, client_, eventController_, chatWindowFactory_, treeWidgetFactory_, nickResolver_, presenceOracle_, serverDiscoInfo_, presenceSender_, uiEventStream_, chatListWindowFactory_, useDelayForLatency_); + chatsManager_ = new ChatsManager(jid_, client_, client_, eventController_, chatWindowFactory_, nickResolver_, presenceOracle_, serverDiscoInfo_, presenceSender_, uiEventStream_, chatListWindowFactory_, useDelayForLatency_); nickResolver_->setMUCRegistry(chatsManager_); client_->onMessageReceived.connect(boost::bind(&ChatsManager::handleIncomingMessage, chatsManager_, _1)); chatsManager_->setAvatarManager(avatarManager_); - rosterController_->onStartChatRequest.connect(boost::bind(&ChatsManager::handleChatRequest, chatsManager_, _1)); avatarManager_->setMUCRegistry(chatsManager_); diff --git a/Swift/Controllers/MainController.h b/Swift/Controllers/MainController.h index 2ed922c..5d3f998 100644 --- a/Swift/Controllers/MainController.h +++ b/Swift/Controllers/MainController.h @@ -47,7 +47,6 @@ namespace Swift { class EventLoop; class SoftwareVersionResponder; class LoginWindowFactory; - class TreeWidgetFactory; class MUCController; class PresenceOracle; class SystemTray; @@ -62,7 +61,7 @@ namespace Swift { class MainController { public: - MainController(ChatWindowFactory* chatWindowFactory, MainWindowFactory *mainWindowFactory, LoginWindowFactory *loginWindowFactory, TreeWidgetFactory* treeWidgetFactory, 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_, bool useDelayForLatency); ~MainController(); @@ -94,7 +93,6 @@ namespace Swift { ChatWindowFactory* chatWindowFactory_; MainWindowFactory* mainWindowFactory_; LoginWindowFactory* loginWindowFactory_; - TreeWidgetFactory* treeWidgetFactory_; EventWindowFactory* eventWindowFactory_; SettingsProvider *settings_; Application* application_; diff --git a/Swift/Controllers/RosterController.cpp b/Swift/Controllers/RosterController.cpp index 3bbc9f8..4738d76 100644 --- a/Swift/Controllers/RosterController.cpp +++ b/Swift/Controllers/RosterController.cpp @@ -25,11 +25,9 @@ #include "Swiften/Roster/SetAvatar.h" #include "Swiften/Roster/SetName.h" #include "Swiften/Roster/OfflineRosterFilter.h" -#include "Swiften/Roster/OpenChatRosterAction.h" -#include "Swiften/Roster/TreeWidgetFactory.h" #include "Swiften/Roster/XMPPRoster.h" #include "Swift/Controllers/UIEvents/AddContactUIEvent.h" -#include "Swift/Controllers/UIEvents/RemoveItemRosterAction.h" +#include "Swift/Controllers/UIEvents/RemoveRosterItemUIEvent.h" namespace Swift { @@ -37,17 +35,17 @@ namespace Swift { /** * The controller does not gain ownership of these parameters. */ -RosterController::RosterController(const JID& jid, boost::shared_ptr xmppRoster, AvatarManager* avatarManager, MainWindowFactory* mainWindowFactory, TreeWidgetFactory* treeWidgetFactory, NickResolver* nickResolver, PresenceOracle* presenceOracle, EventController* eventController, UIEventStream* uiEventStream, IQRouter* iqRouter) - : myJID_(jid), xmppRoster_(xmppRoster), mainWindowFactory_(mainWindowFactory), treeWidgetFactory_(treeWidgetFactory), mainWindow_(mainWindowFactory_->createMainWindow(uiEventStream)), roster_(new Roster(mainWindow_->getTreeWidget(), treeWidgetFactory_)), offlineFilter_(new OfflineRosterFilter()) { +RosterController::RosterController(const JID& jid, boost::shared_ptr xmppRoster, AvatarManager* avatarManager, MainWindowFactory* mainWindowFactory, NickResolver* nickResolver, PresenceOracle* presenceOracle, EventController* eventController, UIEventStream* uiEventStream, IQRouter* iqRouter) + : myJID_(jid), xmppRoster_(xmppRoster), mainWindowFactory_(mainWindowFactory), mainWindow_(mainWindowFactory_->createMainWindow(uiEventStream)), roster_(new Roster()), offlineFilter_(new OfflineRosterFilter()) { iqRouter_ = iqRouter; presenceOracle_ = presenceOracle; eventController_ = eventController; roster_->addFilter(offlineFilter_); + mainWindow_->setRosterModel(roster_); changeStatusConnection_ = mainWindow_->onChangeStatusRequest.connect(boost::bind(&RosterController::handleChangeStatusRequest, this, _1, _2)); showOfflineConnection_ = mainWindow_->onShowOfflineToggled.connect(boost::bind(&RosterController::handleShowOfflineToggled, this, _1)); signOutConnection_ = mainWindow_->onSignOutRequest.connect(boost::bind(boost::ref(onSignOutRequest))); - roster_->onUserAction.connect(boost::bind(&RosterController::handleUserAction, this, _1)); xmppRoster_->onJIDAdded.connect(boost::bind(&RosterController::handleOnJIDAdded, this, _1)); xmppRoster_->onJIDUpdated.connect(boost::bind(&RosterController::handleOnJIDUpdated, this, _1, _2, _3)); xmppRoster_->onJIDRemoved.connect(boost::bind(&RosterController::handleOnJIDRemoved, this, _1)); @@ -101,31 +99,6 @@ void RosterController::handleChangeStatusRequest(StatusShow::Type show, const St onChangeStatusRequest(show, statusText); } -void RosterController::handleUserAction(boost::shared_ptr action) { - boost::shared_ptr chatAction = boost::dynamic_pointer_cast(action); - if (chatAction) { - ContactRosterItem *contactItem = dynamic_cast(chatAction->getRosterItem()); - assert(contactItem); - onStartChatRequest(contactItem->getJID().toBare()); - return; - } - - boost::shared_ptr removeAction = boost::dynamic_pointer_cast(action); - if (removeAction) { - ContactRosterItem *contactItem = dynamic_cast(removeAction->getRosterItem()); - assert(contactItem); - - RosterItemPayload item(contactItem->getJID(), "", RosterItemPayload::Remove); - boost::shared_ptr roster(new RosterPayload()); - roster->addItem(item); - boost::shared_ptr request(new SetRosterRequest(roster, iqRouter_)); - request->onResponse.connect(boost::bind(&RosterController::handleRosterSetError, this, _1, roster)); - request->send(); - - return; - } -} - void RosterController::handleOnJIDAdded(const JID& jid) { std::vector groups = xmppRoster_->getGroupsForJID(jid); String name = xmppRoster_->getNameForJID(jid); @@ -182,7 +155,20 @@ void RosterController::handleUIEvent(boost::shared_ptr event) { request->onResponse.connect(boost::bind(&RosterController::handleRosterSetError, this, _1, roster)); request->send(); presenceOracle_->requestSubscription(addContactEvent->getJID()); + return; } + boost::shared_ptr removeEvent = boost::dynamic_pointer_cast(event); + if (removeEvent) { + RosterItemPayload item(removeEvent->getJID(), "", RosterItemPayload::Remove); + boost::shared_ptr roster(new RosterPayload()); + roster->addItem(item); + boost::shared_ptr request(new SetRosterRequest(roster, iqRouter_)); + request->onResponse.connect(boost::bind(&RosterController::handleRosterSetError, this, _1, roster)); + request->send(); + + return; + } + } void RosterController::handleRosterSetError(boost::optional error, boost::shared_ptr rosterPayload) { diff --git a/Swift/Controllers/RosterController.h b/Swift/Controllers/RosterController.h index e9561bb..eca4e33 100644 --- a/Swift/Controllers/RosterController.h +++ b/Swift/Controllers/RosterController.h @@ -11,7 +11,6 @@ #include "Swiften/Base/String.h" #include "Swiften/Elements/Presence.h" #include "Swiften/Elements/RosterPayload.h" -#include "Swiften/Roster/UserRosterAction.h" #include "Swiften/Avatars/AvatarManager.h" #include "Swift/Controllers/UIEvents/UIEvent.h" @@ -24,7 +23,6 @@ namespace Swift { class XMPPRoster; class MainWindow; class MainWindowFactory; - class TreeWidgetFactory; class OfflineRosterFilter; class NickResolver; class PresenceOracle; @@ -35,13 +33,12 @@ namespace Swift { class RosterController { public: - RosterController(const JID& jid, boost::shared_ptr xmppRoster, AvatarManager* avatarManager, MainWindowFactory* mainWindowFactory, TreeWidgetFactory* treeWidgetFactory, NickResolver* nickResolver, PresenceOracle* presenceOracle, EventController* eventController, UIEventStream* uiEventStream, IQRouter* iqRouter_); + RosterController(const JID& jid, boost::shared_ptr xmppRoster, AvatarManager* avatarManager, MainWindowFactory* mainWindowFactory, NickResolver* nickResolver, PresenceOracle* presenceOracle, EventController* eventController, UIEventStream* uiEventStream, IQRouter* iqRouter_); ~RosterController(); void showRosterWindow(); MainWindow* getWindow() {return mainWindow_;}; void setAvatarManager(AvatarManager* avatarManager); void setNickResolver(NickResolver* nickResolver); - boost::signal onStartChatRequest; boost::signal onChangeStatusRequest; boost::signal onSignOutRequest; void handleAvatarChanged(const JID& jid, const String& hash); @@ -51,7 +48,6 @@ namespace Swift { void handleOnJIDRemoved(const JID &jid); void handleOnJIDUpdated(const JID &jid, const String& oldName, const std::vector oldGroups); void handleStartChatRequest(const JID& contact); - void handleUserAction(boost::shared_ptr action); void handleChangeStatusRequest(StatusShow::Type show, const String &statusText); void handleShowOfflineToggled(bool state); void handleIncomingPresence(boost::shared_ptr newPresence, boost::shared_ptr oldPresence); @@ -63,7 +59,6 @@ namespace Swift { JID myJID_; boost::shared_ptr xmppRoster_; MainWindowFactory* mainWindowFactory_; - TreeWidgetFactory* treeWidgetFactory_; MainWindow* mainWindow_; Roster* roster_; OfflineRosterFilter* offlineFilter_; diff --git a/Swift/Controllers/UIEvents/RemoveItemRosterAction.h b/Swift/Controllers/UIEvents/RemoveItemRosterAction.h deleted file mode 100644 index 751e248..0000000 --- a/Swift/Controllers/UIEvents/RemoveItemRosterAction.h +++ /dev/null @@ -1,21 +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 "Swiften/Roster/UserRosterAction.h" - -namespace Swift { -class RosterItem; -class TreeWidgetItem; - -class RemoveItemRosterAction : public UserRosterAction { - public: - virtual ~RemoveItemRosterAction() {}; - -}; - -} diff --git a/Swift/Controllers/UIEvents/RemoveRosterItemUIEvent.h b/Swift/Controllers/UIEvents/RemoveRosterItemUIEvent.h new file mode 100644 index 0000000..7e5236a --- /dev/null +++ b/Swift/Controllers/UIEvents/RemoveRosterItemUIEvent.h @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2010 Kevin Smith + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma once + +#include "Swiften/JID/JID.h" +#include "Swift/Controllers/UIEvents/UIEvent.h" + +namespace Swift { + +class RemoveRosterItemUIEvent : public UIEvent { + public: + RemoveRosterItemUIEvent(const JID& jid) : jid_(jid) {}; + virtual ~RemoveRosterItemUIEvent() {}; + JID getJID() {return jid_;}; + private: + JID jid_; + +}; + +} diff --git a/Swift/Controllers/UIInterfaces/ChatWindow.h b/Swift/Controllers/UIInterfaces/ChatWindow.h index 0463508..33133f3 100644 --- a/Swift/Controllers/UIInterfaces/ChatWindow.h +++ b/Swift/Controllers/UIInterfaces/ChatWindow.h @@ -19,6 +19,7 @@ namespace Swift { class AvatarManager; class TreeWidget; + class Roster; class ChatWindow { public: @@ -38,10 +39,11 @@ namespace Swift { virtual void setSecurityLabelsEnabled(bool enabled) = 0; virtual void setUnreadMessageCount(int count) = 0; virtual void convertToMUC() = 0; - virtual TreeWidget *getTreeWidget() = 0; +// virtual TreeWidget *getTreeWidget() = 0; virtual void setSecurityLabelsError() = 0; virtual SecurityLabel getSelectedSecurityLabel() = 0; virtual void setInputEnabled(bool enabled) = 0; + virtual void setRosterModel(Roster* model) = 0; boost::signal onClosed; boost::signal onAllMessagesRead; diff --git a/Swift/Controllers/UIInterfaces/ChatWindowFactory.h b/Swift/Controllers/UIInterfaces/ChatWindowFactory.h index 3ea2416..b7b4479 100644 --- a/Swift/Controllers/UIInterfaces/ChatWindowFactory.h +++ b/Swift/Controllers/UIInterfaces/ChatWindowFactory.h @@ -11,14 +11,14 @@ namespace Swift { class ChatWindow; - + class UIEventStream; class ChatWindowFactory { public: virtual ~ChatWindowFactory() {}; /** * Transfers ownership of result. */ - virtual ChatWindow* createChatWindow(const JID &contact) = 0; + virtual ChatWindow* createChatWindow(const JID &contact, UIEventStream* eventStream) = 0; }; } diff --git a/Swift/Controllers/UIInterfaces/MainWindow.h b/Swift/Controllers/UIInterfaces/MainWindow.h index ce8b877..6d6e980 100644 --- a/Swift/Controllers/UIInterfaces/MainWindow.h +++ b/Swift/Controllers/UIInterfaces/MainWindow.h @@ -15,16 +15,16 @@ #include namespace Swift { - class TreeWidget; + class Roster; class MainWindow { public: virtual ~MainWindow() {}; - virtual TreeWidget* getTreeWidget() = 0; virtual void setMyName(const String& name) = 0; virtual void setMyAvatarPath(const String& path) = 0; virtual void setMyStatusText(const String& status) = 0; virtual void setMyStatusType(StatusShow::Type type) = 0; + virtual void setRosterModel(Roster* roster) = 0; boost::signal onStartChatRequest; boost::signal onChangeStatusRequest; diff --git a/Swift/Controllers/UnitTest/MockChatWindow.h b/Swift/Controllers/UnitTest/MockChatWindow.h index fecd665..1ce87ff 100644 --- a/Swift/Controllers/UnitTest/MockChatWindow.h +++ b/Swift/Controllers/UnitTest/MockChatWindow.h @@ -27,10 +27,10 @@ namespace Swift { virtual void setSecurityLabelsEnabled(bool enabled) {labelsEnabled_ = enabled;}; virtual void setUnreadMessageCount(int /*count*/) {}; virtual void convertToMUC() {}; - virtual TreeWidget *getTreeWidget() {return NULL;}; virtual void setSecurityLabelsError() {}; virtual SecurityLabel getSelectedSecurityLabel() {return SecurityLabel();}; virtual void setInputEnabled(bool /*enabled*/) {}; + virtual void setRosterModel(Roster* /*roster*/) {}; boost::signal onClosed; boost::signal onAllMessagesRead; diff --git a/Swift/Controllers/UnitTest/MockMainWindow.h b/Swift/Controllers/UnitTest/MockMainWindow.h index f6134da..4d0c67a 100644 --- a/Swift/Controllers/UnitTest/MockMainWindow.h +++ b/Swift/Controllers/UnitTest/MockMainWindow.h @@ -7,20 +7,19 @@ #pragma once #include "Swift/Controllers/UIInterfaces/MainWindow.h" -#include "Swiften/Roster/TreeWidget.h" namespace Swift { + class Roster; class MockMainWindow : public MainWindow { public: - MockMainWindow(TreeWidget* treeWidget) {treeWidget_ = treeWidget;}; + MockMainWindow() {}; virtual ~MockMainWindow() {}; - virtual TreeWidget* getTreeWidget() {return treeWidget_;}; + virtual void setRosterModel(Roster* roster) {this->roster = roster;}; virtual void setMyName(const String& /*name*/) {};; virtual void setMyAvatarPath(const String& /*path*/) {}; virtual void setMyStatusText(const String& /*status*/) {}; virtual void setMyStatusType(StatusShow::Type /*type*/) {}; - - private: - TreeWidget* treeWidget_; + Roster* roster; + }; } diff --git a/Swift/Controllers/UnitTest/MockMainWindowFactory.h b/Swift/Controllers/UnitTest/MockMainWindowFactory.h index 2f0559b..8a35d1a 100644 --- a/Swift/Controllers/UnitTest/MockMainWindowFactory.h +++ b/Swift/Controllers/UnitTest/MockMainWindowFactory.h @@ -7,21 +7,19 @@ #pragma once #include "Swift/Controllers/UIInterfaces/MainWindowFactory.h" -#include "Swiften/Roster/TreeWidgetFactory.h" #include "Swift/Controllers/UnitTest/MockMainWindow.h" namespace Swift { class MockMainWindowFactory : public MainWindowFactory { public: - MockMainWindowFactory(TreeWidgetFactory* treeWidgetFactory) {factory_ = treeWidgetFactory;}; + MockMainWindowFactory() {}; virtual ~MockMainWindowFactory() {}; /** * Transfers ownership of result. */ - virtual MainWindow* createMainWindow(UIEventStream*) {return new MockMainWindow(factory_->createTreeWidget());}; - private: - TreeWidgetFactory* factory_; + virtual MainWindow* createMainWindow(UIEventStream*) {last = new MockMainWindow();return last;}; + MockMainWindow* last; }; } diff --git a/Swift/Controllers/UnitTest/RosterControllerTest.cpp b/Swift/Controllers/UnitTest/RosterControllerTest.cpp index 1177bd7..4bb3a08 100644 --- a/Swift/Controllers/UnitTest/RosterControllerTest.cpp +++ b/Swift/Controllers/UnitTest/RosterControllerTest.cpp @@ -10,7 +10,6 @@ #include "Swift/Controllers/RosterController.h" #include "Swift/Controllers/UnitTest/MockMainWindowFactory.h" -#include "Swiften/Roster/UnitTest/MockTreeWidgetFactory.h" // #include "Swiften/Elements/Payload.h" // #include "Swiften/Elements/RosterItemPayload.h" // #include "Swiften/Elements/RosterPayload.h" @@ -18,6 +17,9 @@ #include "Swiften/Client/DummyStanzaChannel.h" #include "Swiften/Queries/IQRouter.h" #include "Swiften/Roster/XMPPRoster.h" +#include "Swiften/Roster/Roster.h" +#include "Swiften/Roster/GroupRosterItem.h" +#include "Swiften/Roster/ContactRosterItem.h" #include "Swift/Controllers/EventController.h" #include "Swiften/Presence/PresenceOracle.h" #include "Swift/Controllers/NickResolver.h" @@ -25,6 +27,7 @@ using namespace Swift; +#define CHILDREN mainWindow_->roster->getRoot()->getChildren() class RosterControllerTest : public CppUnit::TestFixture { CPPUNIT_TEST_SUITE(RosterControllerTest); @@ -40,8 +43,7 @@ class RosterControllerTest : public CppUnit::TestFixture jid_ = JID("testjid@swift.im/swift"); xmppRoster_ = boost::shared_ptr(new XMPPRoster()); avatarManager_ = NULL;//new AvatarManager(); - treeWidgetFactory_ = new MockTreeWidgetFactory(); - mainWindowFactory_ = new MockMainWindowFactory(treeWidgetFactory_); + mainWindowFactory_ = new MockMainWindowFactory(); nickResolver_ = new NickResolver(xmppRoster_); channel_ = new DummyIQChannel(); router_ = new IQRouter(channel_); @@ -49,9 +51,8 @@ class RosterControllerTest : public CppUnit::TestFixture presenceOracle_ = new PresenceOracle(stanzaChannel_); eventController_ = new EventController(); uiEventStream_ = new UIEventStream(); - rosterController_ = new RosterController(jid_, xmppRoster_, avatarManager_, mainWindowFactory_, treeWidgetFactory_, nickResolver_, presenceOracle_, eventController_, uiEventStream_, router_); - - + rosterController_ = new RosterController(jid_, xmppRoster_, avatarManager_, mainWindowFactory_, nickResolver_, presenceOracle_, eventController_, uiEventStream_, router_); + mainWindow_ = mainWindowFactory_->last; }; void tearDown() { @@ -65,16 +66,19 @@ class RosterControllerTest : public CppUnit::TestFixture delete presenceOracle_; delete stanzaChannel_; delete uiEventStream_; - delete treeWidgetFactory_; }; + GroupRosterItem* groupChild(size_t i) { + return dynamic_cast(CHILDREN[i]); + } + void testAdd() { std::vector groups; groups.push_back("testGroup1"); groups.push_back("testGroup2"); xmppRoster_->addContact(JID("test@testdomain.com/bob"), "name", groups, RosterItemPayload::Both); - CPPUNIT_ASSERT_EQUAL(2, (int)treeWidgetFactory_->getGroups().size()); + CPPUNIT_ASSERT_EQUAL(2, (int)CHILDREN.size()); //CPPUNIT_ASSERT_EQUAL(String("Bob"), xmppRoster_->getNameForJID(JID("foo@bar.com"))); }; @@ -83,15 +87,15 @@ class RosterControllerTest : public CppUnit::TestFixture JID jid("test@testdomain.com"); xmppRoster_->addContact(jid, "name", groups, RosterItemPayload::None); - CPPUNIT_ASSERT_EQUAL(1, (int)treeWidgetFactory_->getGroups().size()); - CPPUNIT_ASSERT_EQUAL(1, (int)treeWidgetFactory_->getGroupMembers("Contacts").size()); + CPPUNIT_ASSERT_EQUAL(1, (int)CHILDREN.size()); + CPPUNIT_ASSERT_EQUAL(1, (int)groupChild(0)->getChildren().size()); xmppRoster_->addContact(jid, "name", groups, RosterItemPayload::To); - CPPUNIT_ASSERT_EQUAL(1, (int)treeWidgetFactory_->getGroups().size()); - CPPUNIT_ASSERT_EQUAL(1, (int)treeWidgetFactory_->getGroupMembers("Contacts").size()); + CPPUNIT_ASSERT_EQUAL(1, (int)CHILDREN.size()); + CPPUNIT_ASSERT_EQUAL(1, (int)groupChild(0)->getChildren().size()); xmppRoster_->addContact(jid, "name", groups, RosterItemPayload::Both); - CPPUNIT_ASSERT_EQUAL(1, (int)treeWidgetFactory_->getGroups().size()); - CPPUNIT_ASSERT_EQUAL(1, (int)treeWidgetFactory_->getGroupMembers("Contacts").size()); + CPPUNIT_ASSERT_EQUAL(1, (int)CHILDREN.size()); + CPPUNIT_ASSERT_EQUAL(1, (int)groupChild(0)->getChildren().size()); }; @@ -100,20 +104,20 @@ class RosterControllerTest : public CppUnit::TestFixture JID jid("test@testdomain.com"); xmppRoster_->addContact(jid, "name", groups, RosterItemPayload::Both); - CPPUNIT_ASSERT_EQUAL(1, (int)treeWidgetFactory_->getGroups().size()); - CPPUNIT_ASSERT_EQUAL(1, (int)treeWidgetFactory_->getGroupMembers("Contacts").size()); + CPPUNIT_ASSERT_EQUAL(1, (int)CHILDREN.size()); + CPPUNIT_ASSERT_EQUAL(1, (int)groupChild(0)->getChildren().size()); + CPPUNIT_ASSERT_EQUAL(String("name"), groupChild(0)->getChildren()[0]->getDisplayName()); xmppRoster_->addContact(jid, "NewName", groups, RosterItemPayload::Both); - CPPUNIT_ASSERT_EQUAL(1, (int)treeWidgetFactory_->getGroups().size()); - CPPUNIT_ASSERT_EQUAL(1, (int)treeWidgetFactory_->getGroupMembers("Contacts").size()); - CPPUNIT_ASSERT_EQUAL(String("NewName"), treeWidgetFactory_->getGroupMembers("Contacts")[0]->getText()); + CPPUNIT_ASSERT_EQUAL(1, (int)CHILDREN.size()); + CPPUNIT_ASSERT_EQUAL(1, (int)groupChild(0)->getChildren().size()); + CPPUNIT_ASSERT_EQUAL(String("NewName"), groupChild(0)->getChildren()[0]->getDisplayName()); }; private: JID jid_; boost::shared_ptr xmppRoster_; AvatarManager* avatarManager_; - MainWindowFactory* mainWindowFactory_; - MockTreeWidgetFactory* treeWidgetFactory_; + MockMainWindowFactory* mainWindowFactory_; NickResolver* nickResolver_; RosterController* rosterController_; DummyIQChannel* channel_; @@ -122,6 +126,8 @@ class RosterControllerTest : public CppUnit::TestFixture PresenceOracle* presenceOracle_; EventController* eventController_; UIEventStream* uiEventStream_; + MockMainWindow* mainWindow_; }; +#undef children CPPUNIT_TEST_SUITE_REGISTRATION(RosterControllerTest); diff --git a/Swift/Controllers/XMPPRosterController.cpp b/Swift/Controllers/XMPPRosterController.cpp index a7e634a..de5ff8c 100644 --- a/Swift/Controllers/XMPPRosterController.cpp +++ b/Swift/Controllers/XMPPRosterController.cpp @@ -16,8 +16,6 @@ #include "Swiften/Roster/Roster.h" #include "Swiften/Roster/SetPresence.h" #include "Swiften/Roster/OfflineRosterFilter.h" -#include "Swiften/Roster/OpenChatRosterAction.h" -#include "Swiften/Roster/TreeWidgetFactory.h" #include "Swiften/Roster/XMPPRoster.h" namespace Swift { diff --git a/Swift/QtUI/ChatList/QtChatListWindow.cpp b/Swift/QtUI/ChatList/QtChatListWindow.cpp index 7d307f9..9b70881 100644 --- a/Swift/QtUI/ChatList/QtChatListWindow.cpp +++ b/Swift/QtUI/ChatList/QtChatListWindow.cpp @@ -29,6 +29,7 @@ QtChatListWindow::QtChatListWindow(UIEventStream *uiEventStream, QWidget* parent #ifdef SWIFT_PLATFORM_MACOSX setAlternatingRowColors(true); #endif + expandAll(); setAnimated(true); setIndentation(0); setRootIsDecorated(true); diff --git a/Swift/QtUI/ContextMenus/QtContextMenu.h b/Swift/QtUI/ContextMenus/QtContextMenu.h index baa0180..9e73ef9 100644 --- a/Swift/QtUI/ContextMenus/QtContextMenu.h +++ b/Swift/QtUI/ContextMenus/QtContextMenu.h @@ -7,11 +7,11 @@ #pragma once namespace Swift { - class QtTreeWidgetItem; + class RosterItem; class QtContextMenu { public: virtual ~QtContextMenu(); - virtual void show(QtTreeWidgetItem* item) = 0; + virtual void show(RosterItem* item) = 0; }; } diff --git a/Swift/QtUI/ContextMenus/QtRosterContextMenu.cpp b/Swift/QtUI/ContextMenus/QtRosterContextMenu.cpp index 10e0b56..e6b5ae5 100644 --- a/Swift/QtUI/ContextMenus/QtRosterContextMenu.cpp +++ b/Swift/QtUI/ContextMenus/QtRosterContextMenu.cpp @@ -11,9 +11,10 @@ #include +#include "Swiften/Roster/ContactRosterItem.h" #include "Swiften/Base/String.h" -#include "Swift/Controllers/UIEvents/RemoveItemRosterAction.h" -#include "Swift/QtUI/Roster/QtTreeWidgetItem.h" +#include "Swift/Controllers/UIEvents/UIEvent.h" +#include "Swift/Controllers/UIEvents/RemoveRosterItemUIEvent.h" #include "Swift/QtUI/QtSwiftUtil.h" namespace Swift { @@ -22,8 +23,9 @@ QtRosterContextMenu::QtRosterContextMenu(UIEventStream* eventStream) { eventStream_ = eventStream; } -void QtRosterContextMenu::show(QtTreeWidgetItem* item) { - if (!item->isContact()) { +void QtRosterContextMenu::show(RosterItem* item) { + ContactRosterItem* contact = dynamic_cast(item); + if (!contact) { return; } item_ = item; @@ -33,7 +35,9 @@ void QtRosterContextMenu::show(QtTreeWidgetItem* item) { } void QtRosterContextMenu::handleRemove() { - item_->performUserAction(boost::shared_ptr(new RemoveItemRosterAction())); + ContactRosterItem* contact = dynamic_cast(item_); + assert(contact); + eventStream_->send(boost::shared_ptr(new RemoveRosterItemUIEvent(contact->getJID()))); } } diff --git a/Swift/QtUI/ContextMenus/QtRosterContextMenu.h b/Swift/QtUI/ContextMenus/QtRosterContextMenu.h index ffa8ba6..51556e4 100644 --- a/Swift/QtUI/ContextMenus/QtRosterContextMenu.h +++ b/Swift/QtUI/ContextMenus/QtRosterContextMenu.h @@ -12,17 +12,18 @@ #include "Swift/Controllers/UIEvents/UIEventStream.h" namespace Swift { + class RosterItem; class QtRosterContextMenu : public QObject, public QtContextMenu { Q_OBJECT public: QtRosterContextMenu(UIEventStream* eventStream); - void show(QtTreeWidgetItem* item); + void show(RosterItem* item); private slots: void handleRemove(); private: - QtTreeWidgetItem* item_; + RosterItem* item_; UIEventStream* eventStream_; }; } diff --git a/Swift/QtUI/QtChatWindow.cpp b/Swift/QtUI/QtChatWindow.cpp index 5bedc22..d1b3194 100644 --- a/Swift/QtUI/QtChatWindow.cpp +++ b/Swift/QtUI/QtChatWindow.cpp @@ -6,8 +6,8 @@ #include "QtChatWindow.h" #include "QtSwiftUtil.h" +#include "Swiften/Roster/Roster.h" #include "Roster/QtTreeWidget.h" -#include "Roster/QtTreeWidgetFactory.h" #include "SwifTools/Linkify.h" #include "QtChatView.h" #include "MessageSnippet.h" @@ -26,7 +26,7 @@ #include namespace Swift { -QtChatWindow::QtChatWindow(const QString &contact, QtTreeWidgetFactory *treeWidgetFactory) : QtTabbable(), contact_(contact), previousMessageWasSelf_(false), previousMessageWasSystem_(false) { +QtChatWindow::QtChatWindow(const QString &contact, UIEventStream* eventStream) : QtTabbable(), contact_(contact), previousMessageWasSelf_(false), previousMessageWasSystem_(false), eventStream_(eventStream) { unreadCount_ = 0; updateTitleWithUnreadCount(); @@ -42,7 +42,7 @@ QtChatWindow::QtChatWindow(const QString &contact, QtTreeWidgetFactory *treeWidg messageLog_->setFocusPolicy(Qt::NoFocus); logRosterSplitter->addWidget(messageLog_); - treeWidget_ = dynamic_cast(treeWidgetFactory->createTreeWidget()); + treeWidget_ = new QtTreeWidget(eventStream_); treeWidget_->hide(); logRosterSplitter->addWidget(treeWidget_); @@ -79,8 +79,8 @@ QtChatWindow::~QtChatWindow() { } -TreeWidget* QtChatWindow::getTreeWidget() { - return treeWidget_; +void QtChatWindow::setRosterModel(Roster* roster) { + treeWidget_->setRosterModel(roster); } void QtChatWindow::setAvailableSecurityLabels(const std::vector& labels) { diff --git a/Swift/QtUI/QtChatWindow.h b/Swift/QtUI/QtChatWindow.h index f9b401c..0b22ea1 100644 --- a/Swift/QtUI/QtChatWindow.h +++ b/Swift/QtUI/QtChatWindow.h @@ -21,10 +21,11 @@ namespace Swift { class QtTreeWidgetFactory; class TreeWidget; class QtTextEdit; + class UIEventStream; class QtChatWindow : public QtTabbable, public ChatWindow { Q_OBJECT public: - QtChatWindow(const QString &contact, QtTreeWidgetFactory* treeWidgetFactory); + QtChatWindow(const QString &contact, UIEventStream* eventStream); ~QtChatWindow(); void addMessage(const String &message, const String &senderName, bool senderIsSelf, const boost::optional& label, const String& avatarPath); void addAction(const String &message, const String &senderName, bool senderIsSelf, const boost::optional& label, const String& avatarPath); @@ -34,7 +35,7 @@ namespace Swift { void activate(); void setUnreadMessageCount(int count); void convertToMUC(); - TreeWidget *getTreeWidget(); +// TreeWidget *getTreeWidget(); void setAvailableSecurityLabels(const std::vector& labels); void setSecurityLabelsEnabled(bool enabled); void setSecurityLabelsError(); @@ -43,6 +44,7 @@ namespace Swift { void setInputEnabled(bool enabled); QtTabbable::AlertType getWidgetAlertState(); void setContactChatState(ChatState::ChatStateType state); + void setRosterModel(Roster* roster); protected slots: void qAppFocusChanged(QWidget* old, QWidget* now); @@ -70,6 +72,7 @@ namespace Swift { bool previousMessageWasSystem_; QString previousSenderName_; bool inputClearing_; + UIEventStream* eventStream_; }; } diff --git a/Swift/QtUI/QtChatWindowFactory.cpp b/Swift/QtUI/QtChatWindowFactory.cpp index d96fa2b..5029324 100644 --- a/Swift/QtUI/QtChatWindowFactory.cpp +++ b/Swift/QtUI/QtChatWindowFactory.cpp @@ -11,11 +11,10 @@ #include "QtChatTabs.h" #include "QtChatWindow.h" #include "QtSwiftUtil.h" -#include "Roster/QtTreeWidgetFactory.h" namespace Swift { -QtChatWindowFactory::QtChatWindowFactory(QtTreeWidgetFactory *treeWidgetFactory, QSplitter* splitter, QtSettingsProvider* settings, QtChatTabs* tabs) : treeWidgetFactory_(treeWidgetFactory) { +QtChatWindowFactory::QtChatWindowFactory(QSplitter* splitter, QtSettingsProvider* settings, QtChatTabs* tabs) { settings_ = settings; tabs_ = tabs; if (splitter) { @@ -29,10 +28,9 @@ QtChatWindowFactory::QtChatWindowFactory(QtTreeWidgetFactory *treeWidgetFactory, } } -ChatWindow* QtChatWindowFactory::createChatWindow(const JID &contact) { - QtChatWindow *chatWindow = new QtChatWindow(P2QSTRING(contact.toString()), treeWidgetFactory_); +ChatWindow* QtChatWindowFactory::createChatWindow(const JID &contact,UIEventStream* eventStream) { + QtChatWindow *chatWindow = new QtChatWindow(P2QSTRING(contact.toString()), eventStream); tabs_->addTab(chatWindow); - //chatWindow->show(); return chatWindow; } diff --git a/Swift/QtUI/QtChatWindowFactory.h b/Swift/QtUI/QtChatWindowFactory.h index dc43146..4ffac88 100644 --- a/Swift/QtUI/QtChatWindowFactory.h +++ b/Swift/QtUI/QtChatWindowFactory.h @@ -4,8 +4,7 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#ifndef SWIFT_QtChatWindowFactory_H -#define SWIFT_QtChatWindowFactory_H +#pragma once #include "Swift/Controllers/UIInterfaces/ChatWindowFactory.h" #include "Swiften/JID/JID.h" @@ -14,20 +13,18 @@ #include #include namespace Swift { - class QtTreeWidgetFactory; class QtChatTabs; + class UIEventStream; class QtChatWindowFactory : public QObject, public ChatWindowFactory { Q_OBJECT public: - QtChatWindowFactory(QtTreeWidgetFactory *treeWidgetFactory, QSplitter* splitter, QtSettingsProvider* settings, QtChatTabs* tabs); - ChatWindow* createChatWindow(const JID &contact); + QtChatWindowFactory(QSplitter* splitter, QtSettingsProvider* settings, QtChatTabs* tabs); + ChatWindow* createChatWindow(const JID &contact, UIEventStream* eventStream); private slots: void handleWindowGeometryChanged(); private: - QtTreeWidgetFactory* treeWidgetFactory_; QtSettingsProvider* settings_; QtChatTabs* tabs_; }; } -#endif diff --git a/Swift/QtUI/QtMainWindow.cpp b/Swift/QtUI/QtMainWindow.cpp index fe4b179..0381d9e 100644 --- a/Swift/QtUI/QtMainWindow.cpp +++ b/Swift/QtUI/QtMainWindow.cpp @@ -23,14 +23,13 @@ #include "QtJoinMUCDialog.h" #include "QtSwiftUtil.h" #include "QtTabWidget.h" -#include "Roster/QtTreeWidgetFactory.h" #include "Roster/QtTreeWidget.h" #include "Swift/Controllers/UIEvents/AddContactUIEvent.h" #include "Swift/Controllers/UIEvents/JoinMUCUIEvent.h" namespace Swift { -QtMainWindow::QtMainWindow(UIEventStream* uiEventStream, QtTreeWidgetFactory *treeWidgetFactory) : QWidget() { +QtMainWindow::QtMainWindow(UIEventStream* uiEventStream) : QWidget() { uiEventStream_ = uiEventStream; setSizePolicy(QSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding)); QBoxLayout *mainLayout = new QBoxLayout(QBoxLayout::TopToBottom, this); @@ -53,7 +52,7 @@ QtMainWindow::QtMainWindow(UIEventStream* uiEventStream, QtTreeWidgetFactory *tr contactTabLayout->setSpacing(0); contactTabLayout->setContentsMargins(0, 0, 0, 0); - treeWidget_ = dynamic_cast(treeWidgetFactory->createTreeWidget()); + treeWidget_ = new QtTreeWidget(uiEventStream_); contextMenu_ = new QtRosterContextMenu(uiEventStream_); treeWidget_->setContextMenu(contextMenu_); treeWidget_->setVerticalScrollMode(QAbstractItemView::ScrollPerPixel); @@ -104,6 +103,10 @@ QtChatListWindow* QtMainWindow::getChatListWindow() { return chatListWindow_; } +void QtMainWindow::setRosterModel(Roster* roster) { + treeWidget_->setRosterModel(roster); +} + void QtMainWindow::handleEventCountUpdated(int count) { QColor eventTabColor = (count == 0) ? QColor(-1, -1, -1) : QColor(255, 0, 0); // invalid resets to default int eventIndex = 1; @@ -131,10 +134,6 @@ void QtMainWindow::handleAddContactDialogComplete(const JID& contact, const QStr uiEventStream_->send(event); } -TreeWidget* QtMainWindow::getTreeWidget() { - return treeWidget_; -} - void QtMainWindow::handleJoinMUCAction() { QtJoinMUCDialog* joinMUC = new QtJoinMUCDialog("jabber@conference.jabber.org", "SwiftUser", this); connect(joinMUC, SIGNAL(onJoinCommand(const JID&, const QString&)), SLOT(handleJoinMUCDialogComplete(const JID&, const QString&))); diff --git a/Swift/QtUI/QtMainWindow.h b/Swift/QtUI/QtMainWindow.h index 45dbda6..3c20d66 100644 --- a/Swift/QtUI/QtMainWindow.h +++ b/Swift/QtUI/QtMainWindow.h @@ -35,9 +35,8 @@ namespace Swift { class QtMainWindow : public QWidget, public MainWindow { Q_OBJECT public: - QtMainWindow(UIEventStream* eventStream, QtTreeWidgetFactory *treeWidgetFactory); + QtMainWindow(UIEventStream* eventStream); ~QtMainWindow(); - TreeWidget* getTreeWidget(); std::vector getMenus() {return menus_;} void setMyName(const String& name); void setMyAvatarPath(const String& path); @@ -45,6 +44,7 @@ namespace Swift { void setMyStatusType(const StatusShow::Type type); QtEventWindow* getEventWindow(); QtChatListWindow* getChatListWindow(); + void setRosterModel(Roster* roster); private slots: void handleStatusChanged(StatusShow::Type showType, const QString &statusMessage); void handleShowOfflineToggled(bool); diff --git a/Swift/QtUI/QtMainWindowFactory.cpp b/Swift/QtUI/QtMainWindowFactory.cpp index 12e3532..4405239 100644 --- a/Swift/QtUI/QtMainWindowFactory.cpp +++ b/Swift/QtUI/QtMainWindowFactory.cpp @@ -6,16 +6,15 @@ #include "QtMainWindowFactory.h" #include "QtMainWindow.h" -#include "Roster/QtTreeWidgetFactory.h" namespace Swift { -QtMainWindowFactory::QtMainWindowFactory(QtTreeWidgetFactory *treeWidgetFactory) : treeWidgetFactory_(treeWidgetFactory) { +QtMainWindowFactory::QtMainWindowFactory() { lastWindow_ = NULL; } MainWindow* QtMainWindowFactory::createMainWindow(UIEventStream* eventStream) { - lastWindow_ = new QtMainWindow(eventStream, treeWidgetFactory_); + lastWindow_ = new QtMainWindow(eventStream); return lastWindow_; } diff --git a/Swift/QtUI/QtMainWindowFactory.h b/Swift/QtUI/QtMainWindowFactory.h index c16d229..17eb53c 100644 --- a/Swift/QtUI/QtMainWindowFactory.h +++ b/Swift/QtUI/QtMainWindowFactory.h @@ -13,11 +13,10 @@ namespace Swift { class QtTreeWidgetFactory; class QtMainWindowFactory : public MainWindowFactory{ public: - QtMainWindowFactory(QtTreeWidgetFactory *treeWidgetFactory); + QtMainWindowFactory(); MainWindow* createMainWindow(UIEventStream* eventStream); MainWindow* getLastCreatedWindow(); private: - QtTreeWidgetFactory *treeWidgetFactory_; MainWindow* lastWindow_; }; } diff --git a/Swift/QtUI/QtSwift.cpp b/Swift/QtUI/QtSwift.cpp index fc5f4cb..534697b 100644 --- a/Swift/QtUI/QtSwift.cpp +++ b/Swift/QtUI/QtSwift.cpp @@ -11,7 +11,6 @@ #include "QtLoginWindow.h" #include "QtChatTabs.h" #include "QtMainWindowFactory.h" -#include "Roster/QtTreeWidgetFactory.h" #include "QtSystemTray.h" #include "QtSoundPlayer.h" #include "QtXMLConsoleWidgetFactory.h" @@ -65,11 +64,10 @@ QtSwift::QtSwift(po::variables_map options) : autoUpdater_(NULL) { tabs_ = new QtChatTabs(); settings_ = new QtSettingsProvider(); application_ = new PlatformApplication(SWIFT_APPLICATION_NAME); - treeWidgetFactory_ = new QtTreeWidgetFactory(); systemTray_ = new QtSystemTray(); loginWindowFactory_ = new QtLoginWindowFactory(splitter_, systemTray_, settings_); - chatWindowFactory_ = new QtChatWindowFactory(treeWidgetFactory_, splitter_, settings_, tabs_); - rosterWindowFactory_ = new QtMainWindowFactory(treeWidgetFactory_); + chatWindowFactory_ = new QtChatWindowFactory(splitter_, settings_, tabs_); + rosterWindowFactory_ = new QtMainWindowFactory(); eventWindowFactory_ = new QtEventWindowFactory(rosterWindowFactory_); xmlConsoleWidgetFactory_ = new QtXMLConsoleWidgetFactory(tabs_); chatListWindowFactory_ = new QtChatListWindowFactory(rosterWindowFactory_); @@ -77,7 +75,7 @@ QtSwift::QtSwift(po::variables_map options) : autoUpdater_(NULL) { if (splitter_) { splitter_->show(); } - mainController_ = new MainController(chatWindowFactory_, rosterWindowFactory_, loginWindowFactory_, treeWidgetFactory_, eventWindowFactory_, settings_, application_, systemTray_, soundPlayer_, xmlConsoleWidgetFactory_, chatListWindowFactory_, options.count("latency-debug") > 0); + mainController_ = new MainController(chatWindowFactory_, rosterWindowFactory_, loginWindowFactory_, eventWindowFactory_, settings_, application_, systemTray_, soundPlayer_, xmlConsoleWidgetFactory_, chatListWindowFactory_, options.count("latency-debug") > 0); PlatformAutoUpdaterFactory autoUpdaterFactory; if (autoUpdaterFactory.isSupported()) { @@ -91,7 +89,6 @@ QtSwift::~QtSwift() { delete chatWindowFactory_; delete rosterWindowFactory_; delete loginWindowFactory_; - delete treeWidgetFactory_; delete mainController_; delete settings_; delete application_; diff --git a/Swift/QtUI/QtSwift.h b/Swift/QtUI/QtSwift.h index 72343d8..d0141b2 100644 --- a/Swift/QtUI/QtSwift.h +++ b/Swift/QtUI/QtSwift.h @@ -28,7 +28,6 @@ namespace Swift { class QtChatWindowFactory; class QtMainWindowFactory; class QtLoginWindowFactory; - class QtTreeWidgetFactory; class QtXMLConsoleWidgetFactory; class QtSystemTray; class QtSoundPlayer; @@ -43,7 +42,6 @@ namespace Swift { ~QtSwift(); private: MainController *mainController_; - QtTreeWidgetFactory *treeWidgetFactory_; QtChatWindowFactory *chatWindowFactory_; QtChatListWindowFactory *chatListWindowFactory_; QtMainWindowFactory *rosterWindowFactory_; diff --git a/Swift/QtUI/Roster/QtTreeWidget.cpp b/Swift/QtUI/Roster/QtTreeWidget.cpp index 9dabc81..97b055b 100644 --- a/Swift/QtUI/Roster/QtTreeWidget.cpp +++ b/Swift/QtUI/Roster/QtTreeWidget.cpp @@ -7,7 +7,9 @@ #include "Roster/QtTreeWidget.h" #include "Swiften/Base/Platform.h" -#include "Swiften/Roster/OpenChatRosterAction.h" +#include "Swiften/Roster/ContactRosterItem.h" +#include "Swift/Controllers/UIEvents/UIEventStream.h" +#include "Swift/Controllers/UIEvents/RequestChatUIEvent.h" #include #include @@ -15,26 +17,26 @@ namespace Swift { -QtTreeWidget::QtTreeWidget(QWidget* parent) : QTreeView(parent) { - treeRoot_ = new QtTreeWidgetItem(NULL); - model_ = new RosterModel(); - model_->setRoot(treeRoot_); +QtTreeWidget::QtTreeWidget(UIEventStream* eventStream, QWidget* parent) : QTreeView(parent) { + eventStream_ = eventStream; + model_ = new RosterModel(this); setModel(model_); - delegate_ = new RosterDelegate(); + delegate_ = new RosterDelegate(this); setItemDelegate(delegate_); setHeaderHidden(true); contextMenu_ = NULL; #ifdef SWIFT_PLATFORM_MACOSX setAlternatingRowColors(true); #endif + expandAll(); setAnimated(true); setIndentation(0); setRootIsDecorated(true); connect(this, SIGNAL(activated(const QModelIndex&)), this, SLOT(handleItemActivated(const QModelIndex&))); - connect(model_, SIGNAL(itemExpanded(const QModelIndex&, bool)), this, SLOT(handleModelItemExpanded(const QModelIndex&, bool))); - connect(model_, SIGNAL(dataChanged(const QModelIndex&, const QModelIndex&)), this, SLOT(handleDataChanged(const QModelIndex&, const QModelIndex&))); - connect(this, SIGNAL(expanded(const QModelIndex&)), this, SLOT(handleExpanded(const QModelIndex&))); - connect(this, SIGNAL(collapsed(const QModelIndex&)), this, SLOT(handleCollapsed(const QModelIndex&))); +// connect(model_, SIGNAL(itemExpanded(const QModelIndex&, bool)), this, SLOT(handleModelItemExpanded(const QModelIndex&, bool))); +// connect(model_, SIGNAL(dataChanged(const QModelIndex&, const QModelIndex&)), this, SLOT(handleDataChanged(const QModelIndex&, const QModelIndex&))); +// connect(this, SIGNAL(expanded(const QModelIndex&)), this, SLOT(handleExpanded(const QModelIndex&))); +// connect(this, SIGNAL(collapsed(const QModelIndex&)), this, SLOT(handleCollapsed(const QModelIndex&))); } QtTreeWidget::~QtTreeWidget() { @@ -42,6 +44,11 @@ QtTreeWidget::~QtTreeWidget() { delete delegate_; } +void QtTreeWidget::setRosterModel(Roster* roster) { + model_->setRoster(roster); + expandAll(); +} + void QtTreeWidget::setContextMenu(QtContextMenu* contextMenu) { contextMenu_ = contextMenu; } @@ -51,9 +58,10 @@ QtTreeWidgetItem* QtTreeWidget::getRoot() { } void QtTreeWidget::handleItemActivated(const QModelIndex& index) { - QtTreeWidgetItem* qtItem = static_cast(index.internalPointer()); - if (qtItem) { - qtItem->performUserAction(boost::shared_ptr(new OpenChatRosterAction())); + RosterItem* item = static_cast(index.internalPointer()); + ContactRosterItem* contact = dynamic_cast(item); + if (contact) { + eventStream_->send(boost::shared_ptr(new RequestChatUIEvent(contact->getJID()))); } } @@ -62,53 +70,52 @@ void QtTreeWidget::contextMenuEvent(QContextMenuEvent* event) { return; } QModelIndex index = indexAt(event->pos()); - QtTreeWidgetItem* qtItem = index.isValid() ? static_cast(index.internalPointer()) : NULL; - if (qtItem) { - contextMenu_->show(qtItem); - } -} - -void QtTreeWidget::handleExpanded(const QModelIndex& index) { - QtTreeWidgetItem* qtItem = static_cast(index.internalPointer()); - if (qtItem) { - qtItem->setExpanded(true); - } -} - -void QtTreeWidget::handleCollapsed(const QModelIndex& index) { - QtTreeWidgetItem* qtItem = static_cast(index.internalPointer()); - if (qtItem) { - qtItem->setExpanded(false); - } -} - -void QtTreeWidget::handleModelItemExpanded(const QModelIndex& index, bool shouldExpand) { - if (this->isExpanded(index) == shouldExpand) { - return; - } - //setExpanded(index, shouldExpand); - if (shouldExpand) { - expand(index); - emit expanded(index); - } else { - collapse(index); - emit collapsed(index); + RosterItem* item = index.isValid() ? static_cast(index.internalPointer()) : NULL; + if (item) { + contextMenu_->show(item); } } -void QtTreeWidget::handleDataChanged(const QModelIndex& topLeft, const QModelIndex& bottomRight) { - Q_UNUSED(bottomRight); - //in our model, this is only thrown with topLeft == bottomRight - if (!topLeft.isValid()) { - return; - } - QtTreeWidgetItem* qtItem = static_cast(topLeft.internalPointer()); - if (qtItem) { - setExpanded(topLeft, qtItem->isExpanded()); - //qDebug() << "Item changed, passing expanded state to view: " << qtItem->isExpanded() << " giving an expanded state of " << isExpanded(topLeft); - } - -} +//void QtTreeWidget::handleExpanded(const QModelIndex& index) { +// QtTreeWidgetItem* qtItem = static_cast(index.internalPointer()); +// if (qtItem) { +// qtItem->setExpanded(true); +// } +//} + +//void QtTreeWidget::handleCollapsed(const QModelIndex& index) { +// QtTreeWidgetItem* qtItem = static_cast(index.internalPointer()); +// if (qtItem) { +// qtItem->setExpanded(false); +// } +//} + +//void QtTreeWidget::handleModelItemExpanded(const QModelIndex& index, bool shouldExpand) { +// if (this->isExpanded(index) == shouldExpand) { +// return; +// } +// //setExpanded(index, shouldExpand); +// if (shouldExpand) { +// expand(index); +// emit expanded(index); +// } else { +// collapse(index); +// emit collapsed(index); +// } +//} + +// void QtTreeWidget::handleDataChanged(const QModelIndex& topLeft, const QModelIndex& /*bottomRight*/) { +// //in our model, this is only thrown with topLeft == bottomRight +// if (!topLeft.isValid()) { +// return; +// } +// QtTreeWidgetItem* qtItem = static_cast(topLeft.internalPointer()); +// if (qtItem) { +// setExpanded(topLeft, qtItem->isExpanded()); +// //qDebug() << "Item changed, passing expanded state to view: " << qtItem->isExpanded() << " giving an expanded state of " << isExpanded(topLeft); +// } + +// } void QtTreeWidget::drawBranches(QPainter*, const QRect&, const QModelIndex&) const { } diff --git a/Swift/QtUI/Roster/QtTreeWidget.h b/Swift/QtUI/Roster/QtTreeWidget.h index d6e6038..c03f2e2 100644 --- a/Swift/QtUI/Roster/QtTreeWidget.h +++ b/Swift/QtUI/Roster/QtTreeWidget.h @@ -9,31 +9,29 @@ #include #include -#include "Swiften/Roster/TreeWidgetFactory.h" -#include "Swiften/Roster/TreeWidget.h" -#include "Swiften/Roster/TreeWidgetItem.h" -#include "Swift/QtUI/Roster/QtTreeWidgetItem.h" #include "Swift/QtUI/Roster/QtTreeWidget.h" #include "Swift/QtUI/Roster/RosterModel.h" #include "Swift/QtUI/Roster/RosterDelegate.h" #include "Swift/QtUI/ContextMenus/QtContextMenu.h" namespace Swift { +class UIEventStream; -class QtTreeWidget : public QTreeView, public TreeWidget { +class QtTreeWidget : public QTreeView{ Q_OBJECT public: - QtTreeWidget(QWidget* parent = 0); + QtTreeWidget(UIEventStream* eventStream, QWidget* parent = 0); ~QtTreeWidget(); void show(); QtTreeWidgetItem* getRoot(); void setContextMenu(QtContextMenu* contextMenu); + void setRosterModel(Roster* roster); private slots: void handleItemActivated(const QModelIndex&); - void handleModelItemExpanded(const QModelIndex&, bool expanded); - void handleExpanded(const QModelIndex&); - void handleCollapsed(const QModelIndex&); - void handleDataChanged(const QModelIndex& topLeft, const QModelIndex& bottomRight); +// void handleModelItemExpanded(const QModelIndex&, bool expanded); +// void handleExpanded(const QModelIndex&); +// void handleCollapsed(const QModelIndex&); +// void handleDataChanged(const QModelIndex& topLeft, const QModelIndex& bottomRight); protected: void contextMenuEvent(QContextMenuEvent* event); @@ -43,6 +41,7 @@ class QtTreeWidget : public QTreeView, public TreeWidget { RosterDelegate* delegate_; QtTreeWidgetItem* treeRoot_; QtContextMenu* contextMenu_; + UIEventStream* eventStream_; }; } diff --git a/Swift/QtUI/Roster/QtTreeWidgetFactory.cpp b/Swift/QtUI/Roster/QtTreeWidgetFactory.cpp deleted file mode 100644 index d4a8e4b..0000000 --- a/Swift/QtUI/Roster/QtTreeWidgetFactory.cpp +++ /dev/null @@ -1,6 +0,0 @@ -/* - * Copyright (c) 2010 Kevin Smith - * Licensed under the GNU General Public License v3. - * See Documentation/Licenses/GPLv3.txt for more information. - */ - diff --git a/Swift/QtUI/Roster/QtTreeWidgetFactory.h b/Swift/QtUI/Roster/QtTreeWidgetFactory.h deleted file mode 100644 index b72a508..0000000 --- a/Swift/QtUI/Roster/QtTreeWidgetFactory.h +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright (c) 2010 Kevin Smith - * Licensed under the GNU General Public License v3. - * See Documentation/Licenses/GPLv3.txt for more information. - */ - -#ifndef SWIFT_QtTreeWidgetFactory_H -#define SWIFT_QtTreeWidgetFactory_H - -#include "Swiften/Roster/TreeWidgetFactory.h" -#include "Swiften/Roster/TreeWidget.h" -#include "Swiften/Roster/TreeWidgetItem.h" -#include "Swift/QtUI/Roster/QtTreeWidgetItem.h" -#include "Swift/QtUI/Roster/QtTreeWidget.h" - -namespace Swift { - -class QtTreeWidgetFactory : public TreeWidgetFactory { - public: - QtTreeWidgetFactory() { - } - - TreeWidget* createTreeWidget() { - return new QtTreeWidget(); - } - - TreeWidgetItem* createTreeWidgetItem(TreeWidgetItem* item) { - QtTreeWidgetItem* qtItem = dynamic_cast(item); - assert(qtItem); - QtTreeWidgetItem* newItem = new QtTreeWidgetItem(qtItem); - qtItem->addChild(newItem); - return newItem; - } - - TreeWidgetItem* createTreeWidgetItem(TreeWidget* item) { - QtTreeWidget* treeItem = dynamic_cast(item); - assert(treeItem); - QtTreeWidgetItem* qtItem = treeItem->getRoot(); - QtTreeWidgetItem* newItem = new QtTreeWidgetItem(qtItem); - //qtItem->setItemWidget(newItem, 0, newItem->getCollapsedRosterWidget()); - qtItem->addChild(newItem); - newItem->setExpanded(true); - return newItem; - } -}; - -} -#endif - diff --git a/Swift/QtUI/Roster/RosterDelegate.cpp b/Swift/QtUI/Roster/RosterDelegate.cpp index 0c12d6e..b7ba71b 100644 --- a/Swift/QtUI/Roster/RosterDelegate.cpp +++ b/Swift/QtUI/Roster/RosterDelegate.cpp @@ -15,11 +15,16 @@ #include #include -#include "QtTreeWidgetItem.h" +#include "Swiften/Roster/ContactRosterItem.h" +#include "Swiften/Roster/GroupRosterItem.h" + +#include "QtTreeWidget.h" +#include "RosterModel.h" namespace Swift { -RosterDelegate::RosterDelegate() { +RosterDelegate::RosterDelegate(QtTreeWidget* tree) { + tree_ = tree; groupDelegate_ = new GroupItemDelegate(); } @@ -28,16 +33,14 @@ RosterDelegate::~RosterDelegate() { } QSize RosterDelegate::sizeHint(const QStyleOptionViewItem& option, const QModelIndex& index ) const { - QtTreeWidgetItem* item = static_cast(index.internalPointer()); - if (!item || !item->isContact()) { + RosterItem* item = static_cast(index.internalPointer()); + if (dynamic_cast(item)) { return groupDelegate_->sizeHint(option, index); } return contactSizeHint(option, index); } -QSize RosterDelegate::contactSizeHint(const QStyleOptionViewItem& option, const QModelIndex& index ) const { - Q_UNUSED(option); - Q_UNUSED(index); +QSize RosterDelegate::contactSizeHint(const QStyleOptionViewItem& /*option*/, const QModelIndex& /*index*/ ) const { int heightByAvatar = avatarSize_ + common_.verticalMargin * 2; QFontMetrics nameMetrics(common_.nameFont); QFontMetrics statusMetrics(common_.detailFont); @@ -49,8 +52,8 @@ QSize RosterDelegate::contactSizeHint(const QStyleOptionViewItem& option, const } void RosterDelegate::paint(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const { - QtTreeWidgetItem* item = static_cast(index.internalPointer()); - if (item && !item->isContact()) { + RosterItem* item = static_cast(index.internalPointer()); + if (dynamic_cast(item)) { paintGroup(painter, option, index); } else { paintContact(painter, option, index); @@ -58,15 +61,11 @@ void RosterDelegate::paint(QPainter* painter, const QStyleOptionViewItem& option } void RosterDelegate::paintGroup(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const { - QtTreeWidgetItem* item = index.isValid() ? static_cast(index.internalPointer()) : NULL; - if (item) { - groupDelegate_->paint(painter, option, index.data(Qt::DisplayRole).toString(), item->rowCount(), item->isExpanded()); + if (index.isValid()) { + groupDelegate_->paint(painter, option, index.data(Qt::DisplayRole).toString(), index.data(ChildCountRole).toInt(), tree_->isExpanded(index)); } } - - - void RosterDelegate::paintContact(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const { //qDebug() << "painting" << index.data(Qt::DisplayRole).toString(); painter->save(); diff --git a/Swift/QtUI/Roster/RosterDelegate.h b/Swift/QtUI/Roster/RosterDelegate.h index 696ea03..e6a16f2 100644 --- a/Swift/QtUI/Roster/RosterDelegate.h +++ b/Swift/QtUI/Roster/RosterDelegate.h @@ -14,10 +14,10 @@ #include "DelegateCommons.h" namespace Swift { - class QtTreeWidgetItem; + class QtTreeWidget; class RosterDelegate : public QStyledItemDelegate { public: - RosterDelegate(); + RosterDelegate(QtTreeWidget* tree); ~RosterDelegate(); QSize sizeHint(const QStyleOptionViewItem& option, const QModelIndex& index) const; void paint(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const; @@ -27,6 +27,7 @@ namespace Swift { void paintContact(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const; DelegateCommons common_; GroupItemDelegate* groupDelegate_; + QtTreeWidget* tree_; static const int avatarSize_; static const int presenceIconHeight_; static const int presenceIconWidth_; diff --git a/Swift/QtUI/Roster/RosterModel.cpp b/Swift/QtUI/Roster/RosterModel.cpp index c4cf57e..408cc3e 100644 --- a/Swift/QtUI/Roster/RosterModel.cpp +++ b/Swift/QtUI/Roster/RosterModel.cpp @@ -6,74 +6,184 @@ #include "RosterModel.h" +#include + +#include +#include +#include + +#include "Swiften/Elements/StatusShow.h" +#include "Swiften/Roster/ContactRosterItem.h" +#include "Swiften/Roster/GroupRosterItem.h" + +#include "QtSwiftUtil.h" +#include "Swift/QtUI/Roster/QtTreeWidget.h" + namespace Swift { -RosterModel::RosterModel() { +RosterModel::RosterModel(QtTreeWidget* view) : view_(view) { + roster_ = NULL; } RosterModel::~RosterModel() { - delete tree_; } -void RosterModel::setRoot(QtTreeWidgetItem* root) { - tree_ = root; - connect(tree_, SIGNAL(changed(QtTreeWidgetItem*)), this, SLOT(handleItemChanged(QtTreeWidgetItem*))); +void RosterModel::setRoster(Roster* roster) { + roster_ = roster; + if (!roster_) return; + roster->onChildrenChanged.connect(boost::bind(&RosterModel::handleChildrenChanged, this, _1)); + roster->onDataChanged.connect(boost::bind(&RosterModel::handleDataChanged, this, _1)); + roster->onGroupAdded.connect(boost::bind(&RosterModel::handleGroupAdded, this, _1)); + emit layoutChanged(); } - -void RosterModel::handleItemChanged(QtTreeWidgetItem* item) { - if (!item->isShown()) { - return; - } +void RosterModel::handleGroupAdded(GroupRosterItem* group) { + view_->setExpanded(index(group), true); +} + +void RosterModel::handleChildrenChanged(GroupRosterItem* /*group*/) { + emit layoutChanged(); +} + +void RosterModel::handleDataChanged(RosterItem* item) { Q_ASSERT(item); QModelIndex modelIndex = index(item); - Q_ASSERT(modelIndex.isValid()); - emit itemExpanded(modelIndex, item->isExpanded()); - emit dataChanged(modelIndex, modelIndex); - emit dataChanged(parent(modelIndex), parent(modelIndex)); - emit layoutChanged(); + if (modelIndex.isValid()) { + //emit itemExpanded(modelIndex, item->isExpanded()); + emit dataChanged(modelIndex, modelIndex); + } } -int RosterModel::columnCount(const QModelIndex& parent) const { - Q_UNUSED(parent); +int RosterModel::columnCount(const QModelIndex& /*parent*/) const { return 1; } +RosterItem* RosterModel::getItem(const QModelIndex& index) const { + return index.isValid() ? static_cast(index.internalPointer()) : NULL; +} + QVariant RosterModel::data(const QModelIndex& index, int role) const { - QtTreeWidgetItem* item = index.isValid() ? static_cast(index.internalPointer()) : NULL; - return item ? item->data(role) : QVariant(); + RosterItem* item = getItem(index); + if (!item) return QVariant(); + + switch (role) { + case Qt::DisplayRole: return P2QSTRING(item->getDisplayName()); + case Qt::TextColorRole: return getTextColor(item); + case Qt::BackgroundColorRole: return getBackgroundColor(item); + case Qt::ToolTipRole: return getToolTip(item); + case StatusTextRole: return getStatusText(item); + case AvatarRole: return getAvatar(item); + case PresenceIconRole: return getPresenceIcon(item); + case ChildCountRole: return getChildCount(item); + default: return QVariant(); + } } -QModelIndex RosterModel::index(int row, int column, const QModelIndex& parent) const { - QtTreeWidgetItem* parentItem = parent.isValid() ? static_cast(parent.internalPointer()) : tree_; - Q_ASSERT(parentItem); - - return row < parentItem->rowCount() ? createIndex(row, column, parentItem->getItem(row)) : QModelIndex(); +int RosterModel::getChildCount(RosterItem* item) const { + GroupRosterItem* group = dynamic_cast(item); + return group ? group->getDisplayedChildren().size() : 0; } -QModelIndex RosterModel::index(QtTreeWidgetItem* item) const { - return createIndex(item->row(), 0, item); +QColor RosterModel::intToColor(int color) const { + return QColor( + ((color & 0xFF0000)>>16), + ((color & 0xFF00)>>8), + (color & 0xFF)); } -QModelIndex RosterModel::parent(const QModelIndex& index) const { - if (!index.isValid()) { - return QModelIndex(); +QColor RosterModel::getTextColor(RosterItem* item) const { + ContactRosterItem* contact = dynamic_cast(item); + int color = 0; + if (contact) { + switch (contact->getStatusShow()) { + case StatusShow::Online: color = 0x000000; break; + case StatusShow::Away: color = 0x336699; break; + case StatusShow::XA: color = 0x336699; break; + case StatusShow::FFC: color = 0x000000; break; + case StatusShow::DND: color = 0x990000; break; + case StatusShow::None: color = 0x7F7F7F;break; + } } + return intToColor(color); +} + +QColor RosterModel::getBackgroundColor(RosterItem* item) const { + return dynamic_cast(item) ? intToColor(0xFFFFFF) : intToColor(0x969696); +} + +QString RosterModel::getToolTip(RosterItem* item) const { + return dynamic_cast(item) ? P2QSTRING(item->getDisplayName()) + "\n" + getStatusText(item) : P2QSTRING(item->getDisplayName()); +} + +QIcon RosterModel::getAvatar(RosterItem* item) const { + ContactRosterItem* contact = dynamic_cast(item); + if (!contact) return QIcon(); + String path = contact->getAvatarPath(); - QtTreeWidgetItem* item = static_cast(index.internalPointer()); - Q_ASSERT(item); + return path.isEmpty() ? QIcon() : QIcon(P2QSTRING(path)); +} - QtTreeWidgetItem* parentItem = item->getParentItem(); - /* parentItem_ == NULL can happen during destruction.*/ - return parentItem == tree_ || parentItem == NULL ? QModelIndex() : createIndex(parentItem->row(), 0, parentItem); +QString RosterModel::getStatusText(RosterItem* item) const { + ContactRosterItem* contact = dynamic_cast(item); + if (!contact) return ""; + return P2QSTRING(contact->getStatusText()); +} +QIcon RosterModel::getPresenceIcon(RosterItem* item) const { + ContactRosterItem* contact = dynamic_cast(item); + if (!contact) return QIcon(); + QString iconString; + switch (contact->getStatusShow()) { + case StatusShow::Online: iconString = "online";break; + case StatusShow::Away: iconString = "away";break; + case StatusShow::XA: iconString = "away";break; + case StatusShow::FFC: iconString = "online";break; + case StatusShow::DND: iconString = "dnd";break; + case StatusShow::None: iconString = "offline";break; + } + return QIcon(":/icons/" + iconString + ".png"); +} + + +QModelIndex RosterModel::index(int row, int column, const QModelIndex& parent) const { + GroupRosterItem* parentItem; + if (!parent.isValid()) { + //top level + parentItem = roster_->getRoot(); + } else { + parentItem = dynamic_cast(getItem(parent)); + if (!parentItem) return QModelIndex(); + } + return (size_t)row < parentItem->getDisplayedChildren().size() ? createIndex(row, column, parentItem->getDisplayedChildren()[row]) : QModelIndex(); +} + +QModelIndex RosterModel::index(RosterItem* item) const { + GroupRosterItem* parent = item->getParent(); + for (size_t i = 0; i < parent->getDisplayedChildren().size(); i++) { + if (parent->getDisplayedChildren()[i] == item) { + return createIndex(i, 0, item); + } + } + return QModelIndex(); +} + +QModelIndex RosterModel::parent(const QModelIndex& child) const { + if (!child.isValid()) { + return QModelIndex(); + } + + GroupRosterItem* parent = getItem(child)->getParent(); + return (parent != roster_->getRoot()) ? index(parent) : QModelIndex(); } int RosterModel::rowCount(const QModelIndex& parent) const { - QtTreeWidgetItem* item = parent.isValid() ? static_cast(parent.internalPointer()) : tree_; + if (!roster_) return 0; + RosterItem* item = parent.isValid() ? static_cast(parent.internalPointer()) : roster_->getRoot(); Q_ASSERT(item); - - return item->rowCount(); + GroupRosterItem* group = dynamic_cast(item); + int count = group ? group->getDisplayedChildren().size() : 0; + qDebug() << "rowCount = " << count << " where parent.isValid() == " << parent.isValid() << ", group == " << (group ? P2QSTRING(group->getDisplayName()) : "*contact*"); + return count; } } diff --git a/Swift/QtUI/Roster/RosterModel.h b/Swift/QtUI/Roster/RosterModel.h index 998f879..17fdd3e 100644 --- a/Swift/QtUI/Roster/RosterModel.h +++ b/Swift/QtUI/Roster/RosterModel.h @@ -6,30 +6,48 @@ #pragma once -#include "Swift/QtUI/Roster/QtTreeWidgetItem.h" +#include "Swiften/Roster/Roster.h" #include #include namespace Swift { -class RosterModel : public QAbstractItemModel { -Q_OBJECT -public: - RosterModel(); - ~RosterModel(); - void setRoot(QtTreeWidgetItem* tree); - int columnCount(const QModelIndex& parent = QModelIndex()) const; - QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const; - QModelIndex index(int row, int column, const QModelIndex & parent = QModelIndex()) const; - QModelIndex index(QtTreeWidgetItem* item) const; - QModelIndex parent(const QModelIndex& index) const; - int rowCount(const QModelIndex& parent = QModelIndex()) const; -signals: - void itemExpanded(const QModelIndex& item, bool expanded); -private slots: - void handleItemChanged(QtTreeWidgetItem* item); -private: - QtTreeWidgetItem* tree_; -}; + enum RosterRoles { + StatusTextRole = Qt::UserRole, + AvatarRole = Qt::UserRole + 1, + PresenceIconRole = Qt::UserRole + 2, + StatusShowTypeRole = Qt::UserRole + 3, + ChildCountRole = Qt::UserRole + 4, + }; + class QtTreeWidget; + + class RosterModel : public QAbstractItemModel { + Q_OBJECT + public: + RosterModel(QtTreeWidget* view); + ~RosterModel(); + void setRoster(Roster* swiftRoster); + int columnCount(const QModelIndex& parent = QModelIndex()) const; + QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const; + QModelIndex index(int row, int column, const QModelIndex & parent = QModelIndex()) const; + QModelIndex index(RosterItem* item) const; + QModelIndex parent(const QModelIndex& index) const; + int rowCount(const QModelIndex& parent = QModelIndex()) const; + private: + void handleDataChanged(RosterItem* item); + void handleChildrenChanged(GroupRosterItem* item); + void handleGroupAdded(GroupRosterItem* group); + RosterItem* getItem(const QModelIndex& index) const; + QColor intToColor(int color) const; + QColor getTextColor(RosterItem* item) const; + QColor getBackgroundColor(RosterItem* item) const; + QString getToolTip(RosterItem* item) const; + QIcon getAvatar(RosterItem* item) const; + QString getStatusText(RosterItem* item) const; + QIcon getPresenceIcon(RosterItem* item) const; + int getChildCount(RosterItem* item) const; + Roster* roster_; + QtTreeWidget* view_; + }; } diff --git a/Swift/QtUI/SConscript b/Swift/QtUI/SConscript index b4f8f64..4311623 100644 --- a/Swift/QtUI/SConscript +++ b/Swift/QtUI/SConscript @@ -80,7 +80,7 @@ sources = [ "SystemMessageSnippet.cpp", "Roster/RosterModel.cpp", "Roster/QtTreeWidget.cpp", - "Roster/QtTreeWidgetItem.cpp", +# "Roster/QtTreeWidgetItem.cpp", "Roster/RosterDelegate.cpp", "Roster/GroupItemDelegate.cpp", "Roster/DelegateCommons.cpp", diff --git a/Swiften/Roster/AppearOffline.h b/Swiften/Roster/AppearOffline.h index 792cec1..8e14190 100644 --- a/Swiften/Roster/AppearOffline.h +++ b/Swiften/Roster/AppearOffline.h @@ -21,7 +21,7 @@ class AppearOffline : public RosterItemOperation { virtual void operator() (RosterItem* item) const { ContactRosterItem* contact = dynamic_cast(item); if (contact) { - contact->setStatusShow(StatusShow::None); + contact->clearPresence(); } } diff --git a/Swiften/Roster/ContactRosterItem.cpp b/Swiften/Roster/ContactRosterItem.cpp index 39e96bd..2d5082c 100644 --- a/Swiften/Roster/ContactRosterItem.cpp +++ b/Swiften/Roster/ContactRosterItem.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010 Remko Tronçon + * Copyright (c) 2010 Kevin Smith * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. */ @@ -10,49 +10,77 @@ namespace Swift { -ContactRosterItem::ContactRosterItem(const JID& jid, const String& name, GroupRosterItem* parent, TreeWidgetFactory* factory) : jid_(jid), name_(name) { - parent->addChild(this); - widget_ = factory->createTreeWidgetItem(parent->getWidget()); - widget_->setText(name.isEmpty() ? jid.toString() : name); - widget_->onUserAction.connect(boost::bind(&ContactRosterItem::handleUserAction, this, _1)); - setStatusShow(StatusShow::None); +ContactRosterItem::ContactRosterItem(const JID& jid, const String& name, GroupRosterItem* parent) : RosterItem(name, parent), jid_(jid) { } ContactRosterItem::~ContactRosterItem() { - delete widget_; } -void ContactRosterItem::setName(const String& name) { - widget_->setText(name); +StatusShow::Type ContactRosterItem::getStatusShow() const { + return shownPresence_ ? shownPresence_->getShow() : StatusShow::None; } -StatusShow::Type ContactRosterItem::getStatusShow() { - return statusShow_; +StatusShow::Type ContactRosterItem::getSimplifiedStatusShow() const { + switch (shownPresence_ ? shownPresence_->getShow() : StatusShow::None) { + case StatusShow::Online: return StatusShow::Online; break; + case StatusShow::Away: return StatusShow::Away; break; + case StatusShow::XA: return StatusShow::Away; break; + case StatusShow::FFC: return StatusShow::Online; break; + case StatusShow::DND: return StatusShow::DND; break; + case StatusShow::None: return StatusShow::None; break; + } + assert(false); } -void ContactRosterItem::setStatusShow(StatusShow::Type show) { - statusShow_ = show; - widget_->setStatusShow(show); -} - -void ContactRosterItem::setStatusText(const String& status) { - widget_->setStatusText(status); +String ContactRosterItem::getStatusText() const { + return shownPresence_ ? shownPresence_->getStatus() : ""; } void ContactRosterItem::setAvatarPath(const String& path) { - widget_->setAvatarPath(path); + avatarPath_ = path; + onDataChanged(); +} +const String& ContactRosterItem::getAvatarPath() const { + return avatarPath_; } const JID& ContactRosterItem::getJID() const { return jid_; } -void ContactRosterItem::show() { - widget_->show(); +typedef std::pair > StringPresencePair; + +void ContactRosterItem::calculateShownPresence() { + shownPresence_ = offlinePresence_; + foreach (StringPresencePair presencePair, presences_) { + boost::shared_ptr presence = presencePair.second; + if (!shownPresence_ || presence->getPriority() > shownPresence_->getPriority() || presence->getShow() < shownPresence_->getShow()) { + shownPresence_ = presence; + } + } +} + +void ContactRosterItem::clearPresence() { + presences_.clear(); + calculateShownPresence(); } -void ContactRosterItem::hide() { - widget_->hide(); +void ContactRosterItem::applyPresence(const String& resource, boost::shared_ptr presence) { + if (offlinePresence_) { + offlinePresence_ = boost::shared_ptr(); + } + if (presence->getType() == Presence::Unavailable) { + if (presences_.find(resource) != presences_.end()) { + presences_.erase(resource); + } + if (presences_.size() > 0) { + offlinePresence_ = presence; + } + } else { + presences_[resource] = presence; + } + calculateShownPresence(); + onDataChanged(); } } diff --git a/Swiften/Roster/ContactRosterItem.h b/Swiften/Roster/ContactRosterItem.h index 92b3056..bd49e05 100644 --- a/Swiften/Roster/ContactRosterItem.h +++ b/Swiften/Roster/ContactRosterItem.h @@ -1,48 +1,47 @@ /* - * Copyright (c) 2010 Remko Tronçon + * Copyright (c) 2010 Kevin Smith * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. */ -#ifndef SWIFTEN_ContactRosterItem_H -#define SWIFTEN_ContactRosterItem_H +#pragma once #include "Swiften/Base/String.h" #include "Swiften/JID/JID.h" -#include "Swiften/Roster/TreeWidgetFactory.h" #include "Swiften/Roster/RosterItem.h" -#include "Swiften/Roster/UserRosterAction.h" #include "Swiften/Elements/StatusShow.h" +#include "Swiften/Elements/Presence.h" +#include #include #include #include namespace Swift { -class TreeWidgetItem; class GroupRosterItem; class ContactRosterItem : public RosterItem { public: - ContactRosterItem(const JID& jid, const String& name, GroupRosterItem* parent, TreeWidgetFactory* factory); - ~ContactRosterItem(); + ContactRosterItem(const JID& jid, const String& name, GroupRosterItem* parent); + virtual ~ContactRosterItem(); - StatusShow::Type getStatusShow(); - void setStatusShow(StatusShow::Type show); - void setStatusText(const String& status); + StatusShow::Type getStatusShow() const; + StatusShow::Type getSimplifiedStatusShow() const; + String getStatusText() const; void setAvatarPath(const String& path); + const String& getAvatarPath() const; const JID& getJID() const; - void setName(const String& name); - void show(); - void hide(); - + void applyPresence(const String& resource, boost::shared_ptr presence); + void clearPresence(); + void calculateShownPresence(); private: JID jid_; - String name_; - TreeWidgetItem *widget_; - StatusShow::Type statusShow_; + String avatarPath_; + bool hidden_; + std::map > presences_; + boost::shared_ptr offlinePresence_; + boost::shared_ptr shownPresence_; }; } -#endif diff --git a/Swiften/Roster/GroupRosterItem.cpp b/Swiften/Roster/GroupRosterItem.cpp new file mode 100644 index 0000000..05530ec --- /dev/null +++ b/Swiften/Roster/GroupRosterItem.cpp @@ -0,0 +1,140 @@ +/* + * Copyright (c) 2010 Kevin Smith + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#include "Swiften/Roster/GroupRosterItem.h" + +#include +#include + +namespace Swift { + +GroupRosterItem::GroupRosterItem(const String& name, GroupRosterItem* parent) : RosterItem(name, parent) { + +} + +GroupRosterItem::~GroupRosterItem() { + +} + +const std::vector& GroupRosterItem::getChildren() const { + return children_; +} + +const std::vector& GroupRosterItem::getDisplayedChildren() const { +// std::cout << "Fetching displayed children for " << getDisplayName() << " and found " << displayedChildren_.size() << std::endl; + return displayedChildren_; +} + +void GroupRosterItem::addChild(RosterItem* item) { + children_.push_back(item); + GroupRosterItem* group = dynamic_cast(item); + if (group) { + group->onChildrenChanged.connect(boost::bind(&GroupRosterItem::handleChildrenChanged, this, group)); + } + onChildrenChanged(); + onDataChanged(); +} + +/** + * Returns the removed item - but only if it's the only one, otherwise + * the return result is undefined. + */ +ContactRosterItem* GroupRosterItem::removeChild(const JID& jid) { + std::vector::iterator it = children_.begin(); + ContactRosterItem* removed = NULL; + while (it != children_.end()) { + ContactRosterItem* contact = dynamic_cast(*it); + if (contact && contact->getJID() == jid) { + displayedChildren_.erase(std::remove(displayedChildren_.begin(), displayedChildren_.end(), contact), displayedChildren_.end()); + removed = contact; + delete contact; + it = children_.erase(it); + continue; + } + GroupRosterItem* group = dynamic_cast(*it); + if (group) { + ContactRosterItem* groupRemoved = group->removeChild(jid); + if (groupRemoved) { + removed = groupRemoved; + } + } + it++; + } + onChildrenChanged(); + onDataChanged(); + return removed; +} + +void GroupRosterItem::sortDisplayed() { + std::stable_sort(displayedChildren_.begin(), displayedChildren_.end(), itemLessThan); +} + +bool GroupRosterItem::itemLessThan(const RosterItem* left, const RosterItem* right) { + const ContactRosterItem* leftContact = dynamic_cast(left); + const ContactRosterItem* rightContact = dynamic_cast(right); + if (leftContact) { + if (rightContact) { + return false; + } + StatusShow::Type leftType = leftContact->getSimplifiedStatusShow(); + StatusShow::Type rightType = rightContact->getSimplifiedStatusShow(); + if (leftType == rightType) { + return left->getSortableDisplayName() < right->getSortableDisplayName(); + } else { + return leftType < rightType; + } + } else { + if (rightContact) { + return true; + } + return left->getSortableDisplayName() < right->getSortableDisplayName(); + } +} + +void GroupRosterItem::setDisplayed(RosterItem* item, bool displayed) { + bool found = false; + for (size_t i = 0; i < displayedChildren_.size(); i++) { + if (displayedChildren_[i] == item) { + found = true; + } + } + if (found == displayed) { + return; + } + if (displayed) { + displayedChildren_.push_back(item); + sortDisplayed(); + } else { + displayedChildren_.erase(std::remove(displayedChildren_.begin(), displayedChildren_.end(), item), displayedChildren_.end()); + } + onDataChanged(); + onChildrenChanged(); +} + +void GroupRosterItem::handleChildrenChanged(GroupRosterItem* group) { + size_t oldSize = getDisplayedChildren().size(); + if (group->getDisplayedChildren().size() > 0) { + bool found = false; + for (size_t i = 0; i < displayedChildren_.size(); i++) { + if (displayedChildren_[i] == group) { + found = true; + } + } + if (!found) { + displayedChildren_.push_back(group); + sortDisplayed(); + } + } else { + displayedChildren_.erase(std::remove(displayedChildren_.begin(), displayedChildren_.end(), group), displayedChildren_.end()); + } + if (oldSize != getDisplayedChildren().size()) { + onDataChanged(); + onChildrenChanged(); + } +} + + +} diff --git a/Swiften/Roster/GroupRosterItem.h b/Swiften/Roster/GroupRosterItem.h index 83128a5..5e16b2b 100644 --- a/Swiften/Roster/GroupRosterItem.h +++ b/Swiften/Roster/GroupRosterItem.h @@ -1,74 +1,37 @@ /* - * Copyright (c) 2010 Remko Tronçon + * Copyright (c) 2010 Kevin Smith * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. */ -#ifndef SWIFTEN_GroupRosterItem_H -#define SWIFTEN_GroupRosterItem_H +#pragma once #include "Swiften/Roster/RosterItem.h" #include "Swiften/Base/String.h" -#include "Swiften/Roster/TreeWidget.h" -#include "Swiften/Roster/TreeWidgetFactory.h" -#include "Swiften/Roster/TreeWidgetItem.h" #include "Swiften/Roster/ContactRosterItem.h" -#include +#include namespace Swift { class GroupRosterItem : public RosterItem { public: - GroupRosterItem(const String& name, TreeWidget* tree, TreeWidgetFactory* factory) : name_(name) { - widget_ = factory->createTreeWidgetItem(tree); - widget_->setExpanded(true); - widget_->setText(name); - } - - ~GroupRosterItem() { - delete widget_; - } - - const String& getName() const { - return name_; - } - - TreeWidgetItem* getWidget() const { - return widget_; - } - - const std::list& getChildren() const { - return children_; - } - - void addChild(RosterItem* item) { - children_.push_back(item); - } - - void removeChild(const JID& jid) { - std::list::iterator it = children_.begin(); - while (it != children_.end()) { - ContactRosterItem* contact = dynamic_cast(*it); - if (contact && contact->getJID() == jid) { - delete contact; - it = children_.erase(it); - continue; - } - GroupRosterItem* group = dynamic_cast(*it); - if (group) { - group->removeChild(jid); - } - it++; - } - } - + GroupRosterItem(const String& name, GroupRosterItem* parent); + virtual ~GroupRosterItem(); + const std::vector& getChildren() const; + const std::vector& getDisplayedChildren() const; + void addChild(RosterItem* item); + ContactRosterItem* removeChild(const JID& jid); + void setDisplayed(RosterItem* item, bool displayed); + boost::signal onChildrenChanged; + static bool itemLessThan(const RosterItem* left, const RosterItem* right); private: + void handleChildrenChanged(GroupRosterItem* group); + void sortDisplayed(); String name_; - TreeWidgetItem* widget_; - std::list children_; + std::vector children_; + std::vector displayedChildren_; }; } -#endif diff --git a/Swiften/Roster/OpenChatRosterAction.h b/Swiften/Roster/OpenChatRosterAction.h deleted file mode 100644 index b0784f5..0000000 --- a/Swiften/Roster/OpenChatRosterAction.h +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Copyright (c) 2010 Remko Tronçon - * Licensed under the GNU General Public License v3. - * See Documentation/Licenses/GPLv3.txt for more information. - */ - -#ifndef SWIFTEN_OpenChatRosterAction_H -#define SWIFTEN_OpenChatRosterAction_H - -#include "Swiften/Roster/UserRosterAction.h" - -namespace Swift { -class RosterItem; -class TreeWidgetItem; - -class OpenChatRosterAction : public UserRosterAction { - public: - virtual ~OpenChatRosterAction() {}; - -}; - -} -#endif - - - diff --git a/Swiften/Roster/Roster.cpp b/Swiften/Roster/Roster.cpp index 8c2aa0e..c25fd41 100644 --- a/Swiften/Roster/Roster.cpp +++ b/Swiften/Roster/Roster.cpp @@ -13,79 +13,93 @@ #include "Swiften/Roster/RosterItem.h" #include "Swiften/Roster/GroupRosterItem.h" #include "Swiften/Roster/RosterItemOperation.h" -#include "Swiften/Roster/TreeWidget.h" -#include "Swiften/Roster/TreeWidgetFactory.h" #include +#include #include namespace Swift { -Roster::Roster(TreeWidget *treeWidget, TreeWidgetFactory *widgetFactory) : treeWidget_(treeWidget), widgetFactory_(widgetFactory) { +Roster::Roster() { + root_ = new GroupRosterItem("Dummy-Root", NULL); } Roster::~Roster() { - foreach (RosterItem* item, items_) { + std::deque queue; + queue.push_back(root_); + while (!queue.empty()) { + RosterItem* item = *queue.begin(); + queue.pop_front(); + GroupRosterItem* group = dynamic_cast(item); + if (group) { + queue.insert(queue.begin(), group->getChildren().begin(), group->getChildren().end()); + } delete item; } - delete treeWidget_; } -TreeWidget* Roster::getWidget() { - return treeWidget_; +GroupRosterItem* Roster::getRoot() { + return root_; } GroupRosterItem* Roster::getGroup(const String& groupName) { - foreach (RosterItem *item, children_) { + foreach (RosterItem *item, root_->getChildren()) { GroupRosterItem *group = dynamic_cast(item); - if (group && group->getName() == groupName) { + if (group && group->getDisplayName() == groupName) { return group; } } - GroupRosterItem* group = new GroupRosterItem(groupName, treeWidget_, widgetFactory_); - children_.push_back(group); - items_.push_back(group); + GroupRosterItem* group = new GroupRosterItem(groupName, root_); + root_->addChild(group); +// std::cout << "Added " << groupName << " to root" << std::endl; + group->onChildrenChanged.connect(boost::bind(&Roster::handleChildrenChanged, this, group)); + group->onDataChanged.connect(boost::bind(&Roster::handleDataChanged, this, group)); return group; } -void Roster::handleUserAction(boost::shared_ptr action) { - onUserAction(action); +void Roster::handleDataChanged(RosterItem* item) { + onDataChanged(item); } -void Roster::addContact(const JID& jid, const String& name, const String& group) { - ContactRosterItem *item = new ContactRosterItem(jid, name, getGroup(group), widgetFactory_); - items_.push_back(item); - itemMap_[jid.toBare()].push_back(item); - item->onUserAction.connect(boost::bind(&Roster::handleUserAction, this, _1)); - filterItem(item); +void Roster::handleChildrenChanged(GroupRosterItem* item) { + onChildrenChanged(item); +} +void Roster::addContact(const JID& jid, const String& name, const String& groupName) { + GroupRosterItem* group(getGroup(groupName)); + ContactRosterItem *item = new ContactRosterItem(jid, name, group); + group->addChild(item); + itemMap_[jid.toBare()].push_back(item); + item->onDataChanged.connect(boost::bind(&Roster::handleDataChanged, this, item)); + filterContact(item, group); } + void Roster::removeContact(const JID& jid) { - itemMap_.erase(jid.toBare()); - std::vector::iterator it = children_.begin(); - while (it != children_.end()) { - ContactRosterItem* contact = dynamic_cast(*it); - if (contact && contact->getJID() == jid) { - delete contact; - it = children_.erase(it); - continue; - } - GroupRosterItem* group = dynamic_cast(*it); - if (group) { - group->removeChild(jid); + std::vector items = itemMap_[jid.toBare()]; + std::vector::iterator it = items.begin(); + while (it != items.end()) { + if (jid == (*it)->getJID()) { + it = items.erase(it); } - it++; } + if (items.size() == 0) { + itemMap_.erase(jid.toBare()); + } + //Causes the delete + root_->removeChild(jid); } void Roster::removeContactFromGroup(const JID& jid, const String& groupName) { - std::vector::iterator it = children_.begin(); - while (it != children_.end()) { + std::vector children = root_->getChildren(); + std::vector::iterator it = children.begin(); + while (it != children.end()) { GroupRosterItem* group = dynamic_cast(*it); - if (group && group->getName() == groupName) { - group->removeChild(jid); + if (group && group->getDisplayName() == groupName) { + ContactRosterItem* deleted = group->removeChild(jid); + std::vector items = itemMap_[jid.toBare()]; + items.erase(std::remove(items.begin(), items.end(), deleted), items.end()); } it++; } @@ -101,14 +115,15 @@ void Roster::applyOnItems(const RosterItemOperation& operation) { } void Roster::applyOnItem(const RosterItemOperation& operation, const JID& jid) { - foreach (RosterItem* item, itemMap_[jid]) { + foreach (ContactRosterItem* item, itemMap_[jid.toBare()]) { operation(item); - filterItem(item); + filterContact(item, item->getParent()); } } void Roster::applyOnAllItems(const RosterItemOperation& operation) { - std::deque queue(children_.begin(), children_.end()); + std::deque queue; + queue.push_back(root_); while (!queue.empty()) { RosterItem* item = *queue.begin(); queue.pop_front(); @@ -131,29 +146,40 @@ void Roster::removeFilter(RosterFilter *filter) { filterAll(); } - -void Roster::filterItem(RosterItem* rosterItem) { - ContactRosterItem *item = dynamic_cast(rosterItem); - if (!item) { - return; - } +void Roster::filterContact(ContactRosterItem* contact, GroupRosterItem* group) { + int oldDisplayedSize = group->getDisplayedChildren().size(); bool hide = true; foreach (RosterFilter *filter, filters_) { - hide &= (*filter)(item); + hide &= (*filter)(contact); + } + group->setDisplayed(contact, filters_.size() == 0 || !hide); + int newDisplayedSize = group->getDisplayedChildren().size(); +// std::cout << ", new size = " << newDisplayedSize << std::endl; + if (oldDisplayedSize == 0 && newDisplayedSize > 0) { +// std::cout << "Newly created" << std::endl; + onGroupAdded(group); + } +} + +void Roster::filterGroup(GroupRosterItem* group) { + foreach (RosterItem* child, group->getChildren()) { + ContactRosterItem* contact = dynamic_cast(child); + if (contact) { + filterContact(contact, group); + } } - filters_.size() > 0 && hide ? item->hide() : item->show(); } void Roster::filterAll() { - std::deque queue(children_.begin(), children_.end()); + std::deque queue; + queue.push_back(root_); while (!queue.empty()) { RosterItem *item = *queue.begin(); queue.pop_front(); GroupRosterItem* group = dynamic_cast(item); if (group) { queue.insert(queue.begin(), group->getChildren().begin(), group->getChildren().end()); - } else { - filterItem(item); + filterGroup(group); } } } diff --git a/Swiften/Roster/Roster.h b/Swiften/Roster/Roster.h index 5fc3cfb..3af89d7 100644 --- a/Swiften/Roster/Roster.h +++ b/Swiften/Roster/Roster.h @@ -10,7 +10,6 @@ #include "Swiften/Base/String.h" #include "Swiften/JID/JID.h" #include "Swiften/Roster/RosterItemOperation.h" -#include "Swiften/Roster/UserRosterAction.h" #include "Swiften/Roster/RosterFilter.h" #include @@ -20,39 +19,38 @@ namespace Swift { -class TreeWidgetFactory; -class TreeWidget; class RosterItem; class GroupRosterItem; +class ContactRosterItem; class Roster { public: - Roster(TreeWidget *treeWidget, TreeWidgetFactory *widgetFactory); + Roster(); ~Roster(); - TreeWidget* getWidget(); - GroupRosterItem* getGroup(const String& groupName); void addContact(const JID& jid, const String& name, const String& group); void removeContact(const JID& jid); void removeContactFromGroup(const JID& jid, const String& group); void applyOnItems(const RosterItemOperation& operation); void applyOnAllItems(const RosterItemOperation& operation); void applyOnItem(const RosterItemOperation& operation, const JID& jid); - boost::signal)> onUserAction; - void addFilter(RosterFilter *filter) {filters_.push_back(filter);filterAll();} + void addFilter(RosterFilter *filter) {filters_.push_back(filter);filterAll();}; void removeFilter(RosterFilter *filter); - std::vector getFilters() {return filters_;} - + GroupRosterItem* getRoot(); + std::vector getFilters() {return filters_;}; + boost::signal onChildrenChanged; + boost::signal onGroupAdded; + boost::signal onDataChanged; private: - void filterItem(RosterItem* item); + GroupRosterItem* getGroup(const String& groupName); + void handleDataChanged(RosterItem* item); + void handleChildrenChanged(GroupRosterItem* item); + void filterGroup(GroupRosterItem* item); + void filterContact(ContactRosterItem* contact, GroupRosterItem* group); void filterAll(); - void handleUserAction(boost::shared_ptr action); - TreeWidget *treeWidget_; - TreeWidgetFactory *widgetFactory_; - std::vector children_; - std::vector items_; + GroupRosterItem* root_; std::vector filters_; - std::map > itemMap_; + std::map > itemMap_; }; } diff --git a/Swiften/Roster/RosterItem.cpp b/Swiften/Roster/RosterItem.cpp new file mode 100644 index 0000000..7229199 --- /dev/null +++ b/Swiften/Roster/RosterItem.cpp @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2010 Kevin Smith + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#include "Swiften/Roster/RosterItem.h" + +#include "Swiften/Roster/GroupRosterItem.h" + +namespace Swift { + +RosterItem::RosterItem(const String& name, GroupRosterItem* parent) : name_(name), parent_(parent) { + /* The following would be good, but because of C++'s inheritance not working in constructors, it's not going to work. */ + //if (parent) { + // parent_->addChild(this); + //} +} + +RosterItem::~RosterItem() { + +} + +GroupRosterItem* RosterItem::getParent() const { + return parent_; +} + +void RosterItem::setDisplayName(const String& name) { + name_ = name; + sortableDisplayName_ = name_.getLowerCase(); + onDataChanged(); +} + +String RosterItem::getDisplayName() const { + return name_; +} + +String RosterItem::getSortableDisplayName() const { + return sortableDisplayName_; +} + + +} + diff --git a/Swiften/Roster/RosterItem.h b/Swiften/Roster/RosterItem.h index 2c2a7e4..3a1a1b1 100644 --- a/Swiften/Roster/RosterItem.h +++ b/Swiften/Roster/RosterItem.h @@ -1,30 +1,32 @@ /* - * Copyright (c) 2010 Remko Tronçon + * Copyright (c) 2010 Kevin Smith * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. */ -#ifndef SWIFTEN_RosterItem_H -#define SWIFTEN_RosterItem_H - -#include "Swiften/Roster/UserRosterAction.h" +#pragma once #include #include -namespace Swift { +#include "Swiften/Base/String.h" +namespace Swift { +class GroupRosterItem; class RosterItem { public: - virtual ~RosterItem() {}; - boost::signal)> onUserAction; - protected: - void handleUserAction(boost::shared_ptr action) { - action->setRosterItem(this); - onUserAction(action); - } + RosterItem(const String& name, GroupRosterItem* parent); + virtual ~RosterItem(); + boost::signal onDataChanged; + GroupRosterItem* getParent() const; + void setDisplayName(const String& name); + String getDisplayName() const; + String getSortableDisplayName() const; + private: + String name_; + String sortableDisplayName_; + GroupRosterItem* parent_; }; } -#endif diff --git a/Swiften/Roster/RosterItemOperation.h b/Swiften/Roster/RosterItemOperation.h index a901fb4..e27e68b 100644 --- a/Swiften/Roster/RosterItemOperation.h +++ b/Swiften/Roster/RosterItemOperation.h @@ -17,6 +17,11 @@ class RosterItemOperation { virtual ~RosterItemOperation() {}; bool requiresLookup() const {return requiresLookup_;}; const JID& lookupJID() const {return lookupJID_;}; + /** + * This is called when iterating over possible subjects, so must check it's + * applying to the right items - even if requiresLookup() is true an item + * with the same bare JID but different full JID may be passed. + */ virtual void operator() (RosterItem*) const = 0; private: bool requiresLookup_; diff --git a/Swiften/Roster/SetName.h b/Swiften/Roster/SetName.h index 33dd521..d3f7749 100644 --- a/Swiften/Roster/SetName.h +++ b/Swiften/Roster/SetName.h @@ -22,7 +22,7 @@ class SetName : public RosterItemOperation { virtual void operator() (RosterItem* item) const { ContactRosterItem* contact = dynamic_cast(item); if (contact && contact->getJID().equals(jid_, compareType_)) { - contact->setName(name_); + contact->setDisplayName(name_); } } diff --git a/Swiften/Roster/SetPresence.h b/Swiften/Roster/SetPresence.h index 9cc3ba9..134a63d 100644 --- a/Swiften/Roster/SetPresence.h +++ b/Swiften/Roster/SetPresence.h @@ -4,8 +4,7 @@ * See Documentation/Licenses/GPLv3.txt for more information. */ -#ifndef SWIFTEN_SetPresence_H -#define SWIFTEN_SetPresence_H +#pragma once #include "Swiften/Elements/Presence.h" #include "Swiften/JID/JID.h" @@ -24,13 +23,7 @@ class SetPresence : public RosterItemOperation { virtual void operator() (RosterItem* item) const { ContactRosterItem* contact = dynamic_cast(item); if (contact && contact->getJID().equals(presence_->getFrom(), compareType_)) { - if (presence_->getType() != Presence::Available) { - contact->setStatusShow(StatusShow::None); - contact->setStatusText(presence_->getStatus()); - } else { - contact->setStatusShow(presence_->getShow()); - contact->setStatusText(presence_->getStatus()); - } + contact->applyPresence(presence_->getFrom().getResource(), presence_); } } @@ -40,5 +33,4 @@ class SetPresence : public RosterItemOperation { }; } -#endif diff --git a/Swiften/Roster/TreeWidget.h b/Swiften/Roster/TreeWidget.h deleted file mode 100644 index 78b67b7..0000000 --- a/Swiften/Roster/TreeWidget.h +++ /dev/null @@ -1,19 +0,0 @@ -/* - * Copyright (c) 2010 Remko Tronçon - * Licensed under the GNU General Public License v3. - * See Documentation/Licenses/GPLv3.txt for more information. - */ - -#ifndef SWIFTEN_TreeWidget_H -#define SWIFTEN_TreeWidget_H - -namespace Swift { - -class TreeWidget { - public: - virtual ~TreeWidget() {} -}; - -} -#endif - diff --git a/Swiften/Roster/TreeWidgetFactory.h b/Swiften/Roster/TreeWidgetFactory.h deleted file mode 100644 index fbc4417..0000000 --- a/Swiften/Roster/TreeWidgetFactory.h +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Copyright (c) 2010 Remko Tronçon - * Licensed under the GNU General Public License v3. - * See Documentation/Licenses/GPLv3.txt for more information. - */ - -#ifndef SWIFTEN_TreeWidgetFactory_H -#define SWIFTEN_TreeWidgetFactory_H - -namespace Swift { - -class TreeWidgetItem; -class TreeWidget; - -class TreeWidgetFactory { - public: - virtual ~TreeWidgetFactory() {} - virtual TreeWidget* createTreeWidget() = 0; - virtual TreeWidgetItem* createTreeWidgetItem(TreeWidgetItem* item) = 0; - virtual TreeWidgetItem* createTreeWidgetItem(TreeWidget* item) = 0; -}; - -} - -#endif - diff --git a/Swiften/Roster/TreeWidgetItem.h b/Swiften/Roster/TreeWidgetItem.h deleted file mode 100644 index 1718776..0000000 --- a/Swiften/Roster/TreeWidgetItem.h +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright (c) 2010 Remko Tronçon - * Licensed under the GNU General Public License v3. - * See Documentation/Licenses/GPLv3.txt for more information. - */ - -#ifndef SWIFTEN_TreeWidgetItem_H -#define SWIFTEN_TreeWidgetItem_H - -#include "Swiften/Base/String.h" -#include "Swiften/Roster/UserRosterAction.h" -#include "Swiften/Elements/StatusShow.h" - -#include -#include - -namespace Swift { - -class TreeWidgetItem { - public: - virtual ~TreeWidgetItem() {} - virtual void setText(const String& text) = 0; - virtual void setStatusText(const String& text) = 0; - virtual void setAvatarPath(const String& path) = 0; - virtual void setExpanded(bool b) = 0; - //virtual void setTextColor(unsigned long color) = 0; - virtual void setStatusShow(StatusShow::Type show) = 0; - //virtual void setBackgroundColor(unsigned long color) = 0; - boost::signal)> onUserAction; - virtual void show() = 0; - virtual void hide() = 0; - void performUserAction(boost::shared_ptr action) { - action->setTreeWidgetItem(this); - onUserAction(action); - } -}; - -} -#endif - diff --git a/Swiften/Roster/UnitTest/MockTreeWidget.h b/Swiften/Roster/UnitTest/MockTreeWidget.h deleted file mode 100644 index 97dd796..0000000 --- a/Swiften/Roster/UnitTest/MockTreeWidget.h +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright (c) 2010 Kevin Smith - * Licensed under the GNU General Public License v3. - * See Documentation/Licenses/GPLv3.txt for more information. - */ - -#ifndef SWIFTEN_MockTreeWidget_H -#define SWIFTEN_MockTreeWidget_H - -#include "Swiften/Roster/TreeWidget.h" - -namespace Swift { - -class MockTreeWidget : public TreeWidget { - public: - virtual ~MockTreeWidget() {} -}; - -} -#endif diff --git a/Swiften/Roster/UnitTest/MockTreeWidgetFactory.h b/Swiften/Roster/UnitTest/MockTreeWidgetFactory.h deleted file mode 100644 index d94c859..0000000 --- a/Swiften/Roster/UnitTest/MockTreeWidgetFactory.h +++ /dev/null @@ -1,74 +0,0 @@ -/* - * Copyright (c) 2010 Kevin Smith - * Licensed under the GNU General Public License v3. - * See Documentation/Licenses/GPLv3.txt for more information. - */ - -#ifndef SWIFTEN_MockTreeWidgetFactory_H -#define SWIFTEN_MockTreeWidgetFactory_H - -#include "Swiften/Roster/TreeWidgetFactory.h" - -#include -#include "Swiften/Base/foreach.h" -#include "Swiften/Roster/UnitTest/MockTreeWidget.h" -#include "Swiften/Roster/UnitTest/MockTreeWidgetItem.h" - -namespace Swift { - -class MockTreeWidgetItem; -class MockTreeWidget; - -class MockTreeWidgetFactory : public TreeWidgetFactory { - public: - virtual ~MockTreeWidgetFactory() {} - virtual TreeWidget* createTreeWidget() { - root_ = new MockTreeWidget(); - return root_; - }; - virtual TreeWidgetItem* createTreeWidgetItem(TreeWidgetItem* group) { - MockTreeWidgetItem* entry = new MockTreeWidgetItem(this); - groupMembers_[group].push_back(entry); - return entry; - }; - virtual TreeWidgetItem* createTreeWidgetItem(TreeWidget*) { - MockTreeWidgetItem* group = new MockTreeWidgetItem(this); - groups_.push_back(group); - return group; - }; - virtual std::vector getGroups() { - std::vector groupNames; - foreach (MockTreeWidgetItem* group, groups_) { - groupNames.push_back(group->getText()); - } - return groupNames; - }; - - typedef std::map > itemMap; - - virtual std::vector getGroupMembers(const String& group) { - for (itemMap::iterator it = groupMembers_.begin(); it != groupMembers_.end(); it++) { - if (((MockTreeWidgetItem*)(it->first))->getText() == group) { - return it->second; - } - } - return std::vector(); - }; - - virtual void removeItem(MockTreeWidgetItem* item) { - foreach (TreeWidgetItem* groupItem, groups_) { - std::vector& members = groupMembers_[groupItem]; - members.erase(std::remove(members.begin(), members.end(), item), members.end()); - } - }; - private: - std::vector groups_; - std::map > groupMembers_; - MockTreeWidget* root_; -}; - -} - -#endif - - diff --git a/Swiften/Roster/UnitTest/MockTreeWidgetItem.cpp b/Swiften/Roster/UnitTest/MockTreeWidgetItem.cpp deleted file mode 100644 index 4238ead..0000000 --- a/Swiften/Roster/UnitTest/MockTreeWidgetItem.cpp +++ /dev/null @@ -1,19 +0,0 @@ -/* - * Copyright (c) 2010 Kevin Smith - * Licensed under the GNU General Public License v3. - * See Documentation/Licenses/GPLv3.txt for more information. - */ -#include "Swiften/Roster/UnitTest/MockTreeWidgetItem.h" - -#include "Swiften/Roster/UnitTest/MockTreeWidgetFactory.h" - -namespace Swift { - -MockTreeWidgetItem::~MockTreeWidgetItem() { - factory_->removeItem(this); -} - -} - - - diff --git a/Swiften/Roster/UnitTest/MockTreeWidgetItem.h b/Swiften/Roster/UnitTest/MockTreeWidgetItem.h deleted file mode 100644 index 08b9f1a..0000000 --- a/Swiften/Roster/UnitTest/MockTreeWidgetItem.h +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright (c) 2010 Kevin Smith - * Licensed under the GNU General Public License v3. - * See Documentation/Licenses/GPLv3.txt for more information. - */ - -#ifndef SWIFTEN_MockTreeWidgetItem_H -#define SWIFTEN_MockTreeWidgetItem_H - -#include "Swiften/Base/String.h" -#include "Swiften/Roster/TreeWidgetItem.h" - -#include -#include - -namespace Swift { - class MockTreeWidgetFactory; -class MockTreeWidgetItem : public TreeWidgetItem { - public: - MockTreeWidgetItem(MockTreeWidgetFactory* factory) {factory_ = factory;}; - virtual ~MockTreeWidgetItem(); - virtual void setText(const String& text) {text_ = text;}; - String getText() {return text_;}; - virtual void setStatusText(const String&) {}; - virtual void setAvatarPath(const String&) {}; - virtual void setExpanded(bool) {}; - virtual void setStatusShow(StatusShow::Type /*show*/) {}; - virtual void show() {}; - virtual void hide() {}; - private: - String text_; - MockTreeWidgetFactory* factory_; -}; - -} -#endif - - diff --git a/Swiften/Roster/UnitTest/RosterTest.cpp b/Swiften/Roster/UnitTest/RosterTest.cpp index 5a2a3e3..f9dff33 100644 --- a/Swiften/Roster/UnitTest/RosterTest.cpp +++ b/Swiften/Roster/UnitTest/RosterTest.cpp @@ -9,9 +9,7 @@ #include #include "Swiften/Roster/Roster.h" -#include "Swiften/Roster/UnitTest/MockTreeWidget.h" -#include "Swiften/Roster/UnitTest/MockTreeWidgetFactory.h" -#include "Swiften/Roster/UnitTest/MockTreeWidgetItem.h" +#include "Swiften/Roster/GroupRosterItem.h" using namespace Swift; @@ -23,8 +21,6 @@ class RosterTest : public CppUnit::TestFixture private: Roster *roster_; - TreeWidget *widget_; - TreeWidgetFactory *factory_; JID jid1_; JID jid2_; JID jid3_; @@ -34,15 +30,11 @@ class RosterTest : public CppUnit::TestFixture RosterTest() : jid1_(JID("a@b.c")), jid2_(JID("b@c.d")), jid3_(JID("c@d.e")) {} void setUp() { - factory_ = new MockTreeWidgetFactory(); - widget_ = factory_->createTreeWidget(); - roster_ = new Roster(widget_, factory_); + roster_ = new Roster(); } void tearDown() { delete roster_; - //delete widget_; - delete factory_; } void testGetGroup() { @@ -50,12 +42,13 @@ class RosterTest : public CppUnit::TestFixture roster_->addContact(jid2_, "Ernie", "group2"); roster_->addContact(jid3_, "Cookie", "group1"); - CPPUNIT_ASSERT_EQUAL(roster_->getGroup("group1"), roster_->getGroup("group1")); - CPPUNIT_ASSERT_EQUAL(roster_->getGroup("group2"), roster_->getGroup("group2")); - CPPUNIT_ASSERT_EQUAL(roster_->getGroup("group3"), roster_->getGroup("group3")); - CPPUNIT_ASSERT(roster_->getGroup("group1") != roster_->getGroup("group2")); - CPPUNIT_ASSERT(roster_->getGroup("group2") != roster_->getGroup("group3")); - CPPUNIT_ASSERT(roster_->getGroup("group3") != roster_->getGroup("group1")); + CPPUNIT_ASSERT_EQUAL(2, (int)roster_->getRoot()->getChildren().size()); + CPPUNIT_ASSERT_EQUAL(String("group1"), roster_->getRoot()->getChildren()[0]->getDisplayName()); + CPPUNIT_ASSERT_EQUAL(String("group2"), roster_->getRoot()->getChildren()[1]->getDisplayName()); + CPPUNIT_ASSERT_EQUAL(String("Bert"), ((GroupRosterItem*)roster_->getRoot()->getChildren()[0])->getChildren()[0]->getDisplayName()); + CPPUNIT_ASSERT_EQUAL(String("Cookie"), ((GroupRosterItem*)roster_->getRoot()->getChildren()[0])->getChildren()[1]->getDisplayName()); + CPPUNIT_ASSERT_EQUAL(String("Ernie"), ((GroupRosterItem*)roster_->getRoot()->getChildren()[1])->getChildren()[0]->getDisplayName()); + } }; diff --git a/Swiften/Roster/UserRosterAction.h b/Swiften/Roster/UserRosterAction.h deleted file mode 100644 index b869530..0000000 --- a/Swiften/Roster/UserRosterAction.h +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright (c) 2010 Remko Tronçon - * Licensed under the GNU General Public License v3. - * See Documentation/Licenses/GPLv3.txt for more information. - */ - -#ifndef SWIFTEN_UserRosterAction_H -#define SWIFTEN_UserRosterAction_H - -namespace Swift { -class RosterItem; -class TreeWidgetItem; - -class UserRosterAction { - public: - virtual ~UserRosterAction() {}; - void setRosterItem(RosterItem *item) { - rosterItem_ = item; - }; - void setTreeWidgetItem(TreeWidgetItem *item) { - treeWidgetItem_ = item; - } - RosterItem* getRosterItem() { - return rosterItem_; - } - TreeWidgetItem* getTreeWidgetItem() { - return treeWidgetItem_; - } - - private: - RosterItem *rosterItem_; - TreeWidgetItem *treeWidgetItem_; -}; - -} -#endif - - diff --git a/Swiften/SConscript b/Swiften/SConscript index dfda3ba..a95635a 100644 --- a/Swiften/SConscript +++ b/Swiften/SConscript @@ -54,6 +54,8 @@ if env["SCONS_STAGE"] == "build" : "Queries/Responders/DiscoInfoResponder.cpp", "Queries/Responders/SoftwareVersionResponder.cpp", "Roster/ContactRosterItem.cpp", + "Roster/GroupRosterItem.cpp", + "Roster/RosterItem.cpp", "Roster/Roster.cpp", "Roster/XMPPRoster.cpp", "Serializer/AuthRequestSerializer.cpp", @@ -191,7 +193,6 @@ if env["SCONS_STAGE"] == "build" : File("Roster/UnitTest/OfflineRosterFilterTest.cpp"), File("Roster/UnitTest/RosterTest.cpp"), File("Roster/UnitTest/XMPPRosterTest.cpp"), - File("Roster/UnitTest/MockTreeWidgetItem.cpp"), File("SASL/UnitTest/PLAINMessageTest.cpp"), File("SASL/UnitTest/PLAINClientAuthenticatorTest.cpp"), File("SASL/UnitTest/SCRAMSHA1ClientAuthenticatorTest.cpp"), -- cgit v0.10.2-6-g49f6