diff options
| -rw-r--r-- | Swift/Controllers/MainController.cpp | 3 | ||||
| -rw-r--r-- | Swift/Controllers/Roster/RosterController.cpp | 30 | ||||
| -rw-r--r-- | Swift/Controllers/Roster/RosterController.h | 5 | ||||
| -rw-r--r-- | Swift/Controllers/UIInterfaces/MainWindow.h | 2 | ||||
| -rw-r--r-- | Swift/Controllers/UnitTest/MockMainWindow.h | 1 | ||||
| -rw-r--r-- | Swift/QtUI/QtMainWindow.cpp | 4 | ||||
| -rw-r--r-- | Swift/QtUI/QtMainWindow.h | 1 | ||||
| -rw-r--r-- | Swift/QtUI/QtRosterHeader.cpp | 28 | ||||
| -rw-r--r-- | Swift/QtUI/QtRosterHeader.h | 8 |
9 files changed, 70 insertions, 12 deletions
diff --git a/Swift/Controllers/MainController.cpp b/Swift/Controllers/MainController.cpp index df137f4..f16f8ad 100644 --- a/Swift/Controllers/MainController.cpp +++ b/Swift/Controllers/MainController.cpp @@ -307,71 +307,71 @@ void MainController::handleSettingChanged(const std::string& settingPath) { } } void MainController::resetPendingReconnects() { timeBeforeNextReconnect_ = -1; if (reconnectTimer_) { reconnectTimer_->stop(); reconnectTimer_.reset(); } resetCurrentError(); } void MainController::resetCurrentError() { if (lastDisconnectError_) { lastDisconnectError_->conclude(); lastDisconnectError_ = boost::shared_ptr<ErrorEvent>(); } } void MainController::handleConnected() { boundJID_ = client_->getJID(); resetCurrentError(); resetPendingReconnects(); if (settings_->getSetting(SettingConstants::FORGET_PASSWORDS)) { purgeCachedCredentials(); } bool freshLogin = rosterController_ == NULL; myStatusLooksOnline_ = true; if (freshLogin) { profileController_ = new ProfileController(client_->getVCardManager(), uiFactory_, uiEventStream_); 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(), client_->getVCardManager()); + rosterController_ = new RosterController(boundJID_, 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)); blockListController_ = new BlockListController(client_->getClientBlockListManager(), uiEventStream_, uiFactory_, eventController_); contactEditController_ = new ContactEditController(rosterController_, client_->getVCardManager(), uiFactory_, uiEventStream_); whiteboardManager_ = new WhiteboardManager(uiFactory_, uiEventStream_, client_->getNickResolver(), client_->getWhiteboardSessionManager()); /* Doing this early as an ordering fix. Various things later will * want to have the user's nick available and this means it will * be before they receive stanzas that need it (e.g. bookmarks).*/ client_->getVCardManager()->requestOwnVCard(); contactSuggesterWithoutRoster_ = new ContactSuggester(); contactSuggesterWithRoster_ = new ContactSuggester(); userSearchControllerInvite_ = new UserSearchController(UserSearchController::InviteToChat, jid_, uiEventStream_, client_->getVCardManager(), uiFactory_, client_->getIQRouter(), rosterController_, contactSuggesterWithRoster_, client_->getAvatarManager(), client_->getPresenceOracle()); #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_, 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_, client_->getVCardManager()); #endif contactsFromRosterProvider_ = new ContactsFromXMPPRoster(client_->getRoster(), client_->getAvatarManager(), client_->getPresenceOracle()); contactSuggesterWithoutRoster_->addContactProvider(chatsManager_); contactSuggesterWithRoster_->addContactProvider(chatsManager_); contactSuggesterWithRoster_->addContactProvider(contactsFromRosterProvider_); client_->onMessageReceived.connect(boost::bind(&ChatsManager::handleIncomingMessage, chatsManager_, _1)); chatsManager_->setAvatarManager(client_->getAvatarManager()); eventWindowController_ = new EventWindowController(eventController_, uiFactory_); @@ -379,70 +379,71 @@ void MainController::handleConnected() { DiscoInfo discoInfo; discoInfo.addIdentity(DiscoInfo::Identity(CLIENT_NAME, "client", "pc")); discoInfo.addFeature(DiscoInfo::ChatStatesFeature); discoInfo.addFeature(DiscoInfo::SecurityLabelsFeature); discoInfo.addFeature(DiscoInfo::MessageCorrectionFeature); #ifdef SWIFT_EXPERIMENTAL_FT discoInfo.addFeature(DiscoInfo::JingleFeature); discoInfo.addFeature(DiscoInfo::JingleFTFeature); discoInfo.addFeature(DiscoInfo::JingleTransportsIBBFeature); discoInfo.addFeature(DiscoInfo::JingleTransportsS5BFeature); #endif #ifdef SWIFT_EXPERIMENTAL_WB discoInfo.addFeature(DiscoInfo::WhiteboardFeature); #endif discoInfo.addFeature(DiscoInfo::MessageDeliveryReceiptsFeature); client_->getDiscoManager()->setCapsNode(CLIENT_NODE); client_->getDiscoManager()->setDiscoInfo(discoInfo); userSearchControllerChat_ = new UserSearchController(UserSearchController::StartChat, jid_, uiEventStream_, client_->getVCardManager(), uiFactory_, client_->getIQRouter(), rosterController_, contactSuggesterWithRoster_, client_->getAvatarManager(), client_->getPresenceOracle()); userSearchControllerAdd_ = new UserSearchController(UserSearchController::AddContact, jid_, uiEventStream_, client_->getVCardManager(), uiFactory_, client_->getIQRouter(), rosterController_, contactSuggesterWithoutRoster_, client_->getAvatarManager(), client_->getPresenceOracle()); adHocManager_ = new AdHocManager(JID(boundJID_.getDomain()), uiFactory_, client_->getIQRouter(), uiEventStream_, rosterController_->getWindow()); chatsManager_->onImpromptuMUCServiceDiscovered.connect(boost::bind(&UserSearchController::setCanInitiateImpromptuMUC, userSearchControllerChat_, _1)); } loginWindow_->setIsLoggingIn(false); client_->requestRoster(); GetDiscoInfoRequest::ref discoInfoRequest = GetDiscoInfoRequest::create(JID(boundJID_.getDomain()), client_->getIQRouter()); discoInfoRequest->onResponse.connect(boost::bind(&MainController::handleServerDiscoInfoResponse, this, _1, _2)); discoInfoRequest->send(); client_->getVCardManager()->requestOwnVCard(); + rosterController_->setJID(boundJID_); rosterController_->setEnabled(true); rosterController_->getWindow()->setStreamEncryptionStatus(client_->isStreamEncrypted()); profileController_->setAvailable(true); contactEditController_->setAvailable(true); /* Send presence later to catch all the incoming presences. */ sendPresence(statusTracker_->getNextPresence()); /* Enable chats last of all, so rejoining MUCs has the right sent presence */ assert(chatsManager_); chatsManager_->setOnline(true); } void MainController::handleEventQueueLengthChange(int count) { dock_->setNumberOfPendingMessages(count); } void MainController::reconnectAfterError() { if (reconnectTimer_) { reconnectTimer_->stop(); } performLoginFromCachedCredentials(); } void MainController::handleChangeStatusRequest(StatusShow::Type show, const std::string &statusText) { boost::shared_ptr<Presence> presence(new Presence()); if (show == StatusShow::None) { // Note: this is misleading, None doesn't mean unavailable on the wire. presence->setType(Presence::Unavailable); resetPendingReconnects(); myStatusLooksOnline_ = false; offlineRequested_ = true; } else { offlineRequested_ = false; diff --git a/Swift/Controllers/Roster/RosterController.cpp b/Swift/Controllers/Roster/RosterController.cpp index d2d024c..6bb5119 100644 --- a/Swift/Controllers/Roster/RosterController.cpp +++ b/Swift/Controllers/Roster/RosterController.cpp @@ -26,103 +26,109 @@ #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/GroupRosterItem.h> #include <Swift/Controllers/Roster/OfflineRosterFilter.h> #include <Swift/Controllers/Roster/Roster.h> #include <Swift/Controllers/Roster/RosterVCardProvider.h> #include <Swift/Controllers/Roster/ItemOperations/AppearOffline.h> #include <Swift/Controllers/Roster/ItemOperations/SetAvatar.h> #include <Swift/Controllers/Roster/ItemOperations/SetAvailableFeatures.h> #include <Swift/Controllers/Roster/ItemOperations/SetBlockingState.h> #include <Swift/Controllers/Roster/ItemOperations/SetName.h> #include <Swift/Controllers/Roster/ItemOperations/SetPresence.h> #include <Swift/Controllers/Roster/ItemOperations/SetVCard.h> #include <Swift/Controllers/SettingConstants.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, 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) { + : myJID_(jid), xmppRoster_(xmppRoster), mainWindowFactory_(mainWindowFactory), mainWindow_(mainWindowFactory_->createMainWindow(uiEventStream)), roster_(new Roster()), offlineFilter_(new OfflineRosterFilter()), vcardManager_(vcardManager), avatarManager_(avatarManager), nickManager_(nickManager), nickResolver_(nickResolver), presenceOracle_(presenceOracle), uiEventStream_(uiEventStream), entityCapsManager_(entityCapsManager), ftOverview_(fileTransferOverview), clientBlockListManager_(clientBlockListManager) { assert(fileTransferOverview); iqRouter_ = iqRouter; - presenceOracle_ = presenceOracle; subscriptionManager_ = subscriptionManager; eventController_ = eventController; 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))); xmppRoster_->onJIDAdded.connect(boost::bind(&RosterController::handleOnJIDAdded, this, _1)); xmppRoster_->onJIDUpdated.connect(boost::bind(&RosterController::handleOnJIDUpdated, this, _1, _2, _3)); xmppRoster_->onJIDRemoved.connect(boost::bind(&RosterController::handleOnJIDRemoved, this, _1)); xmppRoster_->onRosterCleared.connect(boost::bind(&RosterController::handleRosterCleared, this)); subscriptionManager_->onPresenceSubscriptionRequest.connect(boost::bind(&RosterController::handleSubscriptionRequest, this, _1, _2)); presenceOracle_->onPresenceChange.connect(boost::bind(&RosterController::handleIncomingPresence, this, _1)); uiEventConnection_ = uiEventStream->onUIEvent.connect(boost::bind(&RosterController::handleUIEvent, this, _1)); - avatarManager_ = avatarManager; + + vcardManager_->onOwnVCardChanged.connect(boost::bind(&RosterController::handleOwnVCardChanged, this, _1)); avatarManager_->onAvatarChanged.connect(boost::bind(&RosterController::handleAvatarChanged, this, _1)); - mainWindow_->setMyAvatarPath(pathToString(avatarManager_->getAvatarPath(myJID_))); + presenceOracle_->onPresenceChange.connect(boost::bind(&RosterController::handlePresenceChanged, this, _1)); + mainWindow_->setMyAvatarPath(pathToString(avatarManager_->getAvatarPath(myJID_.toBare()))); nickManager_->onOwnNickChanged.connect(boost::bind(&MainWindow::setMyNick, mainWindow_, _1)); mainWindow_->setMyJID(jid); mainWindow_->setMyNick(nickManager_->getOwnNick()); entityCapsManager_->onCapsChanged.connect(boost::bind(&RosterController::handleOnCapsChanged, this, _1)); settings_->onSettingChanged.connect(boost::bind(&RosterController::handleSettingChanged, this, _1)); handleShowOfflineToggled(settings_->getSetting(SettingConstants::SHOW_OFFLINE)); + + ownContact_ = boost::make_shared<ContactRosterItem>(myJID_.toBare(), myJID_.toBare(), nickManager_->getOwnNick(), (GroupRosterItem*)0); + ownContact_->setVCard(vcardManager_->getVCard(myJID_.toBare())); + ownContact_->setAvatarPath(pathToString(avatarManager_->getAvatarPath(myJID_.toBare()))); + mainWindow_->setMyContactRosterItem(ownContact_); } RosterController::~RosterController() { settings_->onSettingChanged.disconnect(boost::bind(&RosterController::handleSettingChanged, this, _1)); nickManager_->onOwnNickChanged.disconnect(boost::bind(&MainWindow::setMyNick, mainWindow_, _1)); delete offlineFilter_; delete expandiness_; mainWindow_->setRosterModel(NULL); if (mainWindow_->canDelete()) { delete mainWindow_; } delete rosterVCardProvider_; delete roster_; } void RosterController::setEnabled(bool enabled) { if (!enabled) { roster_->applyOnItems(AppearOffline()); } } void RosterController::handleShowOfflineToggled(bool state) { if (state) { roster_->removeFilter(offlineFilter_); } else { roster_->addFilter(offlineFilter_); } } void RosterController::handleChangeStatusRequest(StatusShow::Type show, const std::string &statusText) { onChangeStatusRequest(show, statusText); } @@ -304,66 +310,80 @@ void RosterController::handleRosterSetError(ErrorPayload::ref error, boost::shar } boost::shared_ptr<ErrorEvent> errorEvent(new ErrorEvent(JID(myJID_.getDomain()), text)); eventController_->handleIncomingEvent(errorEvent); } void RosterController::handleIncomingPresence(Presence::ref newPresence) { if (newPresence->getType() == Presence::Error) { return; } roster_->applyOnItems(SetPresence(newPresence)); } void RosterController::handleSubscriptionRequest(const JID& jid, const std::string& message) { if (xmppRoster_->containsJID(jid) && (xmppRoster_->getSubscriptionStateForJID(jid) == RosterItemPayload::To || xmppRoster_->getSubscriptionStateForJID(jid) == RosterItemPayload::Both)) { subscriptionManager_->confirmSubscription(jid); return; } SubscriptionRequestEvent* eventPointer = new SubscriptionRequestEvent(jid, message); eventPointer->onAccept.connect(boost::bind(&RosterController::handleSubscriptionRequestAccepted, this, eventPointer)); eventPointer->onDecline.connect(boost::bind(&RosterController::handleSubscriptionRequestDeclined, this, eventPointer)); boost::shared_ptr<StanzaEvent> event(eventPointer); eventController_->handleIncomingEvent(event); } void RosterController::handleSubscriptionRequestAccepted(SubscriptionRequestEvent* event) { subscriptionManager_->confirmSubscription(event->getJID()); if (!xmppRoster_->containsJID(event->getJID()) || xmppRoster_->getSubscriptionStateForJID(event->getJID()) == RosterItemPayload::None || xmppRoster_->getSubscriptionStateForJID(event->getJID()) == RosterItemPayload::From) { subscriptionManager_->requestSubscription(event->getJID()); } } void RosterController::handleSubscriptionRequestDeclined(SubscriptionRequestEvent* event) { subscriptionManager_->cancelSubscription(event->getJID()); } +void RosterController::handleOwnVCardChanged(VCard::ref vcard) { + ownContact_->setVCard(vcard); + mainWindow_->setMyContactRosterItem(ownContact_); +} + void RosterController::handleAvatarChanged(const JID& jid) { boost::filesystem::path path = avatarManager_->getAvatarPath(jid); roster_->applyOnItems(SetAvatar(jid, path)); - if (jid.equals(myJID_, JID::WithoutResource)) { + if (jid.equals(myJID_, JID::WithResource)) { mainWindow_->setMyAvatarPath(pathToString(path)); } + ownContact_->setAvatarPath(pathToString(path)); + mainWindow_->setMyContactRosterItem(ownContact_); +} + +void RosterController::handlePresenceChanged(Presence::ref presence) { + if (presence->getFrom().equals(myJID_, JID::WithResource)) { + ownContact_->applyPresence(std::string(), presence); + mainWindow_->setMyContactRosterItem(ownContact_); + } } boost::optional<XMPPRosterItem> RosterController::getItem(const JID& jid) const { return xmppRoster_->getItem(jid); } std::set<std::string> RosterController::getGroups() const { return xmppRoster_->getGroups(); } void RosterController::handleOnCapsChanged(const JID& jid) { DiscoInfo::ref info = entityCapsManager_->getCaps(jid); if (info) { std::set<ContactRosterItem::Feature> features; if (FileTransferManager::isSupportedBy(info)) { features.insert(ContactRosterItem::FileTransferFeature); } if (info->hasFeature(DiscoInfo::WhiteboardFeature)) { features.insert(ContactRosterItem::WhiteboardFeature); } roster_->applyOnItems(SetAvailableFeatures(jid, features)); } } } diff --git a/Swift/Controllers/Roster/RosterController.h b/Swift/Controllers/Roster/RosterController.h index 5b26fc7..d0c7024 100644 --- a/Swift/Controllers/Roster/RosterController.h +++ b/Swift/Controllers/Roster/RosterController.h @@ -18,101 +18,106 @@ #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; class XMPPRoster; class XMPPRosterItem; class MainWindow; class MainWindowFactory; class OfflineRosterFilter; class NickResolver; class PresenceOracle; class SubscriptionManager; class EventController; class SubscriptionRequestEvent; class UIEventStream; class IQRouter; class SettingsProvider; class NickManager; 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, VCardManager* vcardManager); ~RosterController(); void showRosterWindow(); + void setJID(const JID& jid) { myJID_ = jid; } MainWindow* getWindow() {return mainWindow_;} boost::signal<void (StatusShow::Type, const std::string&)> onChangeStatusRequest; boost::signal<void ()> onSignOutRequest; + void handleOwnVCardChanged(VCard::ref vcard); void handleAvatarChanged(const JID& jid); + void handlePresenceChanged(Presence::ref presence); void setEnabled(bool enabled); boost::optional<XMPPRosterItem> getItem(const JID&) const; std::set<std::string> getGroups() const; void setContactGroups(const JID& jid, const std::vector<std::string>& groups); void updateItem(const XMPPRosterItem&); void initBlockingCommand(); private: void handleOnJIDAdded(const JID &jid); void handleRosterCleared(); void handleOnJIDRemoved(const JID &jid); void handleOnJIDUpdated(const JID &jid, const std::string& oldName, const std::vector<std::string>& oldGroups); void handleStartChatRequest(const JID& contact); void handleChangeStatusRequest(StatusShow::Type show, const std::string &statusText); void handleShowOfflineToggled(bool state); void handleIncomingPresence(boost::shared_ptr<Presence> newPresence); void handleSubscriptionRequest(const JID& jid, const std::string& message); void handleSubscriptionRequestAccepted(SubscriptionRequestEvent* event); void handleSubscriptionRequestDeclined(SubscriptionRequestEvent* event); void handleUIEvent(boost::shared_ptr<UIEvent> event); void handleRosterSetError(ErrorPayload::ref error, boost::shared_ptr<RosterPayload> rosterPayload); void applyAllPresenceTo(const JID& jid); void handleEditProfileRequest(); void handleOnCapsChanged(const JID& jid); void handleSettingChanged(const std::string& settingPath); void handleBlockingStateChanged(); void handleBlockingItemAdded(const JID& jid); void handleBlockingItemRemoved(const JID& jid); JID myJID_; XMPPRoster* xmppRoster_; MainWindowFactory* mainWindowFactory_; MainWindow* mainWindow_; Roster* roster_; OfflineRosterFilter* offlineFilter_; + VCardManager* vcardManager_; AvatarManager* avatarManager_; NickManager* nickManager_; NickResolver* nickResolver_; PresenceOracle* presenceOracle_; SubscriptionManager* subscriptionManager_; EventController* eventController_; RosterGroupExpandinessPersister* expandiness_; IQRouter* iqRouter_; SettingsProvider* settings_; UIEventStream* uiEventStream_; EntityCapsProvider* entityCapsManager_; FileTransferOverview* ftOverview_; ClientBlockListManager* clientBlockListManager_; RosterVCardProvider* rosterVCardProvider_; + boost::shared_ptr<ContactRosterItem> ownContact_; boost::bsignals::scoped_connection blockingOnStateChangedConnection_; boost::bsignals::scoped_connection blockingOnItemAddedConnection_; boost::bsignals::scoped_connection blockingOnItemRemovedConnection_; boost::bsignals::scoped_connection changeStatusConnection_; boost::bsignals::scoped_connection signOutConnection_; boost::bsignals::scoped_connection uiEventConnection_; }; } diff --git a/Swift/Controllers/UIInterfaces/MainWindow.h b/Swift/Controllers/UIInterfaces/MainWindow.h index c85106f..82750bf 100644 --- a/Swift/Controllers/UIInterfaces/MainWindow.h +++ b/Swift/Controllers/UIInterfaces/MainWindow.h @@ -1,51 +1,53 @@ /* * Copyright (c) 2010 Kevin Smith * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. */ #pragma once #include <string> #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> +#include <Swift/Controllers/Roster/ContactRosterItem.h> namespace Swift { class Roster; class MainWindow { public: MainWindow(bool candelete = true) : canDelete_(candelete) {} virtual ~MainWindow() {} bool canDelete() const { return canDelete_; } virtual void setMyNick(const std::string& name) = 0; virtual void setMyJID(const JID& jid) = 0; virtual void setMyAvatarPath(const std::string& path) = 0; virtual void setMyStatusText(const std::string& status) = 0; virtual void setMyStatusType(StatusShow::Type type) = 0; + virtual void setMyContactRosterItem(boost::shared_ptr<ContactRosterItem> contact) = 0; /** Must be able to cope with NULL to clear the roster */ virtual void setRosterModel(Roster* roster) = 0; virtual void setConnecting() = 0; virtual void setBlockingCommandAvailable(bool isAvailable) = 0; virtual void setAvailableAdHocCommands(const std::vector<DiscoItems::Item>& commands) = 0; virtual void setStreamEncryptionStatus(bool tlsInPlaceAndValid) = 0; virtual void openCertificateDialog(const std::vector<Certificate::ref>& chain) = 0; boost::signal<void (StatusShow::Type, const std::string&)> onChangeStatusRequest; boost::signal<void ()> onSignOutRequest; boost::signal<void ()> onShowCertificateRequest; private: bool canDelete_; }; } diff --git a/Swift/Controllers/UnitTest/MockMainWindow.h b/Swift/Controllers/UnitTest/MockMainWindow.h index ff3fa4d..b56f352 100644 --- a/Swift/Controllers/UnitTest/MockMainWindow.h +++ b/Swift/Controllers/UnitTest/MockMainWindow.h @@ -1,31 +1,32 @@ /* * Copyright (c) 2010 Kevin Smith * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. */ #pragma once #include <Swift/Controllers/UIInterfaces/MainWindow.h> namespace Swift { class Roster; class MockMainWindow : public MainWindow { public: MockMainWindow() : roster(NULL) {} virtual ~MockMainWindow() {} virtual void setRosterModel(Roster* roster) {this->roster = roster;} virtual void setMyNick(const std::string& /*name*/) {} virtual void setMyJID(const JID& /*jid*/) {} virtual void setMyAvatarPath(const std::string& /*path*/) {} virtual void setMyStatusText(const std::string& /*status*/) {} virtual void setMyStatusType(StatusShow::Type /*type*/) {} + virtual void setMyContactRosterItem(boost::shared_ptr<ContactRosterItem> /*contact*/) {} virtual void setAvailableAdHocCommands(const std::vector<DiscoItems::Item>& /*commands*/) {} virtual void setConnecting() {} virtual void setStreamEncryptionStatus(bool /*tlsInPlaceAndValid*/) {} virtual void openCertificateDialog(const std::vector<Certificate::ref>& /*chain*/) {} virtual void setBlockingCommandAvailable(bool /*isAvailable*/) {} Roster* roster; }; } diff --git a/Swift/QtUI/QtMainWindow.cpp b/Swift/QtUI/QtMainWindow.cpp index 1acc519..31a8234 100644 --- a/Swift/QtUI/QtMainWindow.cpp +++ b/Swift/QtUI/QtMainWindow.cpp @@ -308,70 +308,74 @@ void QtMainWindow::handleSettingChanged(const std::string& settingPath) { void QtMainWindow::handleCompactRosterToggled(bool state) { settings_->storeSetting(QtUISettingConstants::COMPACT_ROSTER, state); compactRosterAction_->setChecked(settings_->getSetting(QtUISettingConstants::COMPACT_ROSTER)); } void QtMainWindow::handleShowOfflineToggled(bool state) { settings_->storeSetting(SettingConstants::SHOW_OFFLINE, state); showOfflineAction_->setChecked(settings_->getSetting(SettingConstants::SHOW_OFFLINE)); } void QtMainWindow::handleShowEmoticonsToggled(bool state) { settings_->storeSetting(QtUISettingConstants::SHOW_EMOTICONS, state); showEmoticonsAction_->setChecked(settings_->getSetting(QtUISettingConstants::SHOW_EMOTICONS)); } void QtMainWindow::setMyNick(const std::string& nick) { meView_->setNick(P2QSTRING(nick)); } void QtMainWindow::setMyJID(const JID& jid) { meView_->setJID(P2QSTRING(jid.toBare().toString())); } void QtMainWindow::setMyAvatarPath(const std::string& path) { meView_->setAvatar(P2QSTRING(path)); } void QtMainWindow::setMyStatusText(const std::string& status) { meView_->setStatusText(P2QSTRING(status)); } void QtMainWindow::setMyStatusType(StatusShow::Type type) { meView_->setStatusType(type); } +void QtMainWindow::setMyContactRosterItem(boost::shared_ptr<ContactRosterItem> contact) { + meView_->setContactRosterItem(contact); +} + void QtMainWindow::setConnecting() { meView_->setConnecting(); } void QtMainWindow::setStreamEncryptionStatus(bool tlsInPlaceAndValid) { meView_->setStreamEncryptionStatus(tlsInPlaceAndValid); } void QtMainWindow::openCertificateDialog(const std::vector<Certificate::ref>& chain) { openCertificateDialog(chain, this); } void QtMainWindow::openCertificateDialog(const std::vector<Certificate::ref>& chain, QWidget* parent) { #if defined(SWIFTEN_PLATFORM_MACOSX) CocoaUIHelpers::displayCertificateChainAsSheet(parent, chain); #elif defined(SWIFTEN_PLATFORM_WINDOWS) WinUIHelpers::displayCertificateChainAsSheet(parent, chain); #else QtCertificateViewerDialog::displayCertificateChainAsSheet(parent, chain); #endif } void QtMainWindow::handleAdHocActionTriggered(bool /*checked*/) { QAction* action = qobject_cast<QAction*>(sender()); assert(action); DiscoItems::Item command = serverAdHocCommands_[serverAdHocCommandActions_.indexOf(action)]; uiEventStream_->send(boost::shared_ptr<UIEvent>(new RequestAdHocUIEvent(command))); } void QtMainWindow::setAvailableAdHocCommands(const std::vector<DiscoItems::Item>& commands) { serverAdHocCommands_ = commands; foreach (QAction* action, serverAdHocCommandActions_) { delete action; } serverAdHocMenu_->clear(); diff --git a/Swift/QtUI/QtMainWindow.h b/Swift/QtUI/QtMainWindow.h index c489a9e..f1f6900 100644 --- a/Swift/QtUI/QtMainWindow.h +++ b/Swift/QtUI/QtMainWindow.h @@ -15,70 +15,71 @@ #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; class QPushButton; class QToolBar; class QAction; class QMenu; class QTabWidget; namespace Swift { class QtRosterWidget; class TreeWidget; class UIEventStream; class QtTabWidget; class SettingsProvider; class QtUIPreferences; class StatusCache; class QtMainWindow : public QWidget, public MainWindow { Q_OBJECT public: QtMainWindow(SettingsProvider*, UIEventStream* eventStream, QtLoginWindow::QtMenus loginMenus, StatusCache* statusCache, bool emoticonsExist); virtual ~QtMainWindow(); std::vector<QMenu*> getMenus() {return menus_;} void setMyNick(const std::string& name); void setMyJID(const JID& jid); void setMyAvatarPath(const std::string& path); void setMyStatusText(const std::string& status); void setMyStatusType(StatusShow::Type type); + void setMyContactRosterItem(boost::shared_ptr<ContactRosterItem> contact); void setConnecting(); void setStreamEncryptionStatus(bool tlsInPlaceAndValid); void openCertificateDialog(const std::vector<Certificate::ref>& chain); static void openCertificateDialog(const std::vector<Certificate::ref>& chain, QWidget* parent); QtEventWindow* getEventWindow(); QtChatListWindow* getChatListWindow(); void setRosterModel(Roster* roster); void setAvailableAdHocCommands(const std::vector<DiscoItems::Item>& commands); void setBlockingCommandAvailable(bool isAvailable); private slots: void handleStatusChanged(StatusShow::Type showType, const QString &statusMessage); void handleSettingChanged(const std::string& settingPath); void handleCompactRosterToggled(bool); void handleShowOfflineToggled(bool); void handleShowEmoticonsToggled(bool); void handleJoinMUCAction(); void handleViewLogsAction(); void handleSignOutAction(); void handleEditProfileAction(); void handleAddUserActionTriggered(bool checked); void handleChatUserActionTriggered(bool checked); void handleAdHocActionTriggered(bool checked); void handleEventCountUpdated(int count); void handleChatCountUpdated(int count); void handleEditProfileRequest(); void handleTabChanged(int index); void handleToggleRequestDeliveryReceipts(bool enabled); void handleShowCertificateInfo(); void handleEditBlockingList(); private: SettingsProvider* settings_; QtLoginWindow::QtMenus loginMenus_; std::vector<QMenu*> menus_; QtRosterWidget* treeWidget_; diff --git a/Swift/QtUI/QtRosterHeader.cpp b/Swift/QtUI/QtRosterHeader.cpp index 2c8f244..69a0ef6 100644 --- a/Swift/QtUI/QtRosterHeader.cpp +++ b/Swift/QtUI/QtRosterHeader.cpp @@ -1,116 +1,134 @@ /* * Copyright (c) 2010-2014 Kevin Smith * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. */ #include "QtRosterHeader.h" -#include <QHBoxLayout> -#include <QVBoxLayout> +#include <QBitmap> +#include <qdebug.h> #include <QFileInfo> +#include <QHBoxLayout> +#include <QHelpEvent> #include <QIcon> -#include <QSizePolicy> -#include <qdebug.h> #include <QMouseEvent> #include <QPainter> -#include <QBitmap> +#include <QSizePolicy> +#include <QToolTip> +#include <QVBoxLayout> #include "QtStatusWidget.h" #include <Swift/QtUI/QtElidingLabel.h> #include <Swift/QtUI/QtClickableLabel.h> #include <Swift/QtUI/QtNameWidget.h> +#include <Swift/QtUI/Roster/RosterTooltip.h> #include "QtScaledAvatarCache.h" namespace Swift { QtRosterHeader::QtRosterHeader(SettingsProvider* settings, StatusCache* statusCache, QWidget* parent) : QWidget(parent), statusEdit_(NULL) { QHBoxLayout* topLayout = new QHBoxLayout(); topLayout->setSpacing(3); topLayout->setContentsMargins(4,4,4,4); setLayout(topLayout); setMinimumHeight(50); setMaximumHeight(50); avatarLabel_ = new QtClickableLabel(this); avatarLabel_->setMinimumSize(avatarSize_, avatarSize_); avatarLabel_->setMaximumSize(avatarSize_, avatarSize_); avatarLabel_->setAlignment(Qt::AlignCenter); setAvatar(":/icons/avatar.png"); avatarLabel_->setScaledContents(false); topLayout->addWidget(avatarLabel_); connect(avatarLabel_, SIGNAL(clicked()), this, SIGNAL(onEditProfileRequest())); QVBoxLayout* rightLayout = new QVBoxLayout(); rightLayout->setSpacing(4); rightLayout->setContentsMargins(4,0,0,0); topLayout->addLayout(rightLayout); QHBoxLayout* nameAndSecurityLayout = new QHBoxLayout(); nameAndSecurityLayout->setContentsMargins(4,0,0,0); nameWidget_ = new QtNameWidget(settings, this); connect(nameWidget_, SIGNAL(onChangeNickRequest()), this, SIGNAL(onEditProfileRequest())); nameAndSecurityLayout->addWidget(nameWidget_); securityInfoButton_ = new QToolButton(this); securityInfoButton_->setStyleSheet("QToolButton { border: none; } QToolButton:hover { border: 1px solid #bebebe; } QToolButton:pressed { border: 1px solid #757575; background-color: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, stop: 0 #777777, stop: 1 #d4d4d4);}"); //securityInfoButton_->setAutoRaise(true); securityInfoButton_->setIcon(QIcon(":/icons/lock.png")); securityInfoButton_->setToolTip(tr("Connection is secured")); connect(securityInfoButton_, SIGNAL(clicked()), this, SIGNAL(onShowCertificateInfo())); nameAndSecurityLayout->addWidget(securityInfoButton_); rightLayout->addLayout(nameAndSecurityLayout); statusWidget_ = new QtStatusWidget(statusCache, this); connect(statusWidget_, SIGNAL(onChangeStatusRequest(StatusShow::Type, const QString&)), this, SLOT(handleChangeStatusRequest(StatusShow::Type, const QString&))); rightLayout->addWidget(statusWidget_); show(); } void QtRosterHeader::handleChangeStatusRequest(StatusShow::Type type, const QString& text) { emit onChangeStatusRequest(type, text); } void QtRosterHeader::setStatusText(const QString& statusMessage) { statusWidget_->setStatusText(statusMessage); } void QtRosterHeader::setStatusType(StatusShow::Type type) { statusWidget_->setStatusType(type); } void QtRosterHeader::setConnecting() { statusWidget_->setConnecting(); } void QtRosterHeader::setStreamEncryptionStatus(bool tlsInPlace) { securityInfoButton_->setVisible(tlsInPlace); } +bool QtRosterHeader::event(QEvent* event) { + if (event->type() == QEvent::ToolTip) { + QHelpEvent *helpEvent = static_cast<QHelpEvent *>(event); + QtScaledAvatarCache scaledAvatarCache(avatarSize_); + QString text = RosterTooltip::buildDetailedTooltip(contact_.get(), &scaledAvatarCache); + QToolTip::showText(helpEvent->globalPos(), text); + return true; + } + return QWidget::event(event); +} + void QtRosterHeader::setAvatar(const QString& path) { QString scaledAvatarPath = QtScaledAvatarCache(avatarSize_).getScaledAvatarPath(path); QPixmap avatar; if (QFileInfo(scaledAvatarPath).exists()) { avatar.load(scaledAvatarPath); } else { avatar = QPixmap(":/icons/avatar.png").scaled(avatarSize_, avatarSize_, Qt::KeepAspectRatio, Qt::SmoothTransformation); } avatarLabel_->setPixmap(avatar); } void QtRosterHeader::setNick(const QString& nick) { nameWidget_->setNick(nick); } +void QtRosterHeader::setContactRosterItem(boost::shared_ptr<ContactRosterItem> contact) { + contact_ = contact; +} + void QtRosterHeader::setJID(const QString& jid) { nameWidget_->setJID(jid); } const int QtRosterHeader::avatarSize_ = 40; } diff --git a/Swift/QtUI/QtRosterHeader.h b/Swift/QtUI/QtRosterHeader.h index ad19178..eafbc02 100644 --- a/Swift/QtUI/QtRosterHeader.h +++ b/Swift/QtUI/QtRosterHeader.h @@ -1,58 +1,64 @@ /* * Copyright (c) 2010 Kevin Smith * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. */ #pragma once #include <QWidget> #include <QLabel> #include <QPixmap> #include <QSize> #include <QToolButton> #include <string> -#include "Swiften/Elements/StatusShow.h" +#include <Swiften/Elements/StatusShow.h> +#include <Swiften/Elements/VCard.h> +#include <Swift/Controllers/Roster/ContactRosterItem.h> #include "QtTextEdit.h" class QHBoxLayout; namespace Swift { class QtClickableLabel; class QtStatusWidget; class QtNameWidget; class SettingsProvider; class StatusCache; class QtRosterHeader : public QWidget { Q_OBJECT public: QtRosterHeader(SettingsProvider* settings, StatusCache* statusCache, QWidget* parent = NULL); void setAvatar(const QString& path); void setJID(const QString& jid); void setNick(const QString& nick); + void setContactRosterItem(boost::shared_ptr<ContactRosterItem> contact); void setStatusText(const QString& statusMessage); void setStatusType(StatusShow::Type type); void setConnecting(); void setStreamEncryptionStatus(bool tlsInPlace); + private: + bool event(QEvent* event); signals: void onChangeStatusRequest(StatusShow::Type showType, const QString &statusMessage); void onEditProfileRequest(); void onShowCertificateInfo(); private slots: void handleChangeStatusRequest(StatusShow::Type type, const QString &statusMessage); private: QString name_; QtClickableLabel* avatarLabel_; QtNameWidget* nameWidget_; QtTextEdit* statusEdit_; QtStatusWidget* statusWidget_; QToolButton* securityInfoButton_; static const int avatarSize_; + boost::shared_ptr<ContactRosterItem> contact_; }; } |
Swift