diff options
34 files changed, 692 insertions, 251 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 @@ -30,6 +30,7 @@  #include <Swiften/Roster/XMPPRoster.h>  #include <Swiften/Client/ClientBlockListManager.h>  #include <Swiften/Client/StanzaChannel.h> +#include <Swiften/VCards/VCardManager.h>  #include <Swift/Controllers/Chat/ChatController.h>  #include <Swift/Controllers/Chat/ChatControllerBase.h> @@ -123,7 +124,8 @@ ChatsManager::ChatsManager(  		HighlightManager* highlightManager,  		ClientBlockListManager* clientBlockListManager,  		const std::map<std::string, std::string>& emoticons, -		UserSearchController* inviteUserSearchController) : +		UserSearchController* inviteUserSearchController, +		VCardManager* vcardManager) :  			jid_(jid),   			joinMUCWindowFactory_(joinMUCWindowFactory),   			useDelayForLatency_(useDelayForLatency),  @@ -138,7 +140,8 @@ ChatsManager::ChatsManager(  			whiteboardManager_(whiteboardManager),  			highlightManager_(highlightManager),  			clientBlockListManager_(clientBlockListManager), -			inviteUserSearchController_(inviteUserSearchController) { +			inviteUserSearchController_(inviteUserSearchController), +			vcardManager_(vcardManager) {  	timerFactory_ = timerFactory;  	eventController_ = eventController;  	stanzaChannel_ = stanzaChannel; @@ -767,7 +770,7 @@ MUC::ref ChatsManager::handleJoinMUCRequest(const JID &mucJID, const boost::opti  		if (reuseChatwindow) {  			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  			 * controllers' dtor, which are deleted in ChatManager's dtor. The adapters 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 @@ -62,10 +62,11 @@ namespace Swift {  	class DiscoServiceWalker;  	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);  			void setOnline(bool enabled); @@ -180,5 +181,6 @@ namespace Swift {  			AutoAcceptMUCInviteDecider* autoAcceptMUCInviteDecider_;  			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 @@ -33,6 +33,7 @@  #include <Swiften/MUC/MUC.h>  #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>  #include <Swiften/Disco/EntityCapsProvider.h> @@ -70,7 +71,8 @@ MUCController::MUCController (  		HighlightManager* highlightManager,  		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;  	joined_ = false; @@ -81,6 +83,7 @@ MUCController::MUCController (  	xmppRoster_ = roster;  	roster_ = new Roster(false, true); +	rosterVCardProvider_ = new RosterVCardProvider(roster_, vcardManager, JID::WithResource);  	completer_ = new TabComplete();  	chatWindow_->setRosterModel(roster_);  	chatWindow_->setTabComplete(completer_); @@ -130,6 +133,7 @@ MUCController::MUCController (  MUCController::~MUCController() {  	eventStream_->onUIEvent.disconnect(boost::bind(&MUCController::handleUIEvent, this, _1));  	chatWindow_->setRosterModel(NULL); +	delete rosterVCardProvider_;  	delete roster_;  	if (loginCheckTimer_) {  		loginCheckTimer_->stop(); 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 @@ -37,6 +37,8 @@ namespace Swift {  	class XMPPRoster;  	class HighlightManager;  	class UIEvent; +	class VCardManager; +	class RosterVCardProvider;  	enum JoinPart {Join, Part, JoinThenPart, PartThenJoin}; @@ -48,8 +50,8 @@ 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;  			boost::signal<void ()> onImpromptuConfigCompleted; @@ -146,6 +148,7 @@ namespace Swift {  			size_t renameCounter_;  			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 @@ -6,53 +6,58 @@  #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; @@ -109,9 +114,12 @@ public:  		wbManager_ = new WhiteboardManager(whiteboardWindowFactory_, uiEventStream_, nickResolver_, wbSessionManager_);  		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_);  	} @@ -123,6 +131,9 @@ public:  		delete avatarManager_;  		delete manager_;  		delete clientBlockListManager_; +		delete vcardManager_; +		delete vcardStorage_; +		delete crypto_;  		delete ftOverview_;  		delete ftManager_;  		delete wbSessionManager_; @@ -488,6 +499,9 @@ private:  	WhiteboardManager* wbManager_;  	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 @@ -79,16 +79,16 @@ public:  		chatMessageParser_ = new ChatMessageParser(std::map<std::string, std::string>());  		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_;  		delete highlightManager_;  		delete settings_;  		delete entityCapsProvider_; -		delete controller_;  		delete eventController_;  		delete presenceOracle_;  		delete mocks_; 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 @@ -12,7 +12,7 @@  #include <Swift/Controllers/MainController.h> -#include <stdlib.h> +#include <cstdlib>  #include <boost/bind.hpp>  #include <boost/lexical_cast.hpp> @@ -91,7 +91,6 @@  #include <Swift/Controllers/HighlightManager.h>  #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> @@ -340,7 +339,7 @@ void MainController::handleConnected() {  		showProfileController_ = new ShowProfileController(client_->getVCardManager(), uiFactory_, uiEventStream_);  		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));  		rosterController_->getWindow()->onShowCertificateRequest.connect(boost::bind(&MainController::handleShowCertificateRequest, this)); @@ -362,9 +361,9 @@ void MainController::handleConnected() {  #ifdef SWIFT_EXPERIMENTAL_HISTORY  		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());  		contactSuggesterWithoutRoster_->addContactProvider(chatsManager_); 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 @@ -4,14 +4,15 @@   * See Documentation/Licenses/GPLv3.txt for more information.   */ -#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>  #include <Swiften/Base/DateTime.h>  #include <Swiften/Elements/Idle.h> -#include <boost/date_time/posix_time/posix_time.hpp> +#include <Swift/Controllers/Roster/GroupRosterItem.h>  namespace Swift { @@ -52,6 +53,16 @@ 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;  	onDataChanged(); @@ -136,12 +147,20 @@ bool ContactRosterItem::supportsFeature(const Feature feature) const {  void ContactRosterItem::setBlockState(BlockState state) {  	blockState_ = state; +	onDataChanged();  }  ContactRosterItem::BlockState ContactRosterItem::blockState() const {  	return blockState_;  } +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 @@ -6,19 +6,22 @@  #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 { @@ -44,6 +47,7 @@ class ContactRosterItem : public RosterItem {  		StatusShow::Type getSimplifiedStatusShow() const;  		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;  		const JID& getJID() const; @@ -63,6 +67,11 @@ class ContactRosterItem : public RosterItem {  		void setBlockState(BlockState state);  		BlockState blockState() const; +		VCard::ref getVCard() const; +		void setVCard(VCard::ref vcard); + +		boost::signal<void ()> onVCardRequested; +  	private:  		JID jid_;  		JID displayJID_; @@ -74,6 +83,7 @@ class ContactRosterItem : public RosterItem {  		std::vector<std::string> groups_;  		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 @@ -4,22 +4,23 @@   * See Documentation/Licenses/GPLv3.txt for more information.   */ -#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 {  Roster::Roster(bool sortByStatus, bool fullJIDMapping) : blockingSupported_(false) { @@ -39,6 +40,10 @@ Roster::~Roster() {  		if (group) {  			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;  	}  } @@ -107,7 +112,8 @@ void Roster::handleChildrenChanged(GroupRosterItem* item) {  void Roster::addContact(const JID& jid, const JID& displayJID, const std::string& name, const std::string& groupName, const boost::filesystem::path& avatarPath) {  	GroupRosterItem* group(getGroup(groupName)); -	ContactRosterItem *item = new ContactRosterItem(jid, displayJID, name, group);	 +	ContactRosterItem *item = new ContactRosterItem(jid, displayJID, name, group); +	item->onVCardRequested.connect(boost::bind(boost::ref(onVCardUpdateRequested), jid));  	item->setAvatarPath(avatarPath);  	if (blockingSupported_) {  		item->setBlockState(ContactRosterItem::IsUnblocked); 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 @@ -7,16 +7,18 @@  #pragma once  #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 {  class RosterItem; @@ -43,6 +45,7 @@ class Roster {  		boost::signal<void (GroupRosterItem*)> onChildrenChanged;  		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);  		void setBlockedState(const std::vector<JID>& jids, ContactRosterItem::BlockState state); 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 @@ -4,55 +4,58 @@   * See Documentation/Licenses/GPLv3.txt for more information.   */ -#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 {  /**   * 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);  	iqRouter_ = iqRouter; @@ -62,6 +65,7 @@ RosterController::RosterController(const JID& jid, XMPPRoster* xmppRoster, Avata  	settings_ = settings;  	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));  	signOutConnection_ = mainWindow_->onSignOutRequest.connect(boost::bind(boost::ref(onSignOutRequest))); @@ -99,8 +103,8 @@ RosterController::~RosterController() {  	if (mainWindow_->canDelete()) {  		delete mainWindow_;  	} -	delete roster_; -	 +	delete rosterVCardProvider_; +	delete roster_;	  }  void RosterController::setEnabled(bool enabled) { 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 @@ -6,20 +6,23 @@  #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;  	class Roster; @@ -40,10 +43,11 @@ namespace Swift {  	class EntityCapsProvider;  	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();  			MainWindow* getWindow() {return mainWindow_;} @@ -102,6 +106,7 @@ namespace Swift {  			EntityCapsProvider* entityCapsManager_;  			FileTransferOverview* ftOverview_;  			ClientBlockListManager* clientBlockListManager_; +			RosterVCardProvider* rosterVCardProvider_;  			boost::bsignals::scoped_connection blockingOnStateChangedConnection_;  			boost::bsignals::scoped_connection blockingOnItemAddedConnection_; 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 @@ -8,36 +8,40 @@  #include <cppunit/extensions/HelperMacros.h>  #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; @@ -84,12 +88,18 @@ class RosterControllerTest : public CppUnit::TestFixture {  			ftManager_ = new DummyFileTransferManager();  			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;  		}  		void tearDown() {  			delete rosterController_; +			delete vcardManager_; +			delete vcardStorage_; +			delete crypto_;  			delete clientBlockListManager_;  			delete ftManager_;  			delete jingleSessionManager_; @@ -341,6 +351,9 @@ class RosterControllerTest : public CppUnit::TestFixture {  		FileTransferManager* ftManager_;  		FileTransferOverview* ftOverview_;  		ClientBlockListManager* clientBlockListManager_; +		CryptoProvider* crypto_; +		VCardStorage* vcardStorage_; +		VCardManager* vcardManager_;  };  CPPUNIT_TEST_SUITE_REGISTRATION(RosterControllerTest); diff --git a/Swift/Controllers/SConscript b/Swift/Controllers/SConscript index ea52084..e0fa508 100644 --- a/Swift/Controllers/SConscript +++ b/Swift/Controllers/SConscript @@ -43,6 +43,7 @@ if env["SCONS_STAGE"] == "build" :  			"Roster/GroupRosterItem.cpp",  			"Roster/RosterItem.cpp",  			"Roster/Roster.cpp", +			"Roster/RosterVCardProvider.cpp",  			"Roster/TableRoster.cpp",  			"EventWindowController.cpp",  			"SoundEventController.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 @@ -7,13 +7,15 @@  #pragma once  #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 @@ -6,7 +6,7 @@  #pragma once -#include "Swift/Controllers/UIInterfaces/MainWindow.h" +#include <Swift/Controllers/UIInterfaces/MainWindow.h>  namespace Swift {  	class Roster; 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 @@ -4,10 +4,11 @@   * See Documentation/Licenses/GPLv3.txt for more information.   */ -#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 {  ChatListRecentItem::ChatListRecentItem(const ChatListWindow::Chat& chat, ChatListGroupItem* parent) : ChatListItem(parent), chat_(chat) { @@ -33,16 +34,7 @@ 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 @@ -10,10 +10,11 @@   * See the COPYING file for more information.   */ -#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 {  	ChatListWhiteboardItem::ChatListWhiteboardItem(const ChatListWindow::Chat& chat, ChatListGroupItem* parent) : ChatListItem(parent), chat_(chat) { @@ -39,16 +40,7 @@ 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 @@ -4,7 +4,7 @@   * See Documentation/Licenses/GPLv3.txt for more information.   */ -#include "QtMainWindow.h" +#include <Swift/QtUI/QtMainWindow.h>  #include <boost/optional.hpp>  #include <boost/bind.hpp> @@ -21,11 +21,8 @@  #include <QAction>  #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>  #include <Swift/Controllers/UIEvents/RequestAddUserDialogUIEvent.h> @@ -34,10 +31,14 @@  #include <Swift/Controllers/UIEvents/JoinMUCUIEvent.h>  #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>  #elif defined(SWIFTEN_PLATFORM_WINDOWS) 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 @@ -6,16 +6,18 @@  #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;  class QLineEdit; 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 @@ -4,27 +4,34 @@   * See Documentation/Licenses/GPLv3.txt for more information.   */ -#include "Roster/QtTreeWidget.h" +#include <Swift/QtUI/Roster/QtTreeWidget.h>  #include <boost/smart_ptr/make_shared.hpp>  #include <boost/bind.hpp>  #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>  #include <Swift/Controllers/UIEvents/UIEventStream.h>  #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;  	model_ = new RosterModel(this); @@ -66,12 +73,25 @@ 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;  	model_->setRoster(roster);  	expandAll();  } +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_;  } @@ -161,6 +181,23 @@ void QtTreeWidget::dragMoveEvent(QDragMoveEvent* event) {  	QTreeView::dragMoveEvent(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()));  	if (item) { 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 @@ -11,8 +11,9 @@  #include <QDragEnterEvent>  #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 {  class UIEventStream; @@ -27,6 +28,7 @@ class QtTreeWidget : public QTreeView{  		QtTreeWidgetItem* getRoot();  		void setRosterModel(Roster* roster);  		Roster* getRoster() {return roster_;} +		void refreshTooltip();  		boost::signal<void (RosterItem*)> onSomethingSelectedChanged;  	private slots: @@ -36,15 +38,19 @@ class QtTreeWidget : public QTreeView{  		void handleCollapsed(const QModelIndex&);  		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:  		QModelIndexList getSelectedIndexes() const;  	private:  		void drawBranches(QPainter*, const QRect&, const QModelIndex&) const; +  	protected slots:  		virtual void currentChanged(const QModelIndex& current, const QModelIndex& previous);  	protected: @@ -56,6 +62,7 @@ class QtTreeWidget : public QTreeView{  		RosterDelegate* delegate_;  		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 @@ -4,7 +4,7 @@   * See Documentation/Licenses/GPLv3.txt for more information.   */ -#include "RosterModel.h" +#include <Swift/QtUI/Roster/RosterModel.h>  #include <boost/bind.hpp> @@ -13,22 +13,26 @@  #include <QMimeData>  #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_;  }  void RosterModel::setRoster(Roster* roster) { @@ -63,6 +67,7 @@ void RosterModel::handleDataChanged(RosterItem* item) {  	QModelIndex modelIndex = index(item);  	if (modelIndex.isValid()) {  		emit dataChanged(modelIndex, modelIndex); +		view_->refreshTooltip();  	}  } @@ -141,16 +146,7 @@ QString RosterModel::getToolTip(RosterItem* item) const {  	QString tip(P2QSTRING(item->getDisplayName()));  	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;  } @@ -176,16 +172,7 @@ QIcon RosterModel::getPresenceIcon(RosterItem* item) const {  		return QIcon(":/icons/stop.png");  	} -	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 @@ -6,11 +6,13 @@  #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 {  		StatusTextRole = Qt::UserRole, @@ -56,5 +58,6 @@ namespace Swift {  			void reLayout();  			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 @@ -147,6 +147,7 @@ sources = [      "Roster/DelegateCommons.cpp",      "Roster/QtRosterWidget.cpp",      "Roster/QtOccupantListWidget.cpp", +    "Roster/RosterTooltip.cpp",      "EventViewer/EventModel.cpp",      "EventViewer/EventDelegate.cpp",      "EventViewer/TwoLineDelegate.cpp", @@ -163,9 +164,9 @@ sources = [      "MUCSearch/MUCSearchRoomItem.cpp",      "MUCSearch/MUCSearchEmptyItem.cpp",      "MUCSearch/MUCSearchDelegate.cpp", -	"UserSearch/ContactListDelegate.cpp", -	"UserSearch/ContactListModel.cpp", -	"UserSearch/QtContactListWidget.cpp", +    "UserSearch/ContactListDelegate.cpp", +    "UserSearch/ContactListModel.cpp", +    "UserSearch/QtContactListWidget.cpp",      "UserSearch/QtSuggestingJIDInput.cpp",      "UserSearch/QtUserSearchFirstPage.cpp",      "UserSearch/QtUserSearchFirstMultiJIDPage.cpp", @@ -175,11 +176,11 @@ sources = [      "UserSearch/QtUserSearchWindow.cpp",      "UserSearch/UserSearchModel.cpp",      "UserSearch/UserSearchDelegate.cpp", -	"Whiteboard/FreehandLineItem.cpp", -	"Whiteboard/GView.cpp", -	"Whiteboard/TextDialog.cpp", -	"Whiteboard/QtWhiteboardWindow.cpp", -	"Whiteboard/ColorWidget.cpp", +    "Whiteboard/FreehandLineItem.cpp", +    "Whiteboard/GView.cpp", +    "Whiteboard/TextDialog.cpp", +    "Whiteboard/QtWhiteboardWindow.cpp", +    "Whiteboard/ColorWidget.cpp",      "QtSubscriptionRequestWindow.cpp",      "QtRosterHeader.cpp",      "QtWebView.cpp", @@ -189,7 +190,8 @@ sources = [      "QtMUCConfigurationWindow.cpp",      "QtAffiliationEditor.cpp",      "QtUISettingConstants.cpp", -    "QtURLValidator.cpp" +    "QtURLValidator.cpp", +    "QtResourceHelper.cpp"    ]  # QtVCardWidget 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 @@ -6,12 +6,14 @@  #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 { @@ -158,16 +160,7 @@ 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));  }  }  | 
 Swift