diff options
Diffstat (limited to 'Swift')
34 files changed, 682 insertions, 241 deletions
diff --git a/Swift/Controllers/Chat/ChatsManager.cpp b/Swift/Controllers/Chat/ChatsManager.cpp index 5d69019..a7e8b73 100644 --- a/Swift/Controllers/Chat/ChatsManager.cpp +++ b/Swift/Controllers/Chat/ChatsManager.cpp @@ -31,4 +31,5 @@ #include <Swiften/Client/ClientBlockListManager.h> #include <Swiften/Client/StanzaChannel.h> +#include <Swiften/VCards/VCardManager.h> #include <Swift/Controllers/Chat/ChatController.h> @@ -124,5 +125,6 @@ ChatsManager::ChatsManager( ClientBlockListManager* clientBlockListManager, const std::map<std::string, std::string>& emoticons, - UserSearchController* inviteUserSearchController) : + UserSearchController* inviteUserSearchController, + VCardManager* vcardManager) : jid_(jid), joinMUCWindowFactory_(joinMUCWindowFactory), @@ -139,5 +141,6 @@ ChatsManager::ChatsManager( highlightManager_(highlightManager), clientBlockListManager_(clientBlockListManager), - inviteUserSearchController_(inviteUserSearchController) { + inviteUserSearchController_(inviteUserSearchController), + vcardManager_(vcardManager) { timerFactory_ = timerFactory; eventController_ = eventController; @@ -768,5 +771,5 @@ MUC::ref ChatsManager::handleJoinMUCRequest(const JID &mucJID, const boost::opti chatWindowFactoryAdapter = new SingleChatWindowFactoryAdapter(reuseChatwindow); } - controller = new MUCController(jid_, muc, password, nick, stanzaChannel_, iqRouter_, reuseChatwindow ? chatWindowFactoryAdapter : chatWindowFactory_, presenceOracle_, avatarManager_, uiEventStream_, false, timerFactory_, eventController_, entityCapsProvider_, roster_, historyController_, mucRegistry_, highlightManager_, chatMessageParser_, isImpromptu, autoAcceptMUCInviteDecider_); + controller = new MUCController(jid_, muc, password, nick, stanzaChannel_, iqRouter_, reuseChatwindow ? chatWindowFactoryAdapter : chatWindowFactory_, presenceOracle_, avatarManager_, uiEventStream_, false, timerFactory_, eventController_, entityCapsProvider_, roster_, historyController_, mucRegistry_, highlightManager_, chatMessageParser_, isImpromptu, autoAcceptMUCInviteDecider_, vcardManager_); if (chatWindowFactoryAdapter) { /* The adapters are only passed to chat windows, which are deleted in their diff --git a/Swift/Controllers/Chat/ChatsManager.h b/Swift/Controllers/Chat/ChatsManager.h index c9dd856..979d52a 100644 --- a/Swift/Controllers/Chat/ChatsManager.h +++ b/Swift/Controllers/Chat/ChatsManager.h @@ -63,8 +63,9 @@ namespace Swift { class AutoAcceptMUCInviteDecider; class UserSearchController; + class VCardManager; class ChatsManager : public ContactProvider { public: - ChatsManager(JID jid, StanzaChannel* stanzaChannel, IQRouter* iqRouter, EventController* eventController, ChatWindowFactory* chatWindowFactory, JoinMUCWindowFactory* joinMUCWindowFactory, NickResolver* nickResolver, PresenceOracle* presenceOracle, PresenceSender* presenceSender, UIEventStream* uiEventStream, ChatListWindowFactory* chatListWindowFactory, bool useDelayForLatency, TimerFactory* timerFactory, MUCRegistry* mucRegistry, EntityCapsProvider* entityCapsProvider, MUCManager* mucManager, MUCSearchWindowFactory* mucSearchWindowFactory, ProfileSettingsProvider* profileSettings, FileTransferOverview* ftOverview, XMPPRoster* roster, bool eagleMode, SettingsProvider* settings, HistoryController* historyController_, WhiteboardManager* whiteboardManager, HighlightManager* highlightManager, ClientBlockListManager* clientBlockListManager, const std::map<std::string, std::string>& emoticons, UserSearchController* inviteUserSearchController); + ChatsManager(JID jid, StanzaChannel* stanzaChannel, IQRouter* iqRouter, EventController* eventController, ChatWindowFactory* chatWindowFactory, JoinMUCWindowFactory* joinMUCWindowFactory, NickResolver* nickResolver, PresenceOracle* presenceOracle, PresenceSender* presenceSender, UIEventStream* uiEventStream, ChatListWindowFactory* chatListWindowFactory, bool useDelayForLatency, TimerFactory* timerFactory, MUCRegistry* mucRegistry, EntityCapsProvider* entityCapsProvider, MUCManager* mucManager, MUCSearchWindowFactory* mucSearchWindowFactory, ProfileSettingsProvider* profileSettings, FileTransferOverview* ftOverview, XMPPRoster* roster, bool eagleMode, SettingsProvider* settings, HistoryController* historyController_, WhiteboardManager* whiteboardManager, HighlightManager* highlightManager, ClientBlockListManager* clientBlockListManager, const std::map<std::string, std::string>& emoticons, UserSearchController* inviteUserSearchController, VCardManager* vcardManager); virtual ~ChatsManager(); void setAvatarManager(AvatarManager* avatarManager); @@ -181,4 +182,5 @@ namespace Swift { UserSearchController* inviteUserSearchController_; IDGenerator idGenerator_; + VCardManager* vcardManager_; }; } diff --git a/Swift/Controllers/Chat/MUCController.cpp b/Swift/Controllers/Chat/MUCController.cpp index 37631a5..ed3ed5f 100644 --- a/Swift/Controllers/Chat/MUCController.cpp +++ b/Swift/Controllers/Chat/MUCController.cpp @@ -34,4 +34,5 @@ #include <Swiften/Client/StanzaChannel.h> #include <Swift/Controllers/Roster/Roster.h> +#include <Swift/Controllers/Roster/RosterVCardProvider.h> #include <Swift/Controllers/Roster/SetAvatar.h> #include <Swift/Controllers/Roster/SetPresence.h> @@ -71,5 +72,6 @@ MUCController::MUCController ( ChatMessageParser* chatMessageParser, bool isImpromptu, - AutoAcceptMUCInviteDecider* autoAcceptMUCInviteDecider) : + AutoAcceptMUCInviteDecider* autoAcceptMUCInviteDecider, + VCardManager* vcardManager) : ChatControllerBase(self, stanzaChannel, iqRouter, chatWindowFactory, muc->getJID(), presenceOracle, avatarManager, useDelayForLatency, uiEventStream, eventController, timerFactory, entityCapsProvider, historyController, mucRegistry, highlightManager, chatMessageParser, autoAcceptMUCInviteDecider), muc_(muc), nick_(nick), desiredNick_(nick), password_(password), renameCounter_(0), isImpromptu_(isImpromptu), isImpromptuAlreadyConfigured_(false) { parting_ = true; @@ -82,4 +84,5 @@ MUCController::MUCController ( roster_ = new Roster(false, true); + rosterVCardProvider_ = new RosterVCardProvider(roster_, vcardManager, JID::WithResource); completer_ = new TabComplete(); chatWindow_->setRosterModel(roster_); @@ -131,4 +134,5 @@ MUCController::~MUCController() { eventStream_->onUIEvent.disconnect(boost::bind(&MUCController::handleUIEvent, this, _1)); chatWindow_->setRosterModel(NULL); + delete rosterVCardProvider_; delete roster_; if (loginCheckTimer_) { diff --git a/Swift/Controllers/Chat/MUCController.h b/Swift/Controllers/Chat/MUCController.h index 9283438..317f579 100644 --- a/Swift/Controllers/Chat/MUCController.h +++ b/Swift/Controllers/Chat/MUCController.h @@ -38,4 +38,6 @@ namespace Swift { class HighlightManager; class UIEvent; + class VCardManager; + class RosterVCardProvider; enum JoinPart {Join, Part, JoinThenPart, PartThenJoin}; @@ -49,6 +51,6 @@ namespace Swift { class MUCController : public ChatControllerBase { public: - MUCController(const JID& self, MUC::ref muc, const boost::optional<std::string>& password, const std::string &nick, StanzaChannel* stanzaChannel, IQRouter* iqRouter, ChatWindowFactory* chatWindowFactory, PresenceOracle* presenceOracle, AvatarManager* avatarManager, UIEventStream* events, bool useDelayForLatency, TimerFactory* timerFactory, EventController* eventController, EntityCapsProvider* entityCapsProvider, XMPPRoster* roster, HistoryController* historyController, MUCRegistry* mucRegistry, HighlightManager* highlightManager, ChatMessageParser* chatMessageParser, bool isImpromptu, AutoAcceptMUCInviteDecider* autoAcceptMUCInviteDecider); - ~MUCController(); + MUCController(const JID& self, MUC::ref muc, const boost::optional<std::string>& password, const std::string &nick, StanzaChannel* stanzaChannel, IQRouter* iqRouter, ChatWindowFactory* chatWindowFactory, PresenceOracle* presenceOracle, AvatarManager* avatarManager, UIEventStream* events, bool useDelayForLatency, TimerFactory* timerFactory, EventController* eventController, EntityCapsProvider* entityCapsProvider, XMPPRoster* roster, HistoryController* historyController, MUCRegistry* mucRegistry, HighlightManager* highlightManager, ChatMessageParser* chatMessageParser, bool isImpromptu, AutoAcceptMUCInviteDecider* autoAcceptMUCInviteDecider, VCardManager* vcardManager); + virtual ~MUCController(); boost::signal<void ()> onUserLeft; boost::signal<void ()> onUserJoined; @@ -147,4 +149,5 @@ namespace Swift { bool isImpromptu_; bool isImpromptuAlreadyConfigured_; + RosterVCardProvider* rosterVCardProvider_; }; } diff --git a/Swift/Controllers/Chat/UnitTest/ChatsManagerTest.cpp b/Swift/Controllers/Chat/UnitTest/ChatsManagerTest.cpp index f5a3003..4c604ac 100644 --- a/Swift/Controllers/Chat/UnitTest/ChatsManagerTest.cpp +++ b/Swift/Controllers/Chat/UnitTest/ChatsManagerTest.cpp @@ -7,51 +7,56 @@ #include <cppunit/extensions/HelperMacros.h> #include <cppunit/extensions/TestFactoryRegistry.h> + #include <hippomocks.h> #include <boost/bind.hpp> -#include <Swift/Controllers/Chat/ChatsManager.h> - -#include <Swift/Controllers/Chat/UnitTest/MockChatListWindow.h> -#include <Swift/Controllers/UIInterfaces/ChatWindow.h> -#include <Swift/Controllers/Settings/DummySettingsProvider.h> -#include <Swift/Controllers/UIInterfaces/ChatWindowFactory.h> -#include <Swift/Controllers/UIInterfaces/ChatListWindowFactory.h> -#include <Swift/Controllers/UIInterfaces/WhiteboardWindowFactory.h> -#include <Swift/Controllers/UIInterfaces/JoinMUCWindowFactory.h> -#include <Swift/Controllers/UIInterfaces/MUCSearchWindowFactory.h> +#include <Swiften/Avatars/AvatarMemoryStorage.h> +#include <Swiften/Avatars/NullAvatarManager.h> +#include <Swiften/Base/Algorithm.h> #include <Swiften/Client/Client.h> -#include <Swiften/Disco/EntityCapsManager.h> +#include <Swiften/Client/ClientBlockListManager.h> +#include <Swiften/Client/DummyStanzaChannel.h> +#include <Swiften/Client/NickResolver.h> +#include <Swiften/Crypto/CryptoProvider.h> +#include <Swiften/Crypto/PlatformCryptoProvider.h> #include <Swiften/Disco/CapsProvider.h> +#include <Swiften/Disco/EntityCapsManager.h> +#include <Swiften/Elements/DeliveryReceipt.h> +#include <Swiften/Elements/DeliveryReceiptRequest.h> +#include <Swiften/FileTransfer/UnitTest/DummyFileTransferManager.h> +#include <Swiften/Jingle/JingleSessionManager.h> #include <Swiften/MUC/MUCManager.h> -#include <Swift/Controllers/Chat/ChatController.h> -#include <Swift/Controllers/XMPPEvents/EventController.h> -#include <Swift/Controllers/Chat/MUCController.h> +#include <Swiften/Presence/DirectedPresenceSender.h> +#include <Swiften/Presence/PresenceOracle.h> #include <Swiften/Presence/StanzaChannelPresenceSender.h> -#include <Swiften/Avatars/NullAvatarManager.h> -#include <Swiften/Avatars/AvatarMemoryStorage.h> +#include <Swiften/Queries/DummyIQChannel.h> +#include <Swiften/Roster/XMPPRosterImpl.h> +#include <Swiften/VCards/VCardManager.h> #include <Swiften/VCards/VCardManager.h> #include <Swiften/VCards/VCardMemoryStorage.h> -#include <Swiften/Client/NickResolver.h> -#include <Swiften/Presence/DirectedPresenceSender.h> -#include <Swiften/Roster/XMPPRosterImpl.h> -#include <Swift/Controllers/UnitTest/MockChatWindow.h> -#include <Swiften/Client/DummyStanzaChannel.h> -#include <Swiften/Queries/DummyIQChannel.h> -#include <Swiften/Presence/PresenceOracle.h> -#include <Swiften/Jingle/JingleSessionManager.h> -#include <Swiften/FileTransfer/UnitTest/DummyFileTransferManager.h> -#include <Swift/Controllers/UIEvents/RequestChatUIEvent.h> -#include <Swift/Controllers/UIEvents/JoinMUCUIEvent.h> -#include <Swift/Controllers/UIEvents/UIEventStream.h> -#include <Swift/Controllers/ProfileSettingsProvider.h> +#include <Swiften/Whiteboard/WhiteboardSessionManager.h> + +#include <Swift/Controllers/Chat/ChatsManager.h> +#include <Swift/Controllers/Chat/ChatController.h> +#include <Swift/Controllers/Chat/MUCController.h> +#include <Swift/Controllers/Chat/UnitTest/MockChatListWindow.h> #include <Swift/Controllers/FileTransfer/FileTransferOverview.h> -#include <Swiften/Elements/DeliveryReceiptRequest.h> -#include <Swiften/Elements/DeliveryReceipt.h> -#include <Swiften/Base/Algorithm.h> +#include <Swift/Controllers/ProfileSettingsProvider.h> #include <Swift/Controllers/SettingConstants.h> +#include <Swift/Controllers/Settings/DummySettingsProvider.h> +#include <Swift/Controllers/UIEvents/JoinMUCUIEvent.h> +#include <Swift/Controllers/UIEvents/RequestChatUIEvent.h> +#include <Swift/Controllers/UIEvents/UIEventStream.h> +#include <Swift/Controllers/UIInterfaces/ChatListWindowFactory.h> +#include <Swift/Controllers/UIInterfaces/ChatWindow.h> +#include <Swift/Controllers/UIInterfaces/ChatWindowFactory.h> +#include <Swift/Controllers/UIInterfaces/JoinMUCWindowFactory.h> +#include <Swift/Controllers/UIInterfaces/MUCSearchWindowFactory.h> +#include <Swift/Controllers/UIInterfaces/WhiteboardWindowFactory.h> +#include <Swift/Controllers/UnitTest/MockChatWindow.h> #include <Swift/Controllers/WhiteboardManager.h> -#include <Swiften/Whiteboard/WhiteboardSessionManager.h> -#include <Swiften/Client/ClientBlockListManager.h> +#include <Swift/Controllers/XMPPEvents/EventController.h> + using namespace Swift; @@ -110,7 +115,10 @@ public: highlightManager_ = new HighlightManager(settings_); + crypto_ = PlatformCryptoProvider::create(); + vcardStorage_ = new VCardMemoryStorage(crypto_); + vcardManager_ = new VCardManager(jid_, iqRouter_, vcardStorage_); mocks_->ExpectCall(chatListWindowFactory_, ChatListWindowFactory::createChatListWindow).With(uiEventStream_).Return(chatListWindow_); clientBlockListManager_ = new ClientBlockListManager(iqRouter_); - manager_ = new ChatsManager(jid_, stanzaChannel_, iqRouter_, eventController_, chatWindowFactory_, joinMUCWindowFactory_, nickResolver_, presenceOracle_, directedPresenceSender_, uiEventStream_, chatListWindowFactory_, true, NULL, mucRegistry_, entityCapsManager_, mucManager_, mucSearchWindowFactory_, profileSettings_, ftOverview_, xmppRoster_, false, settings_, NULL, wbManager_, highlightManager_, clientBlockListManager_, emoticons_, NULL); + manager_ = new ChatsManager(jid_, stanzaChannel_, iqRouter_, eventController_, chatWindowFactory_, joinMUCWindowFactory_, nickResolver_, presenceOracle_, directedPresenceSender_, uiEventStream_, chatListWindowFactory_, true, NULL, mucRegistry_, entityCapsManager_, mucManager_, mucSearchWindowFactory_, profileSettings_, ftOverview_, xmppRoster_, false, settings_, NULL, wbManager_, highlightManager_, clientBlockListManager_, emoticons_, NULL, vcardManager_); manager_->setAvatarManager(avatarManager_); @@ -124,4 +132,7 @@ public: delete manager_; delete clientBlockListManager_; + delete vcardManager_; + delete vcardStorage_; + delete crypto_; delete ftOverview_; delete ftManager_; @@ -489,4 +500,7 @@ private: HighlightManager* highlightManager_; ClientBlockListManager* clientBlockListManager_; + VCardManager* vcardManager_; + CryptoProvider* crypto_; + VCardStorage* vcardStorage_; std::map<std::string, std::string> emoticons_; }; diff --git a/Swift/Controllers/Chat/UnitTest/MUCControllerTest.cpp b/Swift/Controllers/Chat/UnitTest/MUCControllerTest.cpp index 5ca0687..291fb22 100644 --- a/Swift/Controllers/Chat/UnitTest/MUCControllerTest.cpp +++ b/Swift/Controllers/Chat/UnitTest/MUCControllerTest.cpp @@ -80,8 +80,9 @@ public: vcardStorage_ = new VCardMemoryStorage(crypto_.get()); vcardManager_ = new VCardManager(self_, iqRouter_, vcardStorage_); - controller_ = new MUCController (self_, muc_, boost::optional<std::string>(), nick_, stanzaChannel_, iqRouter_, chatWindowFactory_, presenceOracle_, avatarManager_, uiEventStream_, false, timerFactory, eventController_, entityCapsProvider_, NULL, NULL, mucRegistry_, highlightManager_, chatMessageParser_, false, NULL); + controller_ = new MUCController (self_, muc_, boost::optional<std::string>(), nick_, stanzaChannel_, iqRouter_, chatWindowFactory_, presenceOracle_, avatarManager_, uiEventStream_, false, timerFactory, eventController_, entityCapsProvider_, NULL, NULL, mucRegistry_, highlightManager_, chatMessageParser_, false, NULL, vcardManager_); } void tearDown() { + delete controller_; delete vcardManager_; delete vcardStorage_; @@ -89,5 +90,4 @@ public: delete settings_; delete entityCapsProvider_; - delete controller_; delete eventController_; delete presenceOracle_; diff --git a/Swift/Controllers/MainController.cpp b/Swift/Controllers/MainController.cpp index a201994..45a0df7 100644 --- a/Swift/Controllers/MainController.cpp +++ b/Swift/Controllers/MainController.cpp @@ -13,5 +13,5 @@ #include <Swift/Controllers/MainController.h> -#include <stdlib.h> +#include <cstdlib> #include <boost/bind.hpp> @@ -92,5 +92,4 @@ #include <Swift/Controllers/HighlightEditorController.h> #include <Swift/Controllers/BlockListController.h> -#include <Swiften/Crypto/CryptoProvider.h> #include <Swift/Controllers/ContactSuggester.h> #include <Swift/Controllers/ContactsFromXMPPRoster.h> @@ -341,5 +340,5 @@ void MainController::handleConnected() { ftOverview_ = new FileTransferOverview(client_->getFileTransferManager()); fileTransferListController_->setFileTransferOverview(ftOverview_); - rosterController_ = new RosterController(jid_, client_->getRoster(), client_->getAvatarManager(), uiFactory_, client_->getNickManager(), client_->getNickResolver(), client_->getPresenceOracle(), client_->getSubscriptionManager(), eventController_, uiEventStream_, client_->getIQRouter(), settings_, client_->getEntityCapsProvider(), ftOverview_, client_->getClientBlockListManager()); + rosterController_ = new RosterController(jid_, client_->getRoster(), client_->getAvatarManager(), uiFactory_, client_->getNickManager(), client_->getNickResolver(), client_->getPresenceOracle(), client_->getSubscriptionManager(), eventController_, uiEventStream_, client_->getIQRouter(), settings_, client_->getEntityCapsProvider(), ftOverview_, client_->getClientBlockListManager(), client_->getVCardManager()); rosterController_->onChangeStatusRequest.connect(boost::bind(&MainController::handleChangeStatusRequest, this, _1, _2)); rosterController_->onSignOutRequest.connect(boost::bind(&MainController::signOut, this)); @@ -363,7 +362,7 @@ void MainController::handleConnected() { historyController_ = new HistoryController(storages_->getHistoryStorage()); historyViewController_ = new HistoryViewController(jid_, uiEventStream_, historyController_, client_->getNickResolver(), client_->getAvatarManager(), client_->getPresenceOracle(), uiFactory_); - chatsManager_ = new ChatsManager(jid_, client_->getStanzaChannel(), client_->getIQRouter(), eventController_, uiFactory_, uiFactory_, client_->getNickResolver(), client_->getPresenceOracle(), client_->getPresenceSender(), uiEventStream_, uiFactory_, useDelayForLatency_, networkFactories_->getTimerFactory(), client_->getMUCRegistry(), client_->getEntityCapsProvider(), client_->getMUCManager(), uiFactory_, profileSettings_, ftOverview_, client_->getRoster(), !settings_->getSetting(SettingConstants::REMEMBER_RECENT_CHATS), settings_, historyController_, whiteboardManager_, highlightManager_, client_->getClientBlockListManager(), emoticons_, userSearchControllerInvite_); + chatsManager_ = new ChatsManager(jid_, client_->getStanzaChannel(), client_->getIQRouter(), eventController_, uiFactory_, uiFactory_, client_->getNickResolver(), client_->getPresenceOracle(), client_->getPresenceSender(), uiEventStream_, uiFactory_, useDelayForLatency_, networkFactories_->getTimerFactory(), client_->getMUCRegistry(), client_->getEntityCapsProvider(), client_->getMUCManager(), uiFactory_, profileSettings_, ftOverview_, client_->getRoster(), !settings_->getSetting(SettingConstants::REMEMBER_RECENT_CHATS), settings_, historyController_, whiteboardManager_, highlightManager_, client_->getClientBlockListManager(), emoticons_, userSearchControllerInvite_, client_->getVCardManager()); #else - chatsManager_ = new ChatsManager(jid_, client_->getStanzaChannel(), client_->getIQRouter(), eventController_, uiFactory_, uiFactory_, client_->getNickResolver(), client_->getPresenceOracle(), client_->getPresenceSender(), uiEventStream_, uiFactory_, useDelayForLatency_, networkFactories_->getTimerFactory(), client_->getMUCRegistry(), client_->getEntityCapsProvider(), client_->getMUCManager(), uiFactory_, profileSettings_, ftOverview_, client_->getRoster(), !settings_->getSetting(SettingConstants::REMEMBER_RECENT_CHATS), settings_, NULL, whiteboardManager_, highlightManager_, client_->getClientBlockListManager(), emoticons_, userSearchControllerInvite_); + chatsManager_ = new ChatsManager(jid_, client_->getStanzaChannel(), client_->getIQRouter(), eventController_, uiFactory_, uiFactory_, client_->getNickResolver(), client_->getPresenceOracle(), client_->getPresenceSender(), uiEventStream_, uiFactory_, useDelayForLatency_, networkFactories_->getTimerFactory(), client_->getMUCRegistry(), client_->getEntityCapsProvider(), client_->getMUCManager(), uiFactory_, profileSettings_, ftOverview_, client_->getRoster(), !settings_->getSetting(SettingConstants::REMEMBER_RECENT_CHATS), settings_, NULL, whiteboardManager_, highlightManager_, client_->getClientBlockListManager(), emoticons_, userSearchControllerInvite_, client_->getVCardManager()); #endif contactsFromRosterProvider_ = new ContactsFromXMPPRoster(client_->getRoster(), client_->getAvatarManager(), client_->getPresenceOracle()); diff --git a/Swift/Controllers/Roster/ContactRosterItem.cpp b/Swift/Controllers/Roster/ContactRosterItem.cpp index 70b4a1b..6239033 100644 --- a/Swift/Controllers/Roster/ContactRosterItem.cpp +++ b/Swift/Controllers/Roster/ContactRosterItem.cpp @@ -5,6 +5,7 @@ */ -#include "Swift/Controllers/Roster/ContactRosterItem.h" -#include "Swift/Controllers/Roster/GroupRosterItem.h" +#include <Swift/Controllers/Roster/ContactRosterItem.h> + +#include <boost/date_time/posix_time/posix_time.hpp> #include <Swiften/Base/foreach.h> @@ -12,5 +13,5 @@ #include <Swiften/Elements/Idle.h> -#include <boost/date_time/posix_time/posix_time.hpp> +#include <Swift/Controllers/Roster/GroupRosterItem.h> namespace Swift { @@ -53,4 +54,14 @@ std::string ContactRosterItem::getIdleText() const { } +std::string ContactRosterItem::getOfflineSinceText() const { + if (offlinePresence_) { + boost::optional<boost::posix_time::ptime> delay = offlinePresence_->getTimestamp(); + if (offlinePresence_->getType() == Presence::Unavailable && delay) { + return dateTimeToLocalString(*delay); + } + } + return ""; +} + void ContactRosterItem::setAvatarPath(const boost::filesystem::path& path) { avatarPath_ = path; @@ -137,4 +148,5 @@ bool ContactRosterItem::supportsFeature(const Feature feature) const { void ContactRosterItem::setBlockState(BlockState state) { blockState_ = state; + onDataChanged(); } @@ -143,5 +155,12 @@ ContactRosterItem::BlockState ContactRosterItem::blockState() const { } +VCard::ref ContactRosterItem::getVCard() const { + return vcard_; } +void ContactRosterItem::setVCard(VCard::ref vcard) { + vcard_ = vcard; + onDataChanged(); +} +} diff --git a/Swift/Controllers/Roster/ContactRosterItem.h b/Swift/Controllers/Roster/ContactRosterItem.h index 67a9722..d9ca8af 100644 --- a/Swift/Controllers/Roster/ContactRosterItem.h +++ b/Swift/Controllers/Roster/ContactRosterItem.h @@ -7,17 +7,20 @@ #pragma once -#include <string> -#include "Swiften/JID/JID.h" -#include "Swift/Controllers/Roster/RosterItem.h" -#include "Swiften/Elements/StatusShow.h" -#include "Swiften/Elements/Presence.h" - #include <map> #include <set> +#include <string> + #include <boost/bind.hpp> -#include "Swiften/Base/boost_bsignals.h" -#include <boost/shared_ptr.hpp> #include <boost/date_time/posix_time/ptime.hpp> #include <boost/filesystem/path.hpp> +#include <boost/shared_ptr.hpp> + +#include <Swiften/Base/boost_bsignals.h> +#include <Swiften/Elements/Presence.h> +#include <Swiften/Elements/StatusShow.h> +#include <Swiften/Elements/VCard.h> +#include <Swiften/JID/JID.h> + +#include <Swift/Controllers/Roster/RosterItem.h> namespace Swift { @@ -45,4 +48,5 @@ class ContactRosterItem : public RosterItem { std::string getStatusText() const; std::string getIdleText() const; + std::string getOfflineSinceText() const; void setAvatarPath(const boost::filesystem::path& path); const boost::filesystem::path& getAvatarPath() const; @@ -64,4 +68,9 @@ class ContactRosterItem : public RosterItem { BlockState blockState() const; + VCard::ref getVCard() const; + void setVCard(VCard::ref vcard); + + boost::signal<void ()> onVCardRequested; + private: JID jid_; @@ -75,4 +84,5 @@ class ContactRosterItem : public RosterItem { std::set<Feature> features_; BlockState blockState_; + VCard::ref vcard_; }; diff --git a/Swift/Controllers/Roster/Roster.cpp b/Swift/Controllers/Roster/Roster.cpp index 9b45b63..dbb1780 100644 --- a/Swift/Controllers/Roster/Roster.cpp +++ b/Swift/Controllers/Roster/Roster.cpp @@ -5,20 +5,21 @@ */ -#include "Swift/Controllers/Roster/Roster.h" +#include <Swift/Controllers/Roster/Roster.h> -#include "Swiften/Base/foreach.h" #include <string> -#include "Swiften/JID/JID.h" -#include "Swift/Controllers/Roster/ContactRosterItem.h" -#include "Swift/Controllers/Roster/RosterItem.h" -#include "Swift/Controllers/Roster/GroupRosterItem.h" -#include "Swift/Controllers/Roster/RosterItemOperation.h" - -#include <boost/bind.hpp> - #include <iostream> #include <set> #include <deque> +#include <boost/bind.hpp> + +#include <Swiften/Base/foreach.h> +#include <Swiften/JID/JID.h> + +#include <Swift/Controllers/Roster/ContactRosterItem.h> +#include <Swift/Controllers/Roster/RosterItem.h> +#include <Swift/Controllers/Roster/GroupRosterItem.h> +#include <Swift/Controllers/Roster/RosterItemOperation.h> + namespace Swift { @@ -40,4 +41,8 @@ Roster::~Roster() { queue.insert(queue.begin(), group->getChildren().begin(), group->getChildren().end()); } + ContactRosterItem* contact = dynamic_cast<ContactRosterItem*>(item); + if (contact) { + contact->onVCardRequested.disconnect(boost::bind(boost::ref(onVCardUpdateRequested), contact->getJID())); + } delete item; } @@ -109,4 +114,5 @@ void Roster::addContact(const JID& jid, const JID& displayJID, const std::string GroupRosterItem* group(getGroup(groupName)); ContactRosterItem *item = new ContactRosterItem(jid, displayJID, name, group); + item->onVCardRequested.connect(boost::bind(boost::ref(onVCardUpdateRequested), jid)); item->setAvatarPath(avatarPath); if (blockingSupported_) { diff --git a/Swift/Controllers/Roster/Roster.h b/Swift/Controllers/Roster/Roster.h index a4c8b99..821c8f5 100644 --- a/Swift/Controllers/Roster/Roster.h +++ b/Swift/Controllers/Roster/Roster.h @@ -8,14 +8,16 @@ #include <string> -#include "Swiften/JID/JID.h" -#include "Swift/Controllers/Roster/RosterItemOperation.h" -#include "Swift/Controllers/Roster/RosterFilter.h" -#include <Swift/Controllers/Roster/ContactRosterItem.h> - #include <vector> #include <map> -#include "Swiften/Base/boost_bsignals.h" + #include <boost/shared_ptr.hpp> +#include <Swiften/Base/boost_bsignals.h> +#include <Swiften/JID/JID.h> + +#include <Swift/Controllers/Roster/RosterItemOperation.h> +#include <Swift/Controllers/Roster/RosterFilter.h> +#include <Swift/Controllers/Roster/ContactRosterItem.h> + namespace Swift { @@ -44,4 +46,5 @@ class Roster { boost::signal<void (GroupRosterItem*)> onGroupAdded; boost::signal<void (RosterItem*)> onDataChanged; + boost::signal<void (JID&)> onVCardUpdateRequested; GroupRosterItem* getGroup(const std::string& groupName); void setAvailableFeatures(const JID& jid, const std::set<ContactRosterItem::Feature>& features); diff --git a/Swift/Controllers/Roster/RosterController.cpp b/Swift/Controllers/Roster/RosterController.cpp index d277799..fd0dbb8 100644 --- a/Swift/Controllers/Roster/RosterController.cpp +++ b/Swift/Controllers/Roster/RosterController.cpp @@ -5,46 +5,49 @@ */ -#include "Swift/Controllers/Roster/RosterController.h" +#include <Swift/Controllers/Roster/RosterController.h> #include <boost/bind.hpp> #include <boost/smart_ptr/make_shared.hpp> -#include "Swiften/JID/JID.h" -#include "Swiften/Base/foreach.h" -#include "Swift/Controllers/UIInterfaces/MainWindow.h" -#include "Swift/Controllers/UIInterfaces/MainWindowFactory.h" -#include "Swiften/Client/NickResolver.h" -#include "Swiften/Roster/GetRosterRequest.h" -#include "Swiften/Roster/SetRosterRequest.h" -#include "Swift/Controllers/XMPPEvents/SubscriptionRequestEvent.h" -#include "Swift/Controllers/XMPPEvents/ErrorEvent.h" -#include "Swiften/Presence/PresenceOracle.h" -#include "Swiften/Presence/SubscriptionManager.h" -#include "Swift/Controllers/XMPPEvents/EventController.h" -#include "Swiften/Queries/IQRouter.h" -#include "Swift/Controllers/Roster/Roster.h" -#include "Swift/Controllers/Roster/SetPresence.h" -#include "Swift/Controllers/Roster/AppearOffline.h" -#include "Swift/Controllers/Roster/SetAvatar.h" -#include "Swift/Controllers/Roster/SetName.h" -#include "Swift/Controllers/Roster/OfflineRosterFilter.h" -#include "Swift/Controllers/Roster/GroupRosterItem.h" -#include "Swiften/Roster/XMPPRoster.h" -#include "Swiften/Roster/XMPPRosterItem.h" -#include "Swift/Controllers/UIEvents/AddContactUIEvent.h" -#include "Swift/Controllers/UIEvents/RemoveRosterItemUIEvent.h" -#include "Swift/Controllers/UIEvents/RenameRosterItemUIEvent.h" -#include "Swift/Controllers/UIEvents/RenameGroupUIEvent.h" -#include "Swift/Controllers/UIEvents/SendFileUIEvent.h" -#include <Swiften/FileTransfer/FileTransferManager.h> -#include <Swiften/Client/NickManager.h> -#include <Swift/Controllers/Intl.h> +#include <Swiften/Base/foreach.h> #include <Swiften/Base/format.h> #include <Swiften/Base/Path.h> -#include <Swiften/Elements/DiscoInfo.h> +#include <Swiften/Client/ClientBlockListManager.h> +#include <Swiften/Client/NickManager.h> +#include <Swiften/Client/NickResolver.h> #include <Swiften/Disco/EntityCapsManager.h> +#include <Swiften/Elements/DiscoInfo.h> +#include <Swiften/FileTransfer/FileTransferManager.h> +#include <Swiften/JID/JID.h> #include <Swiften/Jingle/JingleSessionManager.h> +#include <Swiften/Presence/PresenceOracle.h> +#include <Swiften/Presence/SubscriptionManager.h> +#include <Swiften/Queries/IQRouter.h> +#include <Swiften/Roster/GetRosterRequest.h> +#include <Swiften/Roster/SetRosterRequest.h> +#include <Swiften/Roster/XMPPRoster.h> +#include <Swiften/Roster/XMPPRosterItem.h> + +#include <Swift/Controllers/Intl.h> +#include <Swift/Controllers/Roster/AppearOffline.h> +#include <Swift/Controllers/Roster/GroupRosterItem.h> +#include <Swift/Controllers/Roster/OfflineRosterFilter.h> +#include <Swift/Controllers/Roster/Roster.h> +#include <Swift/Controllers/Roster/RosterVCardProvider.h> +#include <Swift/Controllers/Roster/SetAvatar.h> +#include <Swift/Controllers/Roster/SetName.h> +#include <Swift/Controllers/Roster/SetPresence.h> +#include <Swift/Controllers/Roster/SetVCard.h> #include <Swift/Controllers/SettingConstants.h> -#include <Swiften/Client/ClientBlockListManager.h> +#include <Swift/Controllers/UIEvents/AddContactUIEvent.h> +#include <Swift/Controllers/UIEvents/RemoveRosterItemUIEvent.h> +#include <Swift/Controllers/UIEvents/RenameGroupUIEvent.h> +#include <Swift/Controllers/UIEvents/RenameRosterItemUIEvent.h> +#include <Swift/Controllers/UIEvents/SendFileUIEvent.h> +#include <Swift/Controllers/UIInterfaces/MainWindow.h> +#include <Swift/Controllers/UIInterfaces/MainWindowFactory.h> +#include <Swift/Controllers/XMPPEvents/ErrorEvent.h> +#include <Swift/Controllers/XMPPEvents/EventController.h> +#include <Swift/Controllers/XMPPEvents/SubscriptionRequestEvent.h> namespace Swift { @@ -53,5 +56,5 @@ namespace Swift { * The controller does not gain ownership of these parameters. */ -RosterController::RosterController(const JID& jid, XMPPRoster* xmppRoster, AvatarManager* avatarManager, MainWindowFactory* mainWindowFactory, NickManager* nickManager, NickResolver* nickResolver, PresenceOracle* presenceOracle, SubscriptionManager* subscriptionManager, EventController* eventController, UIEventStream* uiEventStream, IQRouter* iqRouter, SettingsProvider* settings, EntityCapsProvider* entityCapsManager, FileTransferOverview* fileTransferOverview, ClientBlockListManager* clientBlockListManager) +RosterController::RosterController(const JID& jid, XMPPRoster* xmppRoster, AvatarManager* avatarManager, MainWindowFactory* mainWindowFactory, NickManager* nickManager, NickResolver* nickResolver, PresenceOracle* presenceOracle, SubscriptionManager* subscriptionManager, EventController* eventController, UIEventStream* uiEventStream, IQRouter* iqRouter, SettingsProvider* settings, EntityCapsProvider* entityCapsManager, FileTransferOverview* fileTransferOverview, ClientBlockListManager* clientBlockListManager, VCardManager* vcardManager) : myJID_(jid), xmppRoster_(xmppRoster), mainWindowFactory_(mainWindowFactory), mainWindow_(mainWindowFactory_->createMainWindow(uiEventStream)), roster_(new Roster()), offlineFilter_(new OfflineRosterFilter()), nickManager_(nickManager), nickResolver_(nickResolver), uiEventStream_(uiEventStream), entityCapsManager_(entityCapsManager), ftOverview_(fileTransferOverview), clientBlockListManager_(clientBlockListManager) { assert(fileTransferOverview); @@ -63,4 +66,5 @@ RosterController::RosterController(const JID& jid, XMPPRoster* xmppRoster, Avata expandiness_ = new RosterGroupExpandinessPersister(roster_, settings); mainWindow_->setRosterModel(roster_); + rosterVCardProvider_ = new RosterVCardProvider(roster_, vcardManager, JID::WithoutResource); changeStatusConnection_ = mainWindow_->onChangeStatusRequest.connect(boost::bind(&RosterController::handleChangeStatusRequest, this, _1, _2)); @@ -100,6 +104,6 @@ RosterController::~RosterController() { delete mainWindow_; } + delete rosterVCardProvider_; delete roster_; - } diff --git a/Swift/Controllers/Roster/RosterController.h b/Swift/Controllers/Roster/RosterController.h index 06b551e..5b26fc7 100644 --- a/Swift/Controllers/Roster/RosterController.h +++ b/Swift/Controllers/Roster/RosterController.h @@ -7,18 +7,21 @@ #pragma once -#include "Swiften/JID/JID.h" #include <string> #include <set> -#include "Swiften/Elements/Presence.h" -#include "Swiften/Elements/ErrorPayload.h" -#include "Swiften/Elements/RosterPayload.h" -#include "Swiften/Avatars/AvatarManager.h" -#include "Swift/Controllers/UIEvents/UIEvent.h" -#include "RosterGroupExpandinessPersister.h" -#include "Swift/Controllers/FileTransfer/FileTransferOverview.h" -#include "Swiften/Base/boost_bsignals.h" #include <boost/shared_ptr.hpp> +#include <Swiften/Base/boost_bsignals.h> +#include <Swiften/JID/JID.h> +#include <Swiften/Elements/Presence.h> +#include <Swiften/Elements/ErrorPayload.h> +#include <Swiften/Elements/RosterPayload.h> +#include <Swiften/Avatars/AvatarManager.h> +#include <Swiften/VCards/VCardManager.h> + +#include <Swift/Controllers/UIEvents/UIEvent.h> +#include <Swift/Controllers/FileTransfer/FileTransferOverview.h> +#include <Swift/Controllers/Roster/RosterGroupExpandinessPersister.h> + namespace Swift { class IQRouter; @@ -41,8 +44,9 @@ namespace Swift { class FileTransferManager; class ClientBlockListManager; + class RosterVCardProvider; class RosterController { public: - RosterController(const JID& jid, XMPPRoster* xmppRoster, AvatarManager* avatarManager, MainWindowFactory* mainWindowFactory, NickManager* nickManager, NickResolver* nickResolver, PresenceOracle* presenceOracle, SubscriptionManager* subscriptionManager, EventController* eventController, UIEventStream* uiEventStream, IQRouter* iqRouter_, SettingsProvider* settings, EntityCapsProvider* entityCapsProvider, FileTransferOverview* fileTransferOverview, ClientBlockListManager* clientBlockListManager); + RosterController(const JID& jid, XMPPRoster* xmppRoster, AvatarManager* avatarManager, MainWindowFactory* mainWindowFactory, NickManager* nickManager, NickResolver* nickResolver, PresenceOracle* presenceOracle, SubscriptionManager* subscriptionManager, EventController* eventController, UIEventStream* uiEventStream, IQRouter* iqRouter_, SettingsProvider* settings, EntityCapsProvider* entityCapsProvider, FileTransferOverview* fileTransferOverview, ClientBlockListManager* clientBlockListManager, VCardManager* vcardManager); ~RosterController(); void showRosterWindow(); @@ -103,4 +107,5 @@ namespace Swift { FileTransferOverview* ftOverview_; ClientBlockListManager* clientBlockListManager_; + RosterVCardProvider* rosterVCardProvider_; boost::bsignals::scoped_connection blockingOnStateChangedConnection_; diff --git a/Swift/Controllers/Roster/RosterVCardProvider.cpp b/Swift/Controllers/Roster/RosterVCardProvider.cpp new file mode 100644 index 0000000..26c9a81 --- /dev/null +++ b/Swift/Controllers/Roster/RosterVCardProvider.cpp @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2013 Tobias Markmann + * Licensed under the simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#include <Swift/Controllers/Roster/RosterVCardProvider.h> + +#include <Swiften/VCards/VCardManager.h> + +#include <Swift/Controllers/Roster/Roster.h> +#include <Swift/Controllers/Roster/SetVCard.h> + +namespace Swift { + +RosterVCardProvider::RosterVCardProvider(Roster* roster, VCardManager* vcardManager, JID::CompareType compareType) : roster_(roster), vcardManager_(vcardManager), compareType_(compareType) { + vcardUpdateRequestedConnection = roster_->onVCardUpdateRequested.connect(boost::bind(&RosterVCardProvider::handleVCardUpdateRequested, this, _1)); + vcardChangedConnection = vcardManager_->onVCardChanged.connect(boost::bind(&RosterVCardProvider::handleVCardChanged, this, _1, _2)); +} + +RosterVCardProvider::~RosterVCardProvider() { +} + +void RosterVCardProvider::handleVCardUpdateRequested(const JID& jid) { + VCard::ref vcard = vcardManager_->getVCardAndRequestWhenNeeded(jid); + if (vcard) { + handleVCardChanged(jid, vcard); + } +} + +void RosterVCardProvider::handleVCardChanged(const JID& jid, VCard::ref vcard) { + roster_->applyOnItem(SetVCard(jid, vcard, compareType_), jid); +} + + +} diff --git a/Swift/Controllers/Roster/RosterVCardProvider.h b/Swift/Controllers/Roster/RosterVCardProvider.h new file mode 100644 index 0000000..da41298 --- /dev/null +++ b/Swift/Controllers/Roster/RosterVCardProvider.h @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2013 Tobias Markmann + * Licensed under the simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#pragma once + +#include <boost/signals/connection.hpp> + +#include <Swiften/Base/boost_bsignals.h> +#include <Swiften/Elements/VCard.h> +#include <Swiften/JID/JID.h> + +namespace Swift { + +class Roster; +class VCardManager; + +class RosterVCardProvider { + public: + RosterVCardProvider(Roster* roster, VCardManager* vcardManager, JID::CompareType compareType); + ~RosterVCardProvider(); + + private: + void handleVCardUpdateRequested(const JID& jid); + void handleVCardChanged(const JID& jid, VCard::ref vcard); + + private: + Roster* roster_; + VCardManager* vcardManager_; + JID::CompareType compareType_; + boost::bsignals::scoped_connection vcardUpdateRequestedConnection; + boost::bsignals::scoped_connection vcardChangedConnection; +}; + +} diff --git a/Swift/Controllers/Roster/SetVCard.h b/Swift/Controllers/Roster/SetVCard.h new file mode 100644 index 0000000..4a238ff --- /dev/null +++ b/Swift/Controllers/Roster/SetVCard.h @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2013 Tobias Markmann + * Licensed under the simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#pragma once + +#include <Swiften/Elements/VCard.h> +#include <Swiften/JID/JID.h> + +#include <Swift/Controllers/Roster/RosterItemOperation.h> +#include <Swift/Controllers/Roster/ContactRosterItem.h> + +namespace Swift { + +class RosterItem; + +class SetVCard : public RosterItemOperation { + public: + SetVCard(const JID& jid, VCard::ref vcard, JID::CompareType compareType = JID::WithoutResource) : RosterItemOperation(true, jid), jid_(jid), vcard_(vcard), compareType_(compareType) { + } + + virtual void operator() (RosterItem* item) const { + ContactRosterItem* contact = dynamic_cast<ContactRosterItem*>(item); + if (contact && contact->getJID().equals(jid_, compareType_)) { + contact->setVCard(vcard_); + } + } + + private: + JID jid_; + VCard::ref vcard_; + JID::CompareType compareType_; +}; + +} diff --git a/Swift/Controllers/Roster/UnitTest/RosterControllerTest.cpp b/Swift/Controllers/Roster/UnitTest/RosterControllerTest.cpp index b0034e6..a81d587 100644 --- a/Swift/Controllers/Roster/UnitTest/RosterControllerTest.cpp +++ b/Swift/Controllers/Roster/UnitTest/RosterControllerTest.cpp @@ -9,34 +9,38 @@ #include <cppunit/extensions/TestFactoryRegistry.h> +#include <Swiften/Avatars/NullAvatarManager.h> +#include <Swiften/Base/Algorithm.h> #include <Swiften/Base/foreach.h> -#include "Swift/Controllers/Roster/RosterController.h" -#include "Swift/Controllers/UnitTest/MockMainWindowFactory.h" -// #include "Swiften/Elements/Payload.h" -// #include "Swiften/Elements/RosterItemPayload.h" -// #include "Swiften/Elements/RosterPayload.h" -#include "Swiften/Queries/DummyIQChannel.h" -#include "Swiften/Client/DummyStanzaChannel.h" -#include "Swiften/Queries/IQRouter.h" -#include "Swiften/Roster/XMPPRosterImpl.h" -#include "Swift/Controllers/Roster/Roster.h" -#include "Swift/Controllers/Roster/GroupRosterItem.h" -#include "Swift/Controllers/Roster/ContactRosterItem.h" -#include "Swift/Controllers/Settings/DummySettingsProvider.h" -#include "Swiften/Avatars/NullAvatarManager.h" -#include "Swift/Controllers/XMPPEvents/EventController.h" -#include "Swiften/Presence/PresenceOracle.h" -#include "Swiften/Presence/SubscriptionManager.h" -#include "Swiften/Client/NickResolver.h" -#include "Swift/Controllers/UIEvents/UIEventStream.h" -#include "Swift/Controllers/UIEvents/RenameRosterItemUIEvent.h" -#include "Swiften/MUC/MUCRegistry.h" +#include <Swiften/Client/ClientBlockListManager.h> #include <Swiften/Client/DummyNickManager.h> -#include <Swiften/Disco/EntityCapsManager.h> +#include <Swiften/Client/DummyStanzaChannel.h> +#include <Swiften/Client/NickResolver.h> +#include <Swiften/Crypto/CryptoProvider.h> +#include <Swiften/Crypto/PlatformCryptoProvider.h> #include <Swiften/Disco/CapsProvider.h> -#include <Swiften/Jingle/JingleSessionManager.h> -#include <Swiften/FileTransfer/UnitTest/DummyFileTransferManager.h> -#include <Swiften/Base/Algorithm.h> +#include <Swiften/Disco/EntityCapsManager.h> #include <Swiften/EventLoop/DummyEventLoop.h> -#include <Swiften/Client/ClientBlockListManager.h> +#include <Swiften/FileTransfer/UnitTest/DummyFileTransferManager.h> +#include <Swiften/Jingle/JingleSessionManager.h> +#include <Swiften/MUC/MUCRegistry.h> +#include <Swiften/Presence/PresenceOracle.h> +#include <Swiften/Presence/SubscriptionManager.h> +#include <Swiften/Queries/DummyIQChannel.h> +#include <Swiften/Queries/IQRouter.h> +#include <Swiften/Roster/XMPPRosterImpl.h> +#include <Swiften/VCards/VCardMemoryStorage.h> +// #include <Swiften/Elements/Payload.h> +// #include <Swiften/Elements/RosterItemPayload.h> +// #include <Swiften/Elements/RosterPayload.h> + +#include <Swift/Controllers/Roster/ContactRosterItem.h> +#include <Swift/Controllers/Roster/GroupRosterItem.h> +#include <Swift/Controllers/Roster/Roster.h> +#include <Swift/Controllers/Roster/RosterController.h> +#include <Swift/Controllers/Settings/DummySettingsProvider.h> +#include <Swift/Controllers/UIEvents/RenameRosterItemUIEvent.h> +#include <Swift/Controllers/UIEvents/UIEventStream.h> +#include <Swift/Controllers/UnitTest/MockMainWindowFactory.h> +#include <Swift/Controllers/XMPPEvents/EventController.h> using namespace Swift; @@ -85,5 +89,8 @@ class RosterControllerTest : public CppUnit::TestFixture { ftOverview_ = new FileTransferOverview(ftManager_); clientBlockListManager_ = new ClientBlockListManager(router_); - rosterController_ = new RosterController(jid_, xmppRoster_, avatarManager_, mainWindowFactory_, nickManager_, nickResolver_, presenceOracle_, subscriptionManager_, eventController_, uiEventStream_, router_, settings_, entityCapsManager_, ftOverview_, clientBlockListManager_); + crypto_ = PlatformCryptoProvider::create(); + vcardStorage_ = new VCardMemoryStorage(crypto_); + vcardManager_ = new VCardManager(jid_, router_, vcardStorage_); + rosterController_ = new RosterController(jid_, xmppRoster_, avatarManager_, mainWindowFactory_, nickManager_, nickResolver_, presenceOracle_, subscriptionManager_, eventController_, uiEventStream_, router_, settings_, entityCapsManager_, ftOverview_, clientBlockListManager_, vcardManager_); mainWindow_ = mainWindowFactory_->last; } @@ -91,4 +98,7 @@ class RosterControllerTest : public CppUnit::TestFixture { void tearDown() { delete rosterController_; + delete vcardManager_; + delete vcardStorage_; + delete crypto_; delete clientBlockListManager_; delete ftManager_; @@ -342,4 +352,7 @@ class RosterControllerTest : public CppUnit::TestFixture { FileTransferOverview* ftOverview_; ClientBlockListManager* clientBlockListManager_; + CryptoProvider* crypto_; + VCardStorage* vcardStorage_; + VCardManager* vcardManager_; }; diff --git a/Swift/Controllers/SConscript b/Swift/Controllers/SConscript index ea52084..e0fa508 100644 --- a/Swift/Controllers/SConscript +++ b/Swift/Controllers/SConscript @@ -44,4 +44,5 @@ if env["SCONS_STAGE"] == "build" : "Roster/RosterItem.cpp", "Roster/Roster.cpp", + "Roster/RosterVCardProvider.cpp", "Roster/TableRoster.cpp", "EventWindowController.cpp", diff --git a/Swift/Controllers/UIInterfaces/MainWindow.h b/Swift/Controllers/UIInterfaces/MainWindow.h index 3b10041..c85106f 100644 --- a/Swift/Controllers/UIInterfaces/MainWindow.h +++ b/Swift/Controllers/UIInterfaces/MainWindow.h @@ -8,11 +8,13 @@ #include <string> -#include "Swiften/JID/JID.h" -#include "Swiften/Elements/StatusShow.h" -#include "Swiften/Elements/DiscoItems.h" -#include "Swiften/TLS/Certificate.h" -#include "Swiften/Base/boost_bsignals.h" + #include <boost/shared_ptr.hpp> +#include <Swiften/JID/JID.h> +#include <Swiften/Elements/StatusShow.h> +#include <Swiften/Elements/DiscoItems.h> +#include <Swiften/TLS/Certificate.h> +#include <Swiften/Base/boost_bsignals.h> + namespace Swift { class Roster; diff --git a/Swift/Controllers/UnitTest/MockMainWindow.h b/Swift/Controllers/UnitTest/MockMainWindow.h index 69a4e25..ff3fa4d 100644 --- a/Swift/Controllers/UnitTest/MockMainWindow.h +++ b/Swift/Controllers/UnitTest/MockMainWindow.h @@ -7,5 +7,5 @@ #pragma once -#include "Swift/Controllers/UIInterfaces/MainWindow.h" +#include <Swift/Controllers/UIInterfaces/MainWindow.h> namespace Swift { diff --git a/Swift/QtUI/ChatList/ChatListRecentItem.cpp b/Swift/QtUI/ChatList/ChatListRecentItem.cpp index e9ecec8..5497fdd 100644 --- a/Swift/QtUI/ChatList/ChatListRecentItem.cpp +++ b/Swift/QtUI/ChatList/ChatListRecentItem.cpp @@ -5,8 +5,9 @@ */ -#include <Swift/QtUI/ChatList/ChatListRecentItem.h> +#include <Swiften/Base/Path.h> +#include <Swift/QtUI/ChatList/ChatListRecentItem.h> +#include <Swift/QtUI/QtResourceHelper.h> #include <Swift/QtUI/QtSwiftUtil.h> -#include <Swiften/Base/Path.h> namespace Swift { @@ -34,14 +35,5 @@ QVariant ChatListRecentItem::data(int role) const { QIcon ChatListRecentItem::getPresenceIcon() const { - QString iconString; - switch (chat_.statusType) { - 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"); + return QIcon(statusShowTypeToIconPath(chat_.statusType)); } diff --git a/Swift/QtUI/ChatList/ChatListWhiteboardItem.cpp b/Swift/QtUI/ChatList/ChatListWhiteboardItem.cpp index 6791aa5..05bf6c2 100644 --- a/Swift/QtUI/ChatList/ChatListWhiteboardItem.cpp +++ b/Swift/QtUI/ChatList/ChatListWhiteboardItem.cpp @@ -11,8 +11,9 @@ */ -#include <Swift/QtUI/ChatList/ChatListWhiteboardItem.h> +#include <Swiften/Base/Path.h> +#include <Swift/QtUI/ChatList/ChatListWhiteboardItem.h> #include <Swift/QtUI/QtSwiftUtil.h> -#include <Swiften/Base/Path.h> +#include <Swift/QtUI/QtResourceHelper.h> namespace Swift { @@ -40,14 +41,5 @@ namespace Swift { QIcon ChatListWhiteboardItem::getPresenceIcon() const { - QString iconString; - switch (chat_.statusType) { - 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"); + return QIcon(statusShowTypeToIconPath(chat_.statusType)); } } diff --git a/Swift/QtUI/QtMainWindow.cpp b/Swift/QtUI/QtMainWindow.cpp index 6f87a88..af38d68 100644 --- a/Swift/QtUI/QtMainWindow.cpp +++ b/Swift/QtUI/QtMainWindow.cpp @@ -5,5 +5,5 @@ */ -#include "QtMainWindow.h" +#include <Swift/QtUI/QtMainWindow.h> #include <boost/optional.hpp> @@ -22,9 +22,6 @@ #include <QTabWidget> -#include <Swift/QtUI/QtSwiftUtil.h> -#include <Swift/QtUI/QtTabWidget.h> -#include <Swift/QtUI/QtSettingsProvider.h> -#include <Swift/QtUI/QtLoginWindow.h> -#include <Roster/QtRosterWidget.h> +#include <Swiften/Base/Platform.h> + #include <Swift/Controllers/UIEvents/RequestJoinMUCUIEvent.h> #include <Swift/Controllers/UIEvents/RequestHistoryUIEvent.h> @@ -35,8 +32,12 @@ #include <Swift/Controllers/UIEvents/RequestAdHocUIEvent.h> #include <Swift/Controllers/UIEvents/RequestBlockListDialogUIEvent.h> -#include <Swift/QtUI/QtUISettingConstants.h> #include <Swift/Controllers/SettingConstants.h> -#include <Swiften/Base/Platform.h> +#include <Swift/QtUI/QtSwiftUtil.h> +#include <Swift/QtUI/QtTabWidget.h> +#include <Swift/QtUI/QtSettingsProvider.h> +#include <Swift/QtUI/QtLoginWindow.h> +#include <Swift/QtUI/Roster/QtRosterWidget.h> +#include <Swift/QtUI/QtUISettingConstants.h> #if defined(SWIFTEN_PLATFORM_MACOSX) #include <Swift/QtUI/CocoaUIHelpers.h> diff --git a/Swift/QtUI/QtMainWindow.h b/Swift/QtUI/QtMainWindow.h index 3e6e1d3..627cc17 100644 --- a/Swift/QtUI/QtMainWindow.h +++ b/Swift/QtUI/QtMainWindow.h @@ -7,14 +7,16 @@ #pragma once +#include <vector> + #include <QWidget> #include <QMenu> #include <QList> -#include "Swift/Controllers/UIInterfaces/MainWindow.h" -#include "Swift/QtUI/QtRosterHeader.h" -#include "Swift/QtUI/EventViewer/QtEventWindow.h" -#include "Swift/QtUI/ChatList/QtChatListWindow.h" -#include "Swift/QtUI/QtLoginWindow.h" -#include <vector> +#include <Swift/Controllers/UIInterfaces/MainWindow.h> + +#include <Swift/QtUI/QtRosterHeader.h> +#include <Swift/QtUI/EventViewer/QtEventWindow.h> +#include <Swift/QtUI/ChatList/QtChatListWindow.h> +#include <Swift/QtUI/QtLoginWindow.h> class QComboBox; diff --git a/Swift/QtUI/QtResourceHelper.cpp b/Swift/QtUI/QtResourceHelper.cpp new file mode 100644 index 0000000..f76c438 --- /dev/null +++ b/Swift/QtUI/QtResourceHelper.cpp @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2013 Tobias Markmann + * Licensed under the simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#include <Swift/QtUI/QtResourceHelper.h> + +namespace Swift { + +QString statusShowTypeToIconPath(StatusShow::Type type) { + QString iconString; + switch (type) { + 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 QString(":/icons/%1.png").arg(iconString); +} + +} + diff --git a/Swift/QtUI/QtResourceHelper.h b/Swift/QtUI/QtResourceHelper.h new file mode 100644 index 0000000..034a941 --- /dev/null +++ b/Swift/QtUI/QtResourceHelper.h @@ -0,0 +1,17 @@ +/* + * Copyright (c) 2013 Tobias Markmann + * Licensed under the simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#pragma once + +#include <QString> + +#include <Swiften/Elements/StatusShow.h> + +namespace Swift { + +QString statusShowTypeToIconPath(StatusShow::Type type); + +} diff --git a/Swift/QtUI/Roster/QtTreeWidget.cpp b/Swift/QtUI/Roster/QtTreeWidget.cpp index 99f1f34..f9d3dd0 100644 --- a/Swift/QtUI/Roster/QtTreeWidget.cpp +++ b/Swift/QtUI/Roster/QtTreeWidget.cpp @@ -5,5 +5,5 @@ */ -#include "Roster/QtTreeWidget.h" +#include <Swift/QtUI/Roster/QtTreeWidget.h> #include <boost/smart_ptr/make_shared.hpp> @@ -12,6 +12,11 @@ #include <QUrl> #include <QMimeData> +#include <QObject> +#include <QLabel> +#include <QTimer> +#include <QToolTip> #include <Swiften/Base/Platform.h> + #include <Swift/Controllers/Roster/ContactRosterItem.h> #include <Swift/Controllers/Roster/GroupRosterItem.h> @@ -19,11 +24,13 @@ #include <Swift/Controllers/UIEvents/RequestChatUIEvent.h> #include <Swift/Controllers/UIEvents/SendFileUIEvent.h> -#include <QtSwiftUtil.h> #include <Swift/Controllers/Settings/SettingsProvider.h> + #include <Swift/QtUI/QtUISettingConstants.h> +#include <QtSwiftUtil.h> + namespace Swift { -QtTreeWidget::QtTreeWidget(UIEventStream* eventStream, SettingsProvider* settings, QWidget* parent) : QTreeView(parent) { +QtTreeWidget::QtTreeWidget(UIEventStream* eventStream, SettingsProvider* settings, QWidget* parent) : QTreeView(parent), tooltipShown_(false) { eventStream_ = eventStream; settings_ = settings; @@ -67,4 +74,12 @@ void QtTreeWidget::handleSettingChanged(const std::string& setting) { } +void QtTreeWidget::handleRefreshTooltip() { + if (tooltipShown_) { + QPoint position = QCursor::pos(); + QModelIndex index = indexAt(mapFromGlobal(position)); + QToolTip::showText(position, model_->data(index, Qt::ToolTipRole).toString()); + } +} + void QtTreeWidget::setRosterModel(Roster* roster) { roster_ = roster; @@ -73,4 +88,9 @@ void QtTreeWidget::setRosterModel(Roster* roster) { } +void QtTreeWidget::refreshTooltip() { + // Qt needs some time to emit the events we need to detect tooltip's visibility correctly; 20 ms should be enough + QTimer::singleShot(20, this, SLOT(handleRefreshTooltip())); +} + QtTreeWidgetItem* QtTreeWidget::getRoot() { return treeRoot_; @@ -162,4 +182,21 @@ void QtTreeWidget::dragMoveEvent(QDragMoveEvent* event) { } +bool QtTreeWidget::event(QEvent* event) { + QChildEvent* childEvent = NULL; + if ((childEvent = dynamic_cast<QChildEvent*>(event))) { + if (childEvent->polished()) { + if (dynamic_cast<QLabel*>(childEvent->child())) { + tooltipShown_ = true; + } + } + else if (childEvent->removed()) { + if (childEvent->child()->objectName() == "qtooltip_label") { + tooltipShown_ = false; + } + } + } + return QAbstractItemView::event(event); +} + void QtTreeWidget::handleExpanded(const QModelIndex& index) { GroupRosterItem* item = dynamic_cast<GroupRosterItem*>(static_cast<RosterItem*>(index.internalPointer())); diff --git a/Swift/QtUI/Roster/QtTreeWidget.h b/Swift/QtUI/Roster/QtTreeWidget.h index 7c10a6a..8884a40 100644 --- a/Swift/QtUI/Roster/QtTreeWidget.h +++ b/Swift/QtUI/Roster/QtTreeWidget.h @@ -12,6 +12,7 @@ #include <QDropEvent> #include <QDragMoveEvent> -#include "Swift/QtUI/Roster/RosterModel.h" -#include "Swift/QtUI/Roster/RosterDelegate.h" + +#include <Swift/QtUI/Roster/RosterModel.h> +#include <Swift/QtUI/Roster/RosterDelegate.h> namespace Swift { @@ -28,4 +29,5 @@ class QtTreeWidget : public QTreeView{ void setRosterModel(Roster* roster); Roster* getRoster() {return roster_;} + void refreshTooltip(); boost::signal<void (RosterItem*)> onSomethingSelectedChanged; @@ -37,8 +39,11 @@ class QtTreeWidget : public QTreeView{ void handleClicked(const QModelIndex&); void handleSettingChanged(const std::string& setting); + void handleRefreshTooltip(); + protected: void dragEnterEvent(QDragEnterEvent* event); void dropEvent(QDropEvent* event); void dragMoveEvent(QDragMoveEvent* event); + bool event(QEvent* event); protected: @@ -46,4 +51,5 @@ class QtTreeWidget : public QTreeView{ private: void drawBranches(QPainter*, const QRect&, const QModelIndex&) const; + protected slots: virtual void currentChanged(const QModelIndex& current, const QModelIndex& previous); @@ -57,4 +63,5 @@ class QtTreeWidget : public QTreeView{ QtTreeWidgetItem* treeRoot_; SettingsProvider* settings_; + bool tooltipShown_; }; diff --git a/Swift/QtUI/Roster/RosterModel.cpp b/Swift/QtUI/Roster/RosterModel.cpp index 3791ffa..16c6d7e 100644 --- a/Swift/QtUI/Roster/RosterModel.cpp +++ b/Swift/QtUI/Roster/RosterModel.cpp @@ -5,5 +5,5 @@ */ -#include "RosterModel.h" +#include <Swift/QtUI/Roster/RosterModel.h> #include <boost/bind.hpp> @@ -14,20 +14,24 @@ #include <qdebug.h> -#include "Swiften/Elements/StatusShow.h" -#include "Swift/Controllers/Roster/ContactRosterItem.h" -#include "Swift/Controllers/Roster/GroupRosterItem.h" -#include <Swift/Controllers/StatusUtil.h> +#include <Swiften/Elements/StatusShow.h> #include <Swiften/Base/Path.h> -#include "QtSwiftUtil.h" -#include "Swift/QtUI/Roster/QtTreeWidget.h" +#include <Swift/Controllers/Roster/ContactRosterItem.h> +#include <Swift/Controllers/Roster/GroupRosterItem.h> + +#include <Swift/QtUI/Roster/QtTreeWidget.h> +#include <Swift/QtUI/Roster/RosterTooltip.h> +#include <Swift/QtUI/QtResourceHelper.h> +#include <Swift/QtUI/QtSwiftUtil.h> namespace Swift { -RosterModel::RosterModel(QtTreeWidget* view) : view_(view) { - roster_ = NULL; +RosterModel::RosterModel(QtTreeWidget* view) : roster_(NULL), view_(view) { + const int tooltipAvatarSize = 96; // maximal suggested size according to XEP-0153 + cachedImageScaler_ = new QtScaledAvatarCache(tooltipAvatarSize); } RosterModel::~RosterModel() { + delete cachedImageScaler_; } @@ -64,4 +68,5 @@ void RosterModel::handleDataChanged(RosterItem* item) { if (modelIndex.isValid()) { emit dataChanged(modelIndex, modelIndex); + view_->refreshTooltip(); } } @@ -142,14 +147,5 @@ QString RosterModel::getToolTip(RosterItem* item) const { ContactRosterItem* contact = dynamic_cast<ContactRosterItem*>(item); if (contact) { - if (contact->getDisplayJID().isValid()) { - tip += "\n" + P2QSTRING(contact->getDisplayJID().toBare().toString()); - } - tip += "\n " + P2QSTRING(statusShowTypeToFriendlyName(contact->getStatusShow())); - if (!getStatusText(item).isEmpty()) { - tip += ": " + getStatusText(item); - } - if (!contact->getIdleText().empty()) { - tip += "\n " + tr("Idle since ") + P2QSTRING(contact->getIdleText()); - } + return RosterTooltip::buildDetailedTooltip(contact, cachedImageScaler_); } return tip; @@ -177,14 +173,5 @@ QIcon RosterModel::getPresenceIcon(RosterItem* item) const { } - 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"); + return QIcon(statusShowTypeToIconPath(contact->getStatusShow())); } diff --git a/Swift/QtUI/Roster/RosterModel.h b/Swift/QtUI/Roster/RosterModel.h index cae80c4..5397054 100644 --- a/Swift/QtUI/Roster/RosterModel.h +++ b/Swift/QtUI/Roster/RosterModel.h @@ -7,9 +7,11 @@ #pragma once -#include "Swift/Controllers/Roster/Roster.h" - #include <QAbstractItemModel> #include <QList> +#include <Swift/Controllers/Roster/Roster.h> + +#include <Swift/QtUI/QtScaledAvatarCache.h> + namespace Swift { enum RosterRoles { @@ -57,4 +59,5 @@ namespace Swift { Roster* roster_; QtTreeWidget* view_; + QtScaledAvatarCache* cachedImageScaler_; }; } diff --git a/Swift/QtUI/Roster/RosterTooltip.cpp b/Swift/QtUI/Roster/RosterTooltip.cpp new file mode 100644 index 0000000..edf9c99 --- /dev/null +++ b/Swift/QtUI/Roster/RosterTooltip.cpp @@ -0,0 +1,158 @@ +/* + * Copyright (c) 2013 Tobias Markmann + * Licensed under the simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#include <Swift/QtUI/Roster/RosterTooltip.h> + +#include <QObject> +#include <QString> +#include <QApplication> + +#include <Swiften/Base/Path.h> + +#include <Swift/Controllers/Roster/ContactRosterItem.h> +#include <Swift/Controllers/StatusUtil.h> + +#include <Swift/QtUI/QtSwiftUtil.h> +#include <Swift/QtUI/QtScaledAvatarCache.h> +#include <Swift/QtUI/QtUtilities.h> +#include <Swift/QtUI/QtResourceHelper.h> + +using namespace QtUtilities; + +namespace Swift { + +QString RosterTooltip::buildDetailedTooltip(ContactRosterItem* contact, QtScaledAvatarCache* cachedImageScaler) { + QString tooltipTemplate; + if (QApplication::layoutDirection() == Qt::RightToLeft) { + tooltipTemplate = QString( + "<table style='white-space:pre'>" + "<tr>" + "<td>" + "<img src=\"%1\" />" + "</td>" + "<td>" + "<p style='font-size: 14px'>%3 %2</p>" + "<table><tr><td valign='middle'>%5</td><td valign='middle'>%4</td></tr></table>" + "%6" + "%7" + "%8" + "</td>" + "</tr>" + "</table>"); + } else { + tooltipTemplate = QString( + "<table style='white-space:pre'>" + "<tr>" + "<td>" + "<img src=\"%1\" />" + "</td>" + "<td>" + "<p style='font-size: 14px'>%2 %3</p>" + "<table><tr><td valign='middle'>%4</td><td valign='middle'>%5</td></tr></table>" + "%6" + "%7" + "%8" + "</td>" + "</tr>" + "</table>"); + } + // prepare tooltip + QString fullName = P2QSTRING(contact->getDisplayName()); + + QString vCardSummary; + VCard::ref vCard = contact->getVCard(); + if (vCard) { + fullName = P2QSTRING(vCard->getFullName()).trimmed(); + if (fullName.isEmpty()) { + fullName = (P2QSTRING(vCard->getGivenName()) + " " + P2QSTRING(vCard->getFamilyName())).trimmed(); + } + if (fullName.isEmpty()) { + fullName = P2QSTRING(contact->getDisplayName()); + } + vCardSummary = buildVCardSummary(vCard); + } else { + contact->onVCardRequested(); + } + + QString scaledAvatarPath = cachedImageScaler->getScaledAvatarPath(P2QSTRING(contact->getAvatarPath().empty() ? ":/icons/avatar.png" : pathToString(contact->getAvatarPath()))); + + QString bareJID = contact->getDisplayJID().toString().empty() ? "" : "( " + P2QSTRING(contact->getDisplayJID().toString()) + " )"; + + QString presenceIconTag = QString("<img src='%1' />").arg(statusShowTypeToIconPath(contact->getStatusShow())); + + QString statusMessage = contact->getStatusText().empty() ? QObject::tr("(No message)") : P2QSTRING(contact->getStatusText()); + + QString idleString = P2QSTRING(contact->getIdleText()); + if (!idleString.isEmpty()) { + idleString = QObject::tr("Idle since %1").arg(idleString); + idleString = htmlEscape(idleString) + "<br/>"; + } + + QString lastSeen = P2QSTRING(contact->getOfflineSinceText()); + if (!lastSeen.isEmpty()) { + lastSeen = QObject::tr("Last seen %1").arg(lastSeen); + lastSeen = htmlEscape(lastSeen) + "<br/>"; + } + + return tooltipTemplate.arg(scaledAvatarPath, htmlEscape(fullName), htmlEscape(bareJID), presenceIconTag, htmlEscape(statusMessage), idleString, lastSeen, vCardSummary); +} + +QString RosterTooltip::buildVCardSummary(VCard::ref vcard) { + QString summary; + summary = "<table>"; + + // star | name | content + QString currentBlock; + foreach (const VCard::Telephone& tel, vcard->getTelephones()) { + QString field = buildVCardField(tel.isPreferred, QObject::tr("Telephone"), htmlEscape(P2QSTRING(tel.number))); + if (tel.isPreferred) { + currentBlock = field; + break; + } + currentBlock += field; + } + summary += currentBlock; + + currentBlock = ""; + foreach (const VCard::EMailAddress& mail, vcard->getEMailAddresses()) { + QString field = buildVCardField(mail.isPreferred, QObject::tr("E-Mail"), htmlEscape(P2QSTRING(mail.address))); + if (mail.isPreferred) { + currentBlock = field; + break; + } + currentBlock += field; + } + summary += currentBlock; + + currentBlock = ""; + foreach (const VCard::Organization& org, vcard->getOrganizations()) { + QString field = buildVCardField(false, QObject::tr("Organization"), htmlEscape(P2QSTRING(org.name))); + currentBlock += field; + } + summary += currentBlock; + + currentBlock = ""; + foreach(const std::string& title, vcard->getTitles()) { + QString field = buildVCardField(false, QObject::tr("Title"), htmlEscape(P2QSTRING(title))); + currentBlock += field; + } + summary += currentBlock; + + summary += "</table>"; + return summary; +} + +QString RosterTooltip::buildVCardField(bool preferred, const QString& name, const QString& content) { + QString rowTemplate; + if (QApplication::layoutDirection() == Qt::RightToLeft) { + rowTemplate = QString("<tr><td>%3</td><td valign='middle'><strong>%2</strong></td><td valign='middle'>%1</td></tr>"); + } else { + rowTemplate = QString("<tr><td>%1</td><td valign='middle'><strong>%2</strong></td><td valign='middle'>%3</td></tr>"); + } + return rowTemplate.arg(preferred ? "<img src=':/icons/star-checked.png' />" : "", name, content); +} + +} diff --git a/Swift/QtUI/Roster/RosterTooltip.h b/Swift/QtUI/Roster/RosterTooltip.h new file mode 100644 index 0000000..37f5da2 --- /dev/null +++ b/Swift/QtUI/Roster/RosterTooltip.h @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2013 Tobias Markmann + * Licensed under the simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#pragma once + +#include <QString> + +#include <Swiften/Elements/VCard.h> + +namespace Swift { + +class ContactRosterItem; +class QtScaledAvatarCache; + +class RosterTooltip { + public: + static QString buildDetailedTooltip(ContactRosterItem* contact, QtScaledAvatarCache* cachedImageScaler); + + private: + static QString buildVCardSummary(VCard::ref vcard); + static QString buildVCardField(bool preferred, const QString& name, const QString& content); +}; + +} diff --git a/Swift/QtUI/SConscript b/Swift/QtUI/SConscript index 5cfe81f..2303189 100644 --- a/Swift/QtUI/SConscript +++ b/Swift/QtUI/SConscript @@ -148,4 +148,5 @@ sources = [ "Roster/QtRosterWidget.cpp", "Roster/QtOccupantListWidget.cpp", + "Roster/RosterTooltip.cpp", "EventViewer/EventModel.cpp", "EventViewer/EventDelegate.cpp", @@ -190,5 +191,6 @@ sources = [ "QtAffiliationEditor.cpp", "QtUISettingConstants.cpp", - "QtURLValidator.cpp" + "QtURLValidator.cpp", + "QtResourceHelper.cpp" ] diff --git a/Swift/QtUI/UserSearch/ContactListModel.cpp b/Swift/QtUI/UserSearch/ContactListModel.cpp index 6523a4d..4c4a3ea 100644 --- a/Swift/QtUI/UserSearch/ContactListModel.cpp +++ b/Swift/QtUI/UserSearch/ContactListModel.cpp @@ -7,10 +7,12 @@ #include <Swift/QtUI/UserSearch/ContactListModel.h> -#include <Swift/QtUI/QtSwiftUtil.h> +#include <QMimeData> + #include <Swiften/Base/Path.h> #include <Swiften/Base/foreach.h> #include <Swiften/Elements/StatusShow.h> -#include <QMimeData> +#include <Swift/QtUI/QtSwiftUtil.h> +#include <Swift/QtUI/QtResourceHelper.h> namespace Swift { @@ -159,14 +161,5 @@ QVariant ContactListModel::dataForContact(const Contact& contact, int role) cons QIcon ContactListModel::getPresenceIconForContact(const Contact& contact) const { - QString iconString; - switch (contact.statusType) { - 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"); + return QIcon(statusShowTypeToIconPath(contact.statusType)); } |