diff options
Diffstat (limited to 'Swift/Controllers')
28 files changed, 671 insertions, 256 deletions
diff --git a/Swift/Controllers/Chat/ChatController.cpp b/Swift/Controllers/Chat/ChatController.cpp index 9a56300..ea0e8ea 100644 --- a/Swift/Controllers/Chat/ChatController.cpp +++ b/Swift/Controllers/Chat/ChatController.cpp @@ -1,121 +1,122 @@ /* - * Copyright (c) 2010 Kevin Smith + * Copyright (c) 2010-2012 Kevin Smith * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. */ #include "Swift/Controllers/Chat/ChatController.h" #include <boost/bind.hpp> #include <stdio.h> #include <Swift/Controllers/Intl.h> #include <Swiften/Base/format.h> #include <Swiften/Base/Algorithm.h> #include <Swiften/Avatars/AvatarManager.h> #include <Swiften/Chat/ChatStateNotifier.h> #include <Swiften/Chat/ChatStateTracker.h> #include <Swiften/Client/StanzaChannel.h> #include <Swift/Controllers/UIInterfaces/ChatWindowFactory.h> #include <Swiften/Client/NickResolver.h> #include <Swift/Controllers/XMPPEvents/EventController.h> #include <Swift/Controllers/FileTransfer/FileTransferController.h> #include <Swift/Controllers/StatusUtil.h> #include <Swiften/Disco/EntityCapsProvider.h> #include <Swiften/Base/foreach.h> #include <Swift/Controllers/UIEvents/UIEventStream.h> #include <Swift/Controllers/UIEvents/SendFileUIEvent.h> #include <Swiften/Elements/DeliveryReceipt.h> #include <Swiften/Elements/DeliveryReceiptRequest.h> -#include <Swift/Controllers/UIEvents/ToggleRequestDeliveryReceiptsUIEvent.h> +#include <Swift/Controllers/SettingConstants.h> #include <Swiften/Base/Log.h> namespace Swift { /** * The controller does not gain ownership of the stanzaChannel, nor the factory. */ -ChatController::ChatController(const JID& self, StanzaChannel* stanzaChannel, IQRouter* iqRouter, ChatWindowFactory* chatWindowFactory, const JID &contact, NickResolver* nickResolver, PresenceOracle* presenceOracle, AvatarManager* avatarManager, bool isInMUC, bool useDelayForLatency, UIEventStream* eventStream, EventController* eventController, TimerFactory* timerFactory, EntityCapsProvider* entityCapsProvider, bool userWantsReceipts) - : ChatControllerBase(self, stanzaChannel, iqRouter, chatWindowFactory, contact, presenceOracle, avatarManager, useDelayForLatency, eventStream, eventController, timerFactory, entityCapsProvider), eventStream_(eventStream), userWantsReceipts_(userWantsReceipts) { +ChatController::ChatController(const JID& self, StanzaChannel* stanzaChannel, IQRouter* iqRouter, ChatWindowFactory* chatWindowFactory, const JID &contact, NickResolver* nickResolver, PresenceOracle* presenceOracle, AvatarManager* avatarManager, bool isInMUC, bool useDelayForLatency, UIEventStream* eventStream, EventController* eventController, TimerFactory* timerFactory, EntityCapsProvider* entityCapsProvider, bool userWantsReceipts, SettingsProvider* settings) + : ChatControllerBase(self, stanzaChannel, iqRouter, chatWindowFactory, contact, presenceOracle, avatarManager, useDelayForLatency, eventStream, eventController, timerFactory, entityCapsProvider), eventStream_(eventStream), userWantsReceipts_(userWantsReceipts), settings_(settings) { isInMUC_ = isInMUC; lastWasPresence_ = false; chatStateNotifier_ = new ChatStateNotifier(stanzaChannel, contact, entityCapsProvider); chatStateTracker_ = new ChatStateTracker(); nickResolver_ = nickResolver; presenceOracle_->onPresenceChange.connect(boost::bind(&ChatController::handlePresenceChange, this, _1)); chatStateTracker_->onChatStateChange.connect(boost::bind(&ChatWindow::setContactChatState, chatWindow_, _1)); stanzaChannel_->onStanzaAcked.connect(boost::bind(&ChatController::handleStanzaAcked, this, _1)); nickResolver_->onNickChanged.connect(boost::bind(&ChatController::handleContactNickChanged, this, _1, _2)); std::string nick = nickResolver_->jidToNick(toJID_); chatWindow_->setName(nick); std::string startMessage; Presence::ref theirPresence; if (isInMUC) { startMessage = str(format(QT_TRANSLATE_NOOP("", "Starting chat with %1% in chatroom %2%")) % nick % contact.toBare().toString()); theirPresence = presenceOracle->getLastPresence(contact); } else { startMessage = str(format(QT_TRANSLATE_NOOP("", "Starting chat with %1% - %2%")) % nick % contact.toBare().toString()); theirPresence = contact.isBare() ? presenceOracle->getHighestPriorityPresence(contact.toBare()) : presenceOracle->getLastPresence(contact); } startMessage += ": " + statusShowTypeToFriendlyName(theirPresence ? theirPresence->getShow() : StatusShow::None); if (theirPresence && !theirPresence->getStatus().empty()) { startMessage += " (" + theirPresence->getStatus() + ")"; } lastShownStatus_ = theirPresence ? theirPresence->getShow() : StatusShow::None; chatStateNotifier_->setContactIsOnline(theirPresence && theirPresence->getType() == Presence::Available); startMessage += "."; chatWindow_->addSystemMessage(startMessage); chatWindow_->onUserTyping.connect(boost::bind(&ChatStateNotifier::setUserIsTyping, chatStateNotifier_)); chatWindow_->onUserCancelsTyping.connect(boost::bind(&ChatStateNotifier::userCancelledNewMessage, chatStateNotifier_)); chatWindow_->onFileTransferStart.connect(boost::bind(&ChatController::handleFileTransferStart, this, _1, _2)); chatWindow_->onFileTransferAccept.connect(boost::bind(&ChatController::handleFileTransferAccept, this, _1, _2)); chatWindow_->onFileTransferCancel.connect(boost::bind(&ChatController::handleFileTransferCancel, this, _1)); chatWindow_->onSendFileRequest.connect(boost::bind(&ChatController::handleSendFileRequest, this, _1)); handleBareJIDCapsChanged(toJID_); - eventStream_->onUIEvent.connect(boost::bind(&ChatController::handleUIEvent, this, _1)); + + settings_->onSettingChanged.connect(boost::bind(&ChatController::handleSettingChanged, this, _1)); } void ChatController::handleContactNickChanged(const JID& jid, const std::string& /*oldNick*/) { if (jid.toBare() == toJID_.toBare()) { chatWindow_->setName(nickResolver_->jidToNick(jid)); } } ChatController::~ChatController() { - eventStream_->onUIEvent.disconnect(boost::bind(&ChatController::handleUIEvent, this, _1)); + settings_->onSettingChanged.disconnect(boost::bind(&ChatController::handleSettingChanged, this, _1)); nickResolver_->onNickChanged.disconnect(boost::bind(&ChatController::handleContactNickChanged, this, _1, _2)); delete chatStateNotifier_; delete chatStateTracker_; } void ChatController::handleBareJIDCapsChanged(const JID& /*jid*/) { DiscoInfo::ref disco = entityCapsProvider_->getCaps(toJID_); if (disco) { if (disco->hasFeature(DiscoInfo::MessageCorrectionFeature)) { chatWindow_->setCorrectionEnabled(ChatWindow::Yes); } else { chatWindow_->setCorrectionEnabled(ChatWindow::No); } if (disco->hasFeature(DiscoInfo::MessageDeliveryReceiptsFeature)) { contactSupportsReceipts_ = ChatWindow::Yes; } else { contactSupportsReceipts_ = ChatWindow::No; } } else { SWIFT_LOG(debug) << "No disco info :(" << std::endl; chatWindow_->setCorrectionEnabled(ChatWindow::Maybe); contactSupportsReceipts_ = ChatWindow::Maybe; } checkForDisplayingDisplayReceiptsAlert(); } void ChatController::setToJID(const JID& jid) { chatStateNotifier_->setContact(jid); ChatControllerBase::setToJID(jid); Presence::ref presence; if (isInMUC_) { presence = presenceOracle_->getLastPresence(jid); } else { presence = jid.isBare() ? presenceOracle_->getHighestPriorityPresence(jid.toBare()) : presenceOracle_->getLastPresence(jid); } @@ -142,73 +143,73 @@ void ChatController::preHandleIncomingMessage(boost::shared_ptr<MessageEvent> me chatStateTracker_->handleMessageReceived(message); chatStateNotifier_->receivedMessageFromContact(message->getPayload<ChatState>()); if (boost::shared_ptr<DeliveryReceipt> receipt = message->getPayload<DeliveryReceipt>()) { SWIFT_LOG(debug) << "received receipt for id: " << receipt->getReceivedID() << std::endl; if (requestedReceipts_.find(receipt->getReceivedID()) != requestedReceipts_.end()) { chatWindow_->setMessageReceiptState(requestedReceipts_[receipt->getReceivedID()], ChatWindow::ReceiptReceived); requestedReceipts_.erase(receipt->getReceivedID()); } } else if (message->getPayload<DeliveryReceiptRequest>()) { if (receivingPresenceFromUs_) { boost::shared_ptr<Message> receiptMessage = boost::make_shared<Message>(); receiptMessage->setTo(toJID_); receiptMessage->addPayload(boost::make_shared<DeliveryReceipt>(message->getID())); stanzaChannel_->sendMessage(receiptMessage); } } } void ChatController::postHandleIncomingMessage(boost::shared_ptr<MessageEvent> messageEvent) { eventController_->handleIncomingEvent(messageEvent); } void ChatController::preSendMessageRequest(boost::shared_ptr<Message> message) { chatStateNotifier_->addChatStateRequest(message); if (userWantsReceipts_ && (contactSupportsReceipts_ != ChatWindow::No) && message) { message->addPayload(boost::make_shared<DeliveryReceiptRequest>()); } } void ChatController::setContactIsReceivingPresence(bool isReceivingPresence) { receivingPresenceFromUs_ = isReceivingPresence; } -void ChatController::handleUIEvent(boost::shared_ptr<UIEvent> event) { - if (boost::shared_ptr<ToggleRequestDeliveryReceiptsUIEvent> toggleAllowReceipts = boost::dynamic_pointer_cast<ToggleRequestDeliveryReceiptsUIEvent>(event)) { - userWantsReceipts_ = toggleAllowReceipts->getEnabled(); +void ChatController::handleSettingChanged(const std::string& settingPath) { + if (settingPath == SettingConstants::REQUEST_DELIVERYRECEIPTS.getKey()) { + userWantsReceipts_ = settings_->getSetting(SettingConstants::REQUEST_DELIVERYRECEIPTS); checkForDisplayingDisplayReceiptsAlert(); } } void ChatController::checkForDisplayingDisplayReceiptsAlert() { if (userWantsReceipts_ && (contactSupportsReceipts_ == ChatWindow::No)) { chatWindow_->setAlert("This chat doesn't support delivery receipts."); } else if (userWantsReceipts_ && (contactSupportsReceipts_ == ChatWindow::Maybe)) { chatWindow_->setAlert("This chat may not support delivery receipts. You might not receive delivery receipts for the messages you sent."); } else { chatWindow_->cancelAlert(); } } void ChatController::postSendMessage(const std::string& body, boost::shared_ptr<Stanza> sentStanza) { boost::shared_ptr<Replace> replace = sentStanza->getPayload<Replace>(); if (replace) { eraseIf(unackedStanzas_, PairSecondEquals<boost::shared_ptr<Stanza>, std::string>(myLastMessageUIID_)); chatWindow_->replaceMessage(body, myLastMessageUIID_, boost::posix_time::microsec_clock::universal_time()); } else { myLastMessageUIID_ = addMessage(body, QT_TRANSLATE_NOOP("", "me"), true, labelsEnabled_ ? chatWindow_->getSelectedSecurityLabel().getLabel() : boost::shared_ptr<SecurityLabel>(), std::string(avatarManager_->getAvatarPath(selfJID_).string()), boost::posix_time::microsec_clock::universal_time()); } if (stanzaChannel_->getStreamManagementEnabled() && !myLastMessageUIID_.empty() ) { chatWindow_->setAckState(myLastMessageUIID_, ChatWindow::Pending); unackedStanzas_[sentStanza] = myLastMessageUIID_; } if (sentStanza->getPayload<DeliveryReceiptRequest>()) { requestedReceipts_[sentStanza->getID()] = myLastMessageUIID_; chatWindow_->setMessageReceiptState(myLastMessageUIID_, ChatWindow::ReceiptRequested); } lastWasPresence_ = false; chatStateNotifier_->userSentMessage(); diff --git a/Swift/Controllers/Chat/ChatController.h b/Swift/Controllers/Chat/ChatController.h index 9c01923..2a66772 100644 --- a/Swift/Controllers/Chat/ChatController.h +++ b/Swift/Controllers/Chat/ChatController.h @@ -1,76 +1,77 @@ /* - * Copyright (c) 2010 Kevin Smith + * Copyright (c) 2010-2012 Kevin Smith * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. */ #pragma once -#include "Swift/Controllers/Chat/ChatControllerBase.h" +#include <Swift/Controllers/Chat/ChatControllerBase.h> #include <map> #include <string> #include <Swift/Controllers/UIInterfaces/ChatWindow.h> namespace Swift { class AvatarManager; class ChatStateNotifier; class ChatStateTracker; class NickResolver; class EntityCapsProvider; class FileTransferController; - class UIEvent; + class SettingsProvider; class ChatController : public ChatControllerBase { public: - ChatController(const JID& self, StanzaChannel* stanzaChannel, IQRouter* iqRouter, ChatWindowFactory* chatWindowFactory, const JID &contact, NickResolver* nickResolver, PresenceOracle* presenceOracle, AvatarManager* avatarManager, bool isInMUC, bool useDelayForLatency, UIEventStream* eventStream, EventController* eventController, TimerFactory* timerFactory, EntityCapsProvider* entityCapsProvider, bool userWantsReceipts); + ChatController(const JID& self, StanzaChannel* stanzaChannel, IQRouter* iqRouter, ChatWindowFactory* chatWindowFactory, const JID &contact, NickResolver* nickResolver, PresenceOracle* presenceOracle, AvatarManager* avatarManager, bool isInMUC, bool useDelayForLatency, UIEventStream* eventStream, EventController* eventController, TimerFactory* timerFactory, EntityCapsProvider* entityCapsProvider, bool userWantsReceipts, SettingsProvider* settings); virtual ~ChatController(); virtual void setToJID(const JID& jid); virtual void setOnline(bool online); virtual void handleNewFileTransferController(FileTransferController* ftc); virtual void setContactIsReceivingPresence(bool /*isReceivingPresence*/); private: void handlePresenceChange(boost::shared_ptr<Presence> newPresence); std::string getStatusChangeString(boost::shared_ptr<Presence> presence); bool isIncomingMessageFromMe(boost::shared_ptr<Message> message); void postSendMessage(const std::string &body, boost::shared_ptr<Stanza> sentStanza); void preHandleIncomingMessage(boost::shared_ptr<MessageEvent> messageEvent); void postHandleIncomingMessage(boost::shared_ptr<MessageEvent> messageEvent); void preSendMessageRequest(boost::shared_ptr<Message>); std::string senderDisplayNameFromMessage(const JID& from); virtual boost::optional<boost::posix_time::ptime> getMessageTimestamp(boost::shared_ptr<Message>) const; void handleStanzaAcked(boost::shared_ptr<Stanza> stanza); void dayTicked() {lastWasPresence_ = false;} void handleContactNickChanged(const JID& jid, const std::string& /*oldNick*/); void handleBareJIDCapsChanged(const JID& jid); void handleFileTransferCancel(std::string /* id */); void handleFileTransferStart(std::string /* id */, std::string /* description */); void handleFileTransferAccept(std::string /* id */, std::string /* filename */); void handleSendFileRequest(std::string filename); - void handleUIEvent(boost::shared_ptr<UIEvent> event); + void handleSettingChanged(const std::string& settingPath); void checkForDisplayingDisplayReceiptsAlert(); private: NickResolver* nickResolver_; ChatStateNotifier* chatStateNotifier_; ChatStateTracker* chatStateTracker_; std::string myLastMessageUIID_; bool isInMUC_; bool lastWasPresence_; std::string lastStatusChangeString_; std::map<boost::shared_ptr<Stanza>, std::string> unackedStanzas_; std::map<std::string, std::string> requestedReceipts_; StatusShow::Type lastShownStatus_; UIEventStream* eventStream_; ChatWindow::Tristate contactSupportsReceipts_; bool receivingPresenceFromUs_; bool userWantsReceipts_; std::map<std::string, FileTransferController*> ftControllers; + SettingsProvider* settings_; }; } diff --git a/Swift/Controllers/Chat/ChatsManager.cpp b/Swift/Controllers/Chat/ChatsManager.cpp index c19c524..a2b286f 100644 --- a/Swift/Controllers/Chat/ChatsManager.cpp +++ b/Swift/Controllers/Chat/ChatsManager.cpp @@ -1,148 +1,155 @@ /* * Copyright (c) 2010-2011 Kevin Smith * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. */ #include "Swift/Controllers/Chat/ChatsManager.h" #include <boost/bind.hpp> #include <boost/algorithm/string.hpp> #include <Swiften/Base/foreach.h> #include <Swift/Controllers/Chat/ChatController.h> #include <Swift/Controllers/Chat/ChatControllerBase.h> #include <Swift/Controllers/Chat/MUCSearchController.h> #include <Swift/Controllers/XMPPEvents/EventController.h> #include <Swift/Controllers/Chat/MUCController.h> #include <Swift/Controllers/UIEvents/RequestChatUIEvent.h> #include <Swift/Controllers/UIEvents/JoinMUCUIEvent.h> #include <Swift/Controllers/UIEvents/RequestJoinMUCUIEvent.h> #include <Swift/Controllers/UIEvents/AddMUCBookmarkUIEvent.h> #include <Swift/Controllers/UIEvents/RemoveMUCBookmarkUIEvent.h> #include <Swift/Controllers/UIEvents/EditMUCBookmarkUIEvent.h> -#include <Swift/Controllers/UIEvents/ToggleRequestDeliveryReceiptsUIEvent.h> #include <Swift/Controllers/UIInterfaces/ChatListWindowFactory.h> #include <Swift/Controllers/UIInterfaces/JoinMUCWindow.h> #include <Swift/Controllers/UIInterfaces/JoinMUCWindowFactory.h> #include <Swiften/Presence/PresenceSender.h> #include <Swiften/Client/NickResolver.h> #include <Swiften/MUC/MUCManager.h> #include <Swiften/Elements/ChatState.h> #include <Swiften/Elements/MUCUserPayload.h> #include <Swiften/Elements/DeliveryReceipt.h> #include <Swiften/Elements/DeliveryReceiptRequest.h> #include <Swiften/MUC/MUCBookmarkManager.h> #include <Swift/Controllers/FileTransfer/FileTransferController.h> #include <Swift/Controllers/FileTransfer/FileTransferOverview.h> #include <Swift/Controllers/ProfileSettingsProvider.h> #include <Swiften/Avatars/AvatarManager.h> #include <Swiften/Elements/MUCInvitationPayload.h> #include <Swiften/Roster/XMPPRoster.h> +#include <Swift/Controllers/Settings/SettingsProvider.h> +#include <Swift/Controllers/SettingConstants.h> namespace Swift { typedef std::pair<JID, ChatController*> JIDChatControllerPair; typedef std::pair<JID, MUCController*> JIDMUCControllerPair; #define RECENT_CHATS "recent_chats" ChatsManager::ChatsManager( JID jid, StanzaChannel* stanzaChannel, IQRouter* iqRouter, EventController* eventController, ChatWindowFactory* chatWindowFactory, JoinMUCWindowFactory* joinMUCWindowFactory, NickResolver* nickResolver, PresenceOracle* presenceOracle, PresenceSender* presenceSender, UIEventStream* uiEventStream, ChatListWindowFactory* chatListWindowFactory, bool useDelayForLatency, TimerFactory* timerFactory, MUCRegistry* mucRegistry, EntityCapsProvider* entityCapsProvider, MUCManager* mucManager, MUCSearchWindowFactory* mucSearchWindowFactory, - ProfileSettingsProvider* settings, + ProfileSettingsProvider* profileSettings, FileTransferOverview* ftOverview, XMPPRoster* roster, - bool eagleMode) : + bool eagleMode, + SettingsProvider* settings) : jid_(jid), joinMUCWindowFactory_(joinMUCWindowFactory), useDelayForLatency_(useDelayForLatency), mucRegistry_(mucRegistry), entityCapsProvider_(entityCapsProvider), mucManager(mucManager), ftOverview_(ftOverview), roster_(roster), - eagleMode_(eagleMode) { + eagleMode_(eagleMode), + settings_(settings) { timerFactory_ = timerFactory; eventController_ = eventController; stanzaChannel_ = stanzaChannel; iqRouter_ = iqRouter; chatWindowFactory_ = chatWindowFactory; nickResolver_ = nickResolver; presenceOracle_ = presenceOracle; avatarManager_ = NULL; serverDiscoInfo_ = boost::shared_ptr<DiscoInfo>(new DiscoInfo()); presenceSender_ = presenceSender; uiEventStream_ = uiEventStream; mucBookmarkManager_ = NULL; - profileSettings_ = settings; + profileSettings_ = profileSettings; presenceOracle_->onPresenceChange.connect(boost::bind(&ChatsManager::handlePresenceChange, this, _1)); uiEventConnection_ = uiEventStream_->onUIEvent.connect(boost::bind(&ChatsManager::handleUIEvent, this, _1)); chatListWindow_ = chatListWindowFactory->createChatListWindow(uiEventStream_); chatListWindow_->onMUCBookmarkActivated.connect(boost::bind(&ChatsManager::handleMUCBookmarkActivated, this, _1)); chatListWindow_->onRecentActivated.connect(boost::bind(&ChatsManager::handleRecentActivated, this, _1)); chatListWindow_->onClearRecentsRequested.connect(boost::bind(&ChatsManager::handleClearRecentsRequested, this)); joinMUCWindow_ = NULL; - mucSearchController_ = new MUCSearchController(jid_, mucSearchWindowFactory, iqRouter, settings); + mucSearchController_ = new MUCSearchController(jid_, mucSearchWindowFactory, iqRouter, profileSettings_); mucSearchController_->onMUCSelected.connect(boost::bind(&ChatsManager::handleMUCSelectedAfterSearch, this, _1)); ftOverview_->onNewFileTransferController.connect(boost::bind(&ChatsManager::handleNewFileTransferController, this, _1)); roster_->onJIDAdded.connect(boost::bind(&ChatsManager::handleJIDAddedToRoster, this, _1)); roster_->onJIDRemoved.connect(boost::bind(&ChatsManager::handleJIDRemovedFromRoster, this, _1)); roster_->onJIDUpdated.connect(boost::bind(&ChatsManager::handleJIDUpdatedInRoster, this, _1)); roster_->onRosterCleared.connect(boost::bind(&ChatsManager::handleRosterCleared, this)); + + settings_->onSettingChanged.connect(boost::bind(&ChatsManager::handleSettingChanged, this, _1)); + setupBookmarks(); loadRecents(); } ChatsManager::~ChatsManager() { + settings_->onSettingChanged.disconnect(boost::bind(&ChatsManager::handleSettingChanged, this, _1)); roster_->onJIDAdded.disconnect(boost::bind(&ChatsManager::handleJIDAddedToRoster, this, _1)); roster_->onJIDRemoved.disconnect(boost::bind(&ChatsManager::handleJIDRemovedFromRoster, this, _1)); roster_->onJIDUpdated.disconnect(boost::bind(&ChatsManager::handleJIDUpdatedInRoster, this, _1)); roster_->onRosterCleared.disconnect(boost::bind(&ChatsManager::handleRosterCleared, this)); delete joinMUCWindow_; foreach (JIDChatControllerPair controllerPair, chatControllers_) { delete controllerPair.second; } foreach (JIDMUCControllerPair controllerPair, mucControllers_) { delete controllerPair.second; } delete mucBookmarkManager_; delete mucSearchController_; } void ChatsManager::saveRecents() { std::string recents; int i = 1; foreach (ChatListWindow::Chat chat, recentChats_) { std::vector<std::string> activity; boost::split(activity, chat.activity, boost::is_any_of("\t\n")); if (activity.empty()) { /* Work around Boost bug https://svn.boost.org/trac/boost/ticket/4751 */ activity.push_back(""); } std::string recent = chat.jid.toString() + "\t" + (eagleMode_ ? "" : activity[0]) + "\t" + (chat.isMUC ? "true" : "false") + "\t" + chat.nick; recents += recent + "\n"; if (i++ > 25) { break; } } profileSettings_->storeString(RECENT_CHATS, recents); } void ChatsManager::handleClearRecentsRequested() { @@ -316,91 +323,94 @@ void ChatsManager::handleUnreadCountChanged(ChatControllerBase* controller) { } unreadTotal += chatItem.unreadCount; } chatListWindow_->setRecents(recentChats_); chatListWindow_->setUnreadCount(unreadTotal); } void ChatsManager::appendRecent(const ChatListWindow::Chat& chat) { recentChats_.erase(std::remove(recentChats_.begin(), recentChats_.end(), chat), recentChats_.end()); recentChats_.push_front(chat); } void ChatsManager::prependRecent(const ChatListWindow::Chat& chat) { recentChats_.erase(std::remove(recentChats_.begin(), recentChats_.end(), chat), recentChats_.end()); recentChats_.push_back(chat); } void ChatsManager::handleUserLeftMUC(MUCController* mucController) { std::map<JID, MUCController*>::iterator it; for (it = mucControllers_.begin(); it != mucControllers_.end(); ++it) { if ((*it).second == mucController) { foreach (ChatListWindow::Chat& chat, recentChats_) { if (chat.isMUC && chat.jid == (*it).first) { chat.statusType = StatusShow::None; chatListWindow_->setRecents(recentChats_); break; } } mucControllers_.erase(it); delete mucController; return; } } } +void ChatsManager::handleSettingChanged(const std::string& settingPath) { + if (settingPath == SettingConstants::REQUEST_DELIVERYRECEIPTS.getKey()) { + userWantsReceipts_ = settings_->getSetting(SettingConstants::REQUEST_DELIVERYRECEIPTS); + return; + } +} + void ChatsManager::handleUIEvent(boost::shared_ptr<UIEvent> event) { boost::shared_ptr<RequestChatUIEvent> chatEvent = boost::dynamic_pointer_cast<RequestChatUIEvent>(event); if (chatEvent) { handleChatRequest(chatEvent->getContact()); return; } boost::shared_ptr<RemoveMUCBookmarkUIEvent> removeMUCBookmarkEvent = boost::dynamic_pointer_cast<RemoveMUCBookmarkUIEvent>(event); if (removeMUCBookmarkEvent) { mucBookmarkManager_->removeBookmark(removeMUCBookmarkEvent->getBookmark()); return; } boost::shared_ptr<AddMUCBookmarkUIEvent> addMUCBookmarkEvent = boost::dynamic_pointer_cast<AddMUCBookmarkUIEvent>(event); if (addMUCBookmarkEvent) { mucBookmarkManager_->addBookmark(addMUCBookmarkEvent->getBookmark()); return; } - boost::shared_ptr<ToggleRequestDeliveryReceiptsUIEvent> toggleRequestDeliveryReceiptsEvent = boost::dynamic_pointer_cast<ToggleRequestDeliveryReceiptsUIEvent>(event); - if (toggleRequestDeliveryReceiptsEvent) { - userWantsReceipts_ = toggleRequestDeliveryReceiptsEvent->getEnabled(); - return; - } + boost::shared_ptr<EditMUCBookmarkUIEvent> editMUCBookmarkEvent = boost::dynamic_pointer_cast<EditMUCBookmarkUIEvent>(event); if (editMUCBookmarkEvent) { mucBookmarkManager_->replaceBookmark(editMUCBookmarkEvent->getOldBookmark(), editMUCBookmarkEvent->getNewBookmark()); } else if (JoinMUCUIEvent::ref joinEvent = boost::dynamic_pointer_cast<JoinMUCUIEvent>(event)) { handleJoinMUCRequest(joinEvent->getJID(), joinEvent->getPassword(), joinEvent->getNick(), joinEvent->getShouldJoinAutomatically(), joinEvent->getCreateAsReservedRoomIfNew()); mucControllers_[joinEvent->getJID()]->activateChatWindow(); } else if (boost::shared_ptr<RequestJoinMUCUIEvent> joinEvent = boost::dynamic_pointer_cast<RequestJoinMUCUIEvent>(event)) { if (!joinMUCWindow_) { joinMUCWindow_ = joinMUCWindowFactory_->createJoinMUCWindow(uiEventStream_); joinMUCWindow_->onSearchMUC.connect(boost::bind(&ChatsManager::handleSearchMUCRequest, this)); } joinMUCWindow_->setMUC(joinEvent->getRoom()); joinMUCWindow_->setNick(nickResolver_->jidToNick(jid_)); joinMUCWindow_->show(); } } /** * If a resource goes offline, release bound chatdialog to that resource. */ void ChatsManager::handlePresenceChange(boost::shared_ptr<Presence> newPresence) { if (mucRegistry_->isMUC(newPresence->getFrom().toBare())) return; foreach (ChatListWindow::Chat& chat, recentChats_) { if (newPresence->getFrom().toBare() == chat.jid.toBare() && !chat.isMUC) { Presence::ref presence = presenceOracle_->getHighestPriorityPresence(chat.jid.toBare()); chat.setStatusType(presence ? presence->getShow() : StatusShow::None); chatListWindow_->setRecents(recentChats_); break; } } @@ -457,71 +467,71 @@ void ChatsManager::setOnline(bool enabled) { controllerPair.second->setOnline(enabled); if (enabled) { controllerPair.second->rejoin(); } } if (!enabled) { delete mucBookmarkManager_; mucBookmarkManager_ = NULL; chatListWindow_->setBookmarksEnabled(false); } else { setupBookmarks(); } } void ChatsManager::handleChatRequest(const std::string &contact) { ChatController* controller = getChatControllerOrFindAnother(JID(contact)); controller->activateChatWindow(); } ChatController* ChatsManager::getChatControllerOrFindAnother(const JID &contact) { ChatController* controller = getChatControllerIfExists(contact); if (!controller && !mucRegistry_->isMUC(contact.toBare())) { foreach (JIDChatControllerPair pair, chatControllers_) { if (pair.first.toBare() == contact.toBare()) { controller = pair.second; break; } } } return controller ? controller : createNewChatController(contact); } ChatController* ChatsManager::createNewChatController(const JID& contact) { assert(chatControllers_.find(contact) == chatControllers_.end()); - ChatController* controller = new ChatController(jid_, stanzaChannel_, iqRouter_, chatWindowFactory_, contact, nickResolver_, presenceOracle_, avatarManager_, mucRegistry_->isMUC(contact.toBare()), useDelayForLatency_, uiEventStream_, eventController_, timerFactory_, entityCapsProvider_, userWantsReceipts_); + ChatController* controller = new ChatController(jid_, stanzaChannel_, iqRouter_, chatWindowFactory_, contact, nickResolver_, presenceOracle_, avatarManager_, mucRegistry_->isMUC(contact.toBare()), useDelayForLatency_, uiEventStream_, eventController_, timerFactory_, entityCapsProvider_, userWantsReceipts_, settings_); chatControllers_[contact] = controller; controller->setAvailableServerFeatures(serverDiscoInfo_); controller->onActivity.connect(boost::bind(&ChatsManager::handleChatActivity, this, contact, _1, false)); controller->onUnreadCountChanged.connect(boost::bind(&ChatsManager::handleUnreadCountChanged, this, controller)); updatePresenceReceivingStateOnChatController(contact); return controller; } ChatController* ChatsManager::getChatControllerOrCreate(const JID &contact) { ChatController* controller = getChatControllerIfExists(contact); return controller ? controller : createNewChatController(contact); } ChatController* ChatsManager::getChatControllerIfExists(const JID &contact, bool rebindIfNeeded) { if (chatControllers_.find(contact) == chatControllers_.end()) { if (mucRegistry_->isMUC(contact.toBare())) { return NULL; } //Need to look for an unbound window to bind first JID bare(contact.toBare()); if (chatControllers_.find(bare) != chatControllers_.end()) { rebindControllerJID(bare, contact); } else { foreach (JIDChatControllerPair pair, chatControllers_) { if (pair.first.toBare() == contact.toBare()) { if (rebindIfNeeded) { rebindControllerJID(pair.first, contact); return chatControllers_[contact]; } else { return pair.second; } } } return NULL; diff --git a/Swift/Controllers/Chat/ChatsManager.h b/Swift/Controllers/Chat/ChatsManager.h index 0c7f492..4d1fc14 100644 --- a/Swift/Controllers/Chat/ChatsManager.h +++ b/Swift/Controllers/Chat/ChatsManager.h @@ -14,116 +14,119 @@ #include <Swiften/Elements/DiscoInfo.h> #include <Swiften/Elements/Message.h> #include <Swiften/Elements/Presence.h> #include <Swiften/JID/JID.h> #include <Swiften/MUC/MUCRegistry.h> #include <Swift/Controllers/UIEvents/UIEventStream.h> #include <Swift/Controllers/UIInterfaces/ChatListWindow.h> #include <Swiften/MUC/MUCBookmark.h> namespace Swift { class EventController; class ChatController; class ChatControllerBase; class MUCController; class MUCManager; class ChatWindowFactory; class JoinMUCWindow; class JoinMUCWindowFactory; class NickResolver; class PresenceOracle; class AvatarManager; class StanzaChannel; class IQRouter; class PresenceSender; class MUCBookmarkManager; class ChatListWindowFactory; class TimerFactory; class EntityCapsProvider; class DirectedPresenceSender; class MUCSearchWindowFactory; class ProfileSettingsProvider; class MUCSearchController; class FileTransferOverview; class FileTransferController; class XMPPRoster; + class SettingsProvider; class ChatsManager { 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* settings, FileTransferOverview* ftOverview, XMPPRoster* roster, bool eagleMode); + 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* settings, FileTransferOverview* ftOverview, XMPPRoster* roster, bool eagleMode, SettingsProvider* settings); virtual ~ChatsManager(); void setAvatarManager(AvatarManager* avatarManager); void setOnline(bool enabled); void setServerDiscoInfo(boost::shared_ptr<DiscoInfo> info); void handleIncomingMessage(boost::shared_ptr<Message> message); private: ChatListWindow::Chat createChatListChatItem(const JID& jid, const std::string& activity); void handleChatRequest(const std::string& contact); void handleJoinMUCRequest(const JID& muc, const boost::optional<std::string>& password, const boost::optional<std::string>& nick, bool addAutoJoin, bool createAsReservedIfNew); void handleSearchMUCRequest(); void handleMUCSelectedAfterSearch(const JID&); void rebindControllerJID(const JID& from, const JID& to); void handlePresenceChange(boost::shared_ptr<Presence> newPresence); void handleUIEvent(boost::shared_ptr<UIEvent> event); void handleMUCBookmarkAdded(const MUCBookmark& bookmark); void handleMUCBookmarkRemoved(const MUCBookmark& bookmark); void handleUserLeftMUC(MUCController* mucController); void handleBookmarksReady(); void handleChatActivity(const JID& jid, const std::string& activity, bool isMUC); void handleNewFileTransferController(FileTransferController*); void appendRecent(const ChatListWindow::Chat& chat); void prependRecent(const ChatListWindow::Chat& chat); void setupBookmarks(); void loadRecents(); void saveRecents(); void handleChatMadeRecent(); void handleMUCBookmarkActivated(const MUCBookmark&); void handleRecentActivated(const ChatListWindow::Chat&); void handleUnreadCountChanged(ChatControllerBase* controller); void handleAvatarChanged(const JID& jid); void handleClearRecentsRequested(); void handleJIDAddedToRoster(const JID&); void handleJIDRemovedFromRoster(const JID&); void handleJIDUpdatedInRoster(const JID&); void handleRosterCleared(); + void handleSettingChanged(const std::string& settingPath); void updatePresenceReceivingStateOnChatController(const JID&); ChatController* getChatControllerOrFindAnother(const JID &contact); ChatController* createNewChatController(const JID &contact); ChatController* getChatControllerOrCreate(const JID &contact); ChatController* getChatControllerIfExists(const JID &contact, bool rebindIfNeeded = true); private: std::map<JID, MUCController*> mucControllers_; std::map<JID, ChatController*> chatControllers_; EventController* eventController_; JID jid_; StanzaChannel* stanzaChannel_; IQRouter* iqRouter_; ChatWindowFactory* chatWindowFactory_; JoinMUCWindowFactory* joinMUCWindowFactory_; NickResolver* nickResolver_; PresenceOracle* presenceOracle_; AvatarManager* avatarManager_; PresenceSender* presenceSender_; UIEventStream* uiEventStream_; MUCBookmarkManager* mucBookmarkManager_; boost::shared_ptr<DiscoInfo> serverDiscoInfo_; ChatListWindow* chatListWindow_; JoinMUCWindow* joinMUCWindow_; boost::bsignals::scoped_connection uiEventConnection_; bool useDelayForLatency_; TimerFactory* timerFactory_; MUCRegistry* mucRegistry_; EntityCapsProvider* entityCapsProvider_; MUCManager* mucManager; MUCSearchController* mucSearchController_; std::list<ChatListWindow::Chat> recentChats_; ProfileSettingsProvider* profileSettings_; FileTransferOverview* ftOverview_; XMPPRoster* roster_; bool eagleMode_; bool userWantsReceipts_; + SettingsProvider* settings_; }; } diff --git a/Swift/Controllers/Chat/UnitTest/ChatsManagerTest.cpp b/Swift/Controllers/Chat/UnitTest/ChatsManagerTest.cpp index 8162bec..cd868e6 100644 --- a/Swift/Controllers/Chat/UnitTest/ChatsManagerTest.cpp +++ b/Swift/Controllers/Chat/UnitTest/ChatsManagerTest.cpp @@ -1,169 +1,169 @@ /* - * Copyright (c) 2010-2011 Kevin Smith + * Copyright (c) 2010-2012 Kevin Smith * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. */ #include <cppunit/extensions/HelperMacros.h> #include <cppunit/extensions/TestFactoryRegistry.h> #include "3rdParty/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/JoinMUCWindowFactory.h" #include "Swift/Controllers/UIInterfaces/MUCSearchWindowFactory.h" #include "Swiften/Client/Client.h" #include "Swiften/Disco/EntityCapsManager.h" #include "Swiften/Disco/CapsProvider.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/StanzaChannelPresenceSender.h" #include "Swiften/Avatars/NullAvatarManager.h" #include "Swiften/Avatars/AvatarMemoryStorage.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/UIEvents/ToggleRequestDeliveryReceiptsUIEvent.h" #include <Swift/Controllers/ProfileSettingsProvider.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/SettingConstants.h> using namespace Swift; class DummyCapsProvider : public CapsProvider { DiscoInfo::ref getCaps(const std::string&) const {return DiscoInfo::ref(new DiscoInfo());} }; class ChatsManagerTest : public CppUnit::TestFixture { CPPUNIT_TEST_SUITE(ChatsManagerTest); CPPUNIT_TEST(testFirstOpenWindowIncoming); CPPUNIT_TEST(testSecondOpenWindowIncoming); CPPUNIT_TEST(testFirstOpenWindowOutgoing); CPPUNIT_TEST(testFirstOpenWindowBareToFull); CPPUNIT_TEST(testSecondWindow); CPPUNIT_TEST(testUnbindRebind); CPPUNIT_TEST(testNoDuplicateUnbind); CPPUNIT_TEST(testThreeMUCWindows); CPPUNIT_TEST(testChatControllerPresenceAccessUpdatedOnRemoveFromRoster); CPPUNIT_TEST(testChatControllerPresenceAccessUpdatedOnAddToRoster); CPPUNIT_TEST(testChatControllerPresenceAccessUpdatedOnSubscriptionChangeToBoth); CPPUNIT_TEST(testChatControllerPresenceAccessUpdatedOnSubscriptionChangeToFrom); CPPUNIT_TEST_SUITE_END(); public: void setUp() { mocks_ = new MockRepository(); jid_ = JID("test@test.com/resource"); stanzaChannel_ = new DummyStanzaChannel(); iqChannel_ = new DummyIQChannel(); iqRouter_ = new IQRouter(iqChannel_); capsProvider_ = new DummyCapsProvider(); eventController_ = new EventController(); chatWindowFactory_ = mocks_->InterfaceMock<ChatWindowFactory>(); joinMUCWindowFactory_ = mocks_->InterfaceMock<JoinMUCWindowFactory>(); xmppRoster_ = new XMPPRosterImpl(); mucRegistry_ = new MUCRegistry(); nickResolver_ = new NickResolver(jid_.toBare(), xmppRoster_, NULL, mucRegistry_); presenceOracle_ = new PresenceOracle(stanzaChannel_); serverDiscoInfo_ = boost::shared_ptr<DiscoInfo>(new DiscoInfo()); presenceSender_ = new StanzaChannelPresenceSender(stanzaChannel_); directedPresenceSender_ = new DirectedPresenceSender(presenceSender_); mucManager_ = new MUCManager(stanzaChannel_, iqRouter_, directedPresenceSender_, mucRegistry_); uiEventStream_ = new UIEventStream(); entityCapsManager_ = new EntityCapsManager(capsProvider_, stanzaChannel_); chatListWindowFactory_ = mocks_->InterfaceMock<ChatListWindowFactory>(); mucSearchWindowFactory_ = mocks_->InterfaceMock<MUCSearchWindowFactory>(); settings_ = new DummySettingsProvider(); profileSettings_ = new ProfileSettingsProvider("a", settings_); chatListWindow_ = new MockChatListWindow(); ftManager_ = new DummyFileTransferManager(); ftOverview_ = new FileTransferOverview(ftManager_); mocks_->ExpectCall(chatListWindowFactory_, ChatListWindowFactory::createChatListWindow).With(uiEventStream_).Return(chatListWindow_); - manager_ = new ChatsManager(jid_, stanzaChannel_, iqRouter_, eventController_, chatWindowFactory_, joinMUCWindowFactory_, nickResolver_, presenceOracle_, directedPresenceSender_, uiEventStream_, chatListWindowFactory_, true, NULL, mucRegistry_, entityCapsManager_, mucManager_, mucSearchWindowFactory_, profileSettings_, ftOverview_, xmppRoster_, false); + 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_); avatarManager_ = new NullAvatarManager(); manager_->setAvatarManager(avatarManager_); }; void tearDown() { //delete chatListWindowFactory - delete settings_; delete profileSettings_; delete avatarManager_; delete manager_; delete ftOverview_; delete ftManager_; delete directedPresenceSender_; delete presenceSender_; delete presenceOracle_; delete nickResolver_; delete mucRegistry_; delete stanzaChannel_; delete eventController_; delete iqRouter_; delete iqChannel_; delete uiEventStream_; delete mucManager_; delete xmppRoster_; delete entityCapsManager_; delete capsProvider_; delete chatListWindow_; delete mocks_; + delete settings_; } void testFirstOpenWindowIncoming() { JID messageJID("testling@test.com/resource1"); MockChatWindow* window = new MockChatWindow();//mocks_->InterfaceMock<ChatWindow>(); mocks_->ExpectCall(chatWindowFactory_, ChatWindowFactory::createChatWindow).With(messageJID, uiEventStream_).Return(window); boost::shared_ptr<Message> message(new Message()); message->setFrom(messageJID); std::string body("This is a legible message. >HEH@)oeueu"); message->setBody(body); manager_->handleIncomingMessage(message); CPPUNIT_ASSERT_EQUAL(body, window->lastMessageBody_); } void testSecondOpenWindowIncoming() { JID messageJID1("testling@test.com/resource1"); MockChatWindow* window1 = new MockChatWindow();//mocks_->InterfaceMock<ChatWindow>(); mocks_->ExpectCall(chatWindowFactory_, ChatWindowFactory::createChatWindow).With(messageJID1, uiEventStream_).Return(window1); boost::shared_ptr<Message> message1(new Message()); message1->setFrom(messageJID1); std::string body1("This is a legible message. >HEH@)oeueu"); message1->setBody(body1); manager_->handleIncomingMessage(message1); CPPUNIT_ASSERT_EQUAL(body1, window1->lastMessageBody_); JID messageJID2("testling@test.com/resource2"); //MockChatWindow* window2 = new MockChatWindow();//mocks_->InterfaceMock<ChatWindow>(); //mocks_->ExpectCall(chatWindowFactory_, ChatWindowFactory::createChatWindow).With(messageJID2, uiEventStream_).Return(window2); boost::shared_ptr<Message> message2(new Message()); @@ -321,130 +321,130 @@ public: presenceOracle_->onPresenceChange(jid1Offline); boost::shared_ptr<Presence> jid2Online(new Presence()); jid2Online->setFrom(JID(messageJID2)); boost::shared_ptr<Presence> jid2Offline(new Presence()); jid2Offline->setFrom(JID(messageJID2)); jid2Offline->setType(Presence::Unavailable); presenceOracle_->onPresenceChange(jid2Offline); JID messageJID3("testling@test.com/resource3"); boost::shared_ptr<Message> message3(new Message()); message3->setFrom(messageJID3); std::string body3("This is a legible message3."); message3->setBody(body3); manager_->handleIncomingMessage(message3); CPPUNIT_ASSERT_EQUAL(body3, window1->lastMessageBody_); boost::shared_ptr<Message> message2b(new Message()); message2b->setFrom(messageJID2); std::string body2b("This is a legible message2b."); message2b->setBody(body2b); manager_->handleIncomingMessage(message2b); CPPUNIT_ASSERT_EQUAL(body2b, window1->lastMessageBody_); } /** * Test that ChatController doesn't send receipts anymore after removal of the contact from the roster. */ void testChatControllerPresenceAccessUpdatedOnRemoveFromRoster() { JID messageJID("testling@test.com/resource1"); xmppRoster_->addContact(messageJID, "foo", std::vector<std::string>(), RosterItemPayload::Both); MockChatWindow* window = new MockChatWindow();//mocks_->InterfaceMock<ChatWindow>(); mocks_->ExpectCall(chatWindowFactory_, ChatWindowFactory::createChatWindow).With(messageJID, uiEventStream_).Return(window); - uiEventStream_->send(boost::shared_ptr<UIEvent>(new ToggleRequestDeliveryReceiptsUIEvent(true))); + settings_->storeSetting(SettingConstants::REQUEST_DELIVERYRECEIPTS, true); boost::shared_ptr<Message> message = makeDeliveryReceiptTestMessage(messageJID, "1"); manager_->handleIncomingMessage(message); Stanza::ref stanzaContactOnRoster = stanzaChannel_->getStanzaAtIndex<Stanza>(0); CPPUNIT_ASSERT_EQUAL(st(1), stanzaChannel_->sentStanzas.size()); CPPUNIT_ASSERT(stanzaContactOnRoster->getPayload<DeliveryReceipt>() != 0); xmppRoster_->removeContact(messageJID); message->setID("2"); manager_->handleIncomingMessage(message); CPPUNIT_ASSERT_EQUAL(st(1), stanzaChannel_->sentStanzas.size()); } /** * Test that ChatController sends receipts after the contact has been added to the roster. */ void testChatControllerPresenceAccessUpdatedOnAddToRoster() { JID messageJID("testling@test.com/resource1"); MockChatWindow* window = new MockChatWindow();//mocks_->InterfaceMock<ChatWindow>(); mocks_->ExpectCall(chatWindowFactory_, ChatWindowFactory::createChatWindow).With(messageJID, uiEventStream_).Return(window); - uiEventStream_->send(boost::shared_ptr<UIEvent>(new ToggleRequestDeliveryReceiptsUIEvent(true))); + settings_->storeSetting(SettingConstants::REQUEST_DELIVERYRECEIPTS, true); boost::shared_ptr<Message> message = makeDeliveryReceiptTestMessage(messageJID, "1"); manager_->handleIncomingMessage(message); CPPUNIT_ASSERT_EQUAL(st(0), stanzaChannel_->sentStanzas.size()); xmppRoster_->addContact(messageJID, "foo", std::vector<std::string>(), RosterItemPayload::Both); message->setID("2"); manager_->handleIncomingMessage(message); CPPUNIT_ASSERT_EQUAL(st(1), stanzaChannel_->sentStanzas.size()); Stanza::ref stanzaContactOnRoster = stanzaChannel_->getStanzaAtIndex<Stanza>(0); CPPUNIT_ASSERT(stanzaContactOnRoster->getPayload<DeliveryReceipt>() != 0); } /** * Test that ChatController sends receipts if requested after change from subscription state To to subscription state Both. */ void testChatControllerPresenceAccessUpdatedOnSubscriptionChangeToBoth() { testhelperChatControllerPresenceAccessUpdatedOnSubscriptionChangeReceiptsAllowed(RosterItemPayload::To, RosterItemPayload::Both); } /** * Test that ChatController sends receipts if requested after change from subscription state To to subscription state From. */ void testChatControllerPresenceAccessUpdatedOnSubscriptionChangeToFrom() { testhelperChatControllerPresenceAccessUpdatedOnSubscriptionChangeReceiptsAllowed(RosterItemPayload::To, RosterItemPayload::From); } void testhelperChatControllerPresenceAccessUpdatedOnSubscriptionChangeReceiptsAllowed(RosterItemPayload::Subscription from, RosterItemPayload::Subscription to) { JID messageJID("testling@test.com/resource1"); xmppRoster_->addContact(messageJID, "foo", std::vector<std::string>(), from); MockChatWindow* window = new MockChatWindow();//mocks_->InterfaceMock<ChatWindow>(); mocks_->ExpectCall(chatWindowFactory_, ChatWindowFactory::createChatWindow).With(messageJID, uiEventStream_).Return(window); - uiEventStream_->send(boost::shared_ptr<UIEvent>(new ToggleRequestDeliveryReceiptsUIEvent(true))); + settings_->storeSetting(SettingConstants::REQUEST_DELIVERYRECEIPTS, true); boost::shared_ptr<Message> message = makeDeliveryReceiptTestMessage(messageJID, "1"); manager_->handleIncomingMessage(message); CPPUNIT_ASSERT_EQUAL(st(0), stanzaChannel_->sentStanzas.size()); xmppRoster_->addContact(messageJID, "foo", std::vector<std::string>(), to); message->setID("2"); manager_->handleIncomingMessage(message); CPPUNIT_ASSERT_EQUAL(st(1), stanzaChannel_->sentStanzas.size()); Stanza::ref stanzaContactOnRoster = stanzaChannel_->getStanzaAtIndex<Stanza>(0); CPPUNIT_ASSERT(stanzaContactOnRoster->getPayload<DeliveryReceipt>() != 0); } private: boost::shared_ptr<Message> makeDeliveryReceiptTestMessage(const JID& from, const std::string& id) { boost::shared_ptr<Message> message = boost::make_shared<Message>(); message->setFrom(from); message->setID(id); message->addPayload(boost::make_shared<DeliveryReceiptRequest>()); return message; } size_t st(int i) { return static_cast<size_t>(i); } private: JID jid_; ChatsManager* manager_; DummyStanzaChannel* stanzaChannel_; IQChannel* iqChannel_; IQRouter* iqRouter_; EventController* eventController_; diff --git a/Swift/Controllers/MainController.cpp b/Swift/Controllers/MainController.cpp index 6f93dd3..06f8c3a 100644 --- a/Swift/Controllers/MainController.cpp +++ b/Swift/Controllers/MainController.cpp @@ -1,664 +1,657 @@ /* - * Copyright (c) 2010-2011 Kevin Smith + * Copyright (c) 2010-2012 Kevin Smith * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. */ #include <Swift/Controllers/MainController.h> #include <boost/bind.hpp> #include <boost/lexical_cast.hpp> #include <boost/shared_ptr.hpp> #include <boost/smart_ptr/make_shared.hpp> #include <string> #include <stdlib.h> #include <Swiften/Base/format.h> #include <Swiften/Base/Algorithm.h> #include <Swift/Controllers/Intl.h> #include <Swift/Controllers/UIInterfaces/UIFactory.h> #include "Swiften/Network/TimerFactory.h" #include "Swift/Controllers/BuildVersion.h" #include "Swiften/Client/Storages.h" #include "Swiften/VCards/VCardManager.h" #include "Swift/Controllers/Chat/UserSearchController.h" #include "Swift/Controllers/Chat/ChatsManager.h" #include "Swift/Controllers/XMPPEvents/EventController.h" #include "Swift/Controllers/EventWindowController.h" #include "Swift/Controllers/UIInterfaces/LoginWindow.h" #include "Swift/Controllers/UIInterfaces/LoginWindowFactory.h" #include "Swift/Controllers/UIInterfaces/MainWindow.h" #include "Swift/Controllers/Chat/MUCController.h" #include "Swiften/Client/NickResolver.h" #include "Swift/Controllers/Roster/RosterController.h" #include "Swift/Controllers/SoundEventController.h" #include "Swift/Controllers/SoundPlayer.h" #include "Swift/Controllers/StatusTracker.h" #include "Swift/Controllers/SystemTray.h" #include "Swift/Controllers/SystemTrayController.h" #include "Swift/Controllers/XMLConsoleController.h" #include "Swift/Controllers/FileTransferListController.h" #include "Swift/Controllers/UIEvents/UIEventStream.h" #include "Swift/Controllers/PresenceNotifier.h" #include "Swift/Controllers/EventNotifier.h" #include "Swift/Controllers/Storages/StoragesFactory.h" #include "SwifTools/Dock/Dock.h" #include "SwifTools/Notifier/TogglableNotifier.h" #include "Swiften/Base/foreach.h" #include "Swiften/Client/Client.h" #include "Swiften/Presence/PresenceSender.h" #include "Swiften/Elements/ChatState.h" #include "Swiften/Elements/Presence.h" #include "Swiften/Elements/VCardUpdate.h" #include "Swift/Controllers/Settings/SettingsProvider.h" #include "Swiften/Elements/DiscoInfo.h" #include "Swiften/Disco/CapsInfoGenerator.h" #include "Swiften/Disco/GetDiscoInfoRequest.h" #include "Swiften/Disco/ClientDiscoManager.h" #include "Swiften/VCards/GetVCardRequest.h" #include "Swiften/StringCodecs/SHA1.h" #include "Swiften/StringCodecs/Hexify.h" #include "Swift/Controllers/UIEvents/RequestChatUIEvent.h" -#include "Swift/Controllers/UIEvents/ToggleNotificationsUIEvent.h" -#include "Swift/Controllers/UIEvents/ToggleRequestDeliveryReceiptsUIEvent.h" #include "Swift/Controllers/UIEvents/JoinMUCUIEvent.h" #include "Swift/Controllers/Storages/CertificateStorageFactory.h" #include "Swift/Controllers/Storages/CertificateStorageTrustChecker.h" #include "Swiften/Network/NetworkFactories.h" #include <Swift/Controllers/ProfileController.h> #include <Swift/Controllers/ContactEditController.h> #include <Swift/Controllers/XMPPURIController.h> #include "Swift/Controllers/AdHocManager.h" #include <SwifTools/Idle/IdleDetector.h> #include <Swift/Controllers/FileTransfer/FileTransferOverview.h> #include <Swiften/FileTransfer/FileTransferManager.h> #include <Swiften/Client/ClientXMLTracer.h> +#include <Swift/Controllers/SettingConstants.h> namespace Swift { static const std::string CLIENT_NAME = "Swift"; static const std::string CLIENT_NODE = "http://swift.im"; -static const std::string SHOW_NOTIFICATIONS = "showNotifications"; -static const std::string REQUEST_DELIVERYRECEIPTS = "requestDeliveryReceipts"; MainController::MainController( EventLoop* eventLoop, NetworkFactories* networkFactories, UIFactory* uiFactories, - SettingsProvider *settings, + SettingsProvider* settings, SystemTray* systemTray, SoundPlayer* soundPlayer, StoragesFactory* storagesFactory, CertificateStorageFactory* certificateStorageFactory, Dock* dock, Notifier* notifier, URIHandler* uriHandler, IdleDetector* idleDetector, - bool useDelayForLatency, - bool eagleMode) : + bool useDelayForLatency) : eventLoop_(eventLoop), networkFactories_(networkFactories), uiFactory_(uiFactories), storagesFactory_(storagesFactory), certificateStorageFactory_(certificateStorageFactory), settings_(settings), uriHandler_(uriHandler), idleDetector_(idleDetector), loginWindow_(NULL) , useDelayForLatency_(useDelayForLatency), - eagleMode_(eagleMode), ftOverview_(NULL) { storages_ = NULL; certificateStorage_ = NULL; statusTracker_ = NULL; presenceNotifier_ = NULL; eventNotifier_ = NULL; rosterController_ = NULL; chatsManager_ = NULL; eventWindowController_ = NULL; profileController_ = NULL; contactEditController_ = NULL; userSearchControllerChat_ = NULL; userSearchControllerAdd_ = NULL; adHocManager_ = NULL; quitRequested_ = false; clientInitialized_ = false; offlineRequested_ = false; timeBeforeNextReconnect_ = -1; dock_ = dock; uiEventStream_ = new UIEventStream(); notifier_ = new TogglableNotifier(notifier); eventController_ = new EventController(); eventController_->onEventQueueLengthChange.connect(boost::bind(&MainController::handleEventQueueLengthChange, this, _1)); systemTrayController_ = new SystemTrayController(eventController_, systemTray); loginWindow_ = uiFactory_->createLoginWindow(uiEventStream_); loginWindow_->setShowNotificationToggle(!notifier->isExternallyConfigured()); - soundEventController_ = new SoundEventController(eventController_, soundPlayer, settings, uiEventStream_); + soundEventController_ = new SoundEventController(eventController_, soundPlayer, settings); xmppURIController_ = new XMPPURIController(uriHandler_, uiEventStream_); - std::string selectedLoginJID = settings_->getStringSetting("lastLoginJID"); - bool loginAutomatically = settings_->getBoolSetting("loginAutomatically", false); + std::string selectedLoginJID = settings_->getSetting(SettingConstants::LAST_LOGIN_JID); + bool loginAutomatically = settings_->getSetting(SettingConstants::LOGIN_AUTOMATICALLY); std::string cachedPassword; std::string cachedCertificate; - if (!eagleMode_) { + bool eagle = settings_->getSetting(SettingConstants::FORGET_PASSWORDS); + if (!eagle) { foreach (std::string profile, settings->getAvailableProfiles()) { ProfileSettingsProvider profileSettings(profile, settings); - std::string password = eagleMode ? "" : profileSettings.getStringSetting("pass"); + std::string password = profileSettings.getStringSetting("pass"); std::string certificate = profileSettings.getStringSetting("certificate"); std::string jid = profileSettings.getStringSetting("jid"); loginWindow_->addAvailableAccount(jid, password, certificate); if (jid == selectedLoginJID) { cachedPassword = password; cachedCertificate = certificate; } } loginWindow_->selectUser(selectedLoginJID); loginWindow_->setLoginAutomatically(loginAutomatically); } loginWindow_->onLoginRequest.connect(boost::bind(&MainController::handleLoginRequest, this, _1, _2, _3, _4, _5)); loginWindow_->onPurgeSavedLoginRequest.connect(boost::bind(&MainController::handlePurgeSavedLoginRequest, this, _1)); loginWindow_->onCancelLoginRequest.connect(boost::bind(&MainController::handleCancelLoginRequest, this)); loginWindow_->onQuitRequest.connect(boost::bind(&MainController::handleQuitRequest, this)); - idleDetector_->setIdleTimeSeconds(600); + idleDetector_->setIdleTimeSeconds(settings->getSetting(SettingConstants::IDLE_TIMEOUT)); idleDetector_->onIdleChanged.connect(boost::bind(&MainController::handleInputIdleChanged, this, _1)); xmlConsoleController_ = new XMLConsoleController(uiEventStream_, uiFactory_); fileTransferListController_ = new FileTransferListController(uiEventStream_, uiFactory_); - uiEventStream_->onUIEvent.connect(boost::bind(&MainController::handleUIEvent, this, _1)); - bool enabled = settings_->getBoolSetting(SHOW_NOTIFICATIONS, true); - uiEventStream_->send(boost::shared_ptr<ToggleNotificationsUIEvent>(new ToggleNotificationsUIEvent(enabled))); + settings_->onSettingChanged.connect(boost::bind(&MainController::handleSettingChanged, this, _1)); if (loginAutomatically) { profileSettings_ = new ProfileSettingsProvider(selectedLoginJID, settings_); handleLoginRequest(selectedLoginJID, cachedPassword, cachedCertificate, true, true); } else { profileSettings_ = NULL; } } MainController::~MainController() { idleDetector_->onIdleChanged.disconnect(boost::bind(&MainController::handleInputIdleChanged, this, _1)); purgeCachedCredentials(); //setManagersOffline(); eventController_->disconnectAll(); resetClient(); delete fileTransferListController_; delete xmlConsoleController_; delete xmppURIController_; delete soundEventController_; delete systemTrayController_; delete eventController_; delete notifier_; delete uiEventStream_; } void MainController::purgeCachedCredentials() { safeClear(password_); } void MainController::resetClient() { purgeCachedCredentials(); resetCurrentError(); resetPendingReconnects(); vCardPhotoHash_.clear(); delete contactEditController_; contactEditController_ = NULL; delete profileController_; profileController_ = NULL; delete eventWindowController_; eventWindowController_ = NULL; delete chatsManager_; chatsManager_ = NULL; delete ftOverview_; ftOverview_ = NULL; delete rosterController_; rosterController_ = NULL; delete eventNotifier_; eventNotifier_ = NULL; delete presenceNotifier_; presenceNotifier_ = NULL; delete certificateStorage_; certificateStorage_ = NULL; delete storages_; storages_ = NULL; delete statusTracker_; statusTracker_ = NULL; delete profileSettings_; profileSettings_ = NULL; delete userSearchControllerChat_; userSearchControllerChat_ = NULL; delete userSearchControllerAdd_; userSearchControllerAdd_ = NULL; delete adHocManager_; adHocManager_ = NULL; clientInitialized_ = false; } -void MainController::handleUIEvent(boost::shared_ptr<UIEvent> event) { - boost::shared_ptr<ToggleNotificationsUIEvent> notificationsEvent = boost::dynamic_pointer_cast<ToggleNotificationsUIEvent>(event); - if (notificationsEvent) { - bool enabled = notificationsEvent->getEnabled(); - notifier_->setPersistentEnabled(enabled); - settings_->storeBool(SHOW_NOTIFICATIONS, enabled); +void MainController::handleSettingChanged(const std::string& settingPath) { + if (settingPath == SettingConstants::SHOW_NOTIFICATIONS.getKey()) { + notifier_->setPersistentEnabled(settings_->getSetting(SettingConstants::SHOW_NOTIFICATIONS)); } - boost::shared_ptr<ToggleRequestDeliveryReceiptsUIEvent> deliveryReceiptEvent = boost::dynamic_pointer_cast<ToggleRequestDeliveryReceiptsUIEvent>(event); - if (deliveryReceiptEvent) { - settings_->storeBool(REQUEST_DELIVERYRECEIPTS, deliveryReceiptEvent->getEnabled()); - } - } 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 (eagleMode_) { + if (settings_->getSetting(SettingConstants::FORGET_PASSWORDS)) { purgeCachedCredentials(); } bool freshLogin = rosterController_ == NULL; myStatusLooksOnline_ = true; if (freshLogin) { profileController_ = new ProfileController(client_->getVCardManager(), uiFactory_, uiEventStream_); srand(time(NULL)); int randomPort = 10000 + rand() % 10000; client_->getFileTransferManager()->startListeningOnPort(randomPort); 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_); rosterController_->onChangeStatusRequest.connect(boost::bind(&MainController::handleChangeStatusRequest, this, _1, _2)); rosterController_->onSignOutRequest.connect(boost::bind(&MainController::signOut, this)); contactEditController_ = new ContactEditController(rosterController_, uiFactory_, uiEventStream_); - 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(), eagleMode_); + 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_); client_->onMessageReceived.connect(boost::bind(&ChatsManager::handleIncomingMessage, chatsManager_, _1)); chatsManager_->setAvatarManager(client_->getAvatarManager()); eventWindowController_ = new EventWindowController(eventController_, uiFactory_); loginWindow_->morphInto(rosterController_->getWindow()); 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 discoInfo.addFeature(DiscoInfo::MessageDeliveryReceiptsFeature); client_->getDiscoManager()->setCapsNode(CLIENT_NODE); client_->getDiscoManager()->setDiscoInfo(discoInfo); userSearchControllerChat_ = new UserSearchController(UserSearchController::StartChat, jid_, uiEventStream_, uiFactory_, client_->getIQRouter(), rosterController_); userSearchControllerAdd_ = new UserSearchController(UserSearchController::AddContact, jid_, uiEventStream_, uiFactory_, client_->getIQRouter(), rosterController_); adHocManager_ = new AdHocManager(boundJID_, uiFactory_, client_->getIQRouter(), uiEventStream_, rosterController_->getWindow()); } loginWindow_->setIsLoggingIn(false); client_->requestRoster(); GetDiscoInfoRequest::ref discoInfoRequest = GetDiscoInfoRequest::create(boundJID_.toBare(), client_->getIQRouter()); discoInfoRequest->onResponse.connect(boost::bind(&MainController::handleServerDiscoInfoResponse, this, _1, _2)); discoInfoRequest->send(); client_->getVCardManager()->requestOwnVCard(); rosterController_->setEnabled(true); 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 */ chatsManager_->setOnline(true); - // notify world about current delivey receipt request setting state. - uiEventStream_->send(boost::make_shared<ToggleRequestDeliveryReceiptsUIEvent>(settings_->getBoolSetting(REQUEST_DELIVERYRECEIPTS, false))); } 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; presence->setShow(show); } presence->setStatus(statusText); statusTracker_->setRequestedPresence(presence); if (presence->getType() != Presence::Unavailable) { profileSettings_->storeInt("lastShow", presence->getShow()); profileSettings_->storeString("lastStatus", presence->getStatus()); } if (presence->getType() != Presence::Unavailable && !client_->isAvailable()) { performLoginFromCachedCredentials(); } else { sendPresence(presence); } } void MainController::sendPresence(boost::shared_ptr<Presence> presence) { rosterController_->getWindow()->setMyStatusType(presence->getShow()); rosterController_->getWindow()->setMyStatusText(presence->getStatus()); systemTrayController_->setMyStatusType(presence->getShow()); notifier_->setTemporarilyDisabled(presence->getShow() == StatusShow::DND); // Add information and send if (!vCardPhotoHash_.empty()) { presence->updatePayload(boost::shared_ptr<VCardUpdate>(new VCardUpdate(vCardPhotoHash_))); } client_->getPresenceSender()->sendPresence(presence); if (presence->getType() == Presence::Unavailable) { logout(); } } void MainController::handleInputIdleChanged(bool idle) { if (!statusTracker_) { //Haven't logged in yet. return; } - if (idle) { - if (statusTracker_->goAutoAway()) { - if (client_ && client_->isAvailable()) { - sendPresence(statusTracker_->getNextPresence()); - } + + if (settings_->getSetting(SettingConstants::IDLE_GOES_OFFLINE)) { + if (idle) { + logout(); } - } else { - if (statusTracker_->goAutoUnAway()) { - if (client_ && client_->isAvailable()) { - sendPresence(statusTracker_->getNextPresence()); + } + else { + if (idle) { + if (statusTracker_->goAutoAway()) { + if (client_ && client_->isAvailable()) { + sendPresence(statusTracker_->getNextPresence()); + } + } + } else { + if (statusTracker_->goAutoUnAway()) { + if (client_ && client_->isAvailable()) { + sendPresence(statusTracker_->getNextPresence()); + } } } } } void MainController::handleLoginRequest(const std::string &username, const std::string &password, const std::string& certificateFile, bool remember, bool loginAutomatically) { jid_ = JID(username); if (!jid_.isValid() || jid_.getNode().empty()) { loginWindow_->setMessage(QT_TRANSLATE_NOOP("", "User address invalid. User address should be of the form 'alice@wonderland.lit'")); loginWindow_->setIsLoggingIn(false); } else { loginWindow_->setMessage(""); loginWindow_->setIsLoggingIn(true); profileSettings_ = new ProfileSettingsProvider(username, settings_); - if (!eagleMode_) { + if (!settings_->getSetting(SettingConstants::FORGET_PASSWORDS)) { profileSettings_->storeString("jid", username); profileSettings_->storeString("certificate", certificateFile); profileSettings_->storeString("pass", (remember || loginAutomatically) ? password : ""); - settings_->storeString("lastLoginJID", username); - settings_->storeBool("loginAutomatically", loginAutomatically); + settings_->storeSetting(SettingConstants::LAST_LOGIN_JID, username); + settings_->storeSetting(SettingConstants::LOGIN_AUTOMATICALLY, loginAutomatically); loginWindow_->addAvailableAccount(profileSettings_->getStringSetting("jid"), profileSettings_->getStringSetting("pass"), profileSettings_->getStringSetting("certificate")); } password_ = password; certificateFile_ = certificateFile; performLoginFromCachedCredentials(); } } void MainController::handlePurgeSavedLoginRequest(const std::string& username) { settings_->removeProfile(username); loginWindow_->removeAvailableAccount(username); } void MainController::performLoginFromCachedCredentials() { - if (eagleMode_ && password_.empty()) { + if (settings_->getSetting(SettingConstants::FORGET_PASSWORDS) && password_.empty()) { /* Then we can't try to login again. */ return; } /* If we logged in with a bare JID, and we have a full bound JID, re-login with the * bound JID to try and keep dynamically assigned resources */ JID clientJID = jid_; if (boundJID_.isValid() && jid_.isBare() && boundJID_.toBare() == jid_) { clientJID = boundJID_; } if (!statusTracker_) { statusTracker_ = new StatusTracker(); } if (!clientInitialized_) { storages_ = storagesFactory_->createStorages(jid_.toBare()); certificateStorage_ = certificateStorageFactory_->createCertificateStorage(jid_.toBare()); certificateTrustChecker_ = new CertificateStorageTrustChecker(certificateStorage_); client_ = boost::make_shared<Swift::Client>(clientJID, createSafeByteArray(password_.c_str()), networkFactories_, storages_); clientInitialized_ = true; client_->setCertificateTrustChecker(certificateTrustChecker_); client_->onDataRead.connect(boost::bind(&XMLConsoleController::handleDataRead, xmlConsoleController_, _1)); client_->onDataWritten.connect(boost::bind(&XMLConsoleController::handleDataWritten, xmlConsoleController_, _1)); client_->onDisconnected.connect(boost::bind(&MainController::handleDisconnected, this, _1)); client_->onConnected.connect(boost::bind(&MainController::handleConnected, this)); client_->setSoftwareVersion(CLIENT_NAME, buildVersion); client_->getVCardManager()->onVCardChanged.connect(boost::bind(&MainController::handleVCardReceived, this, _1, _2)); presenceNotifier_ = new PresenceNotifier(client_->getStanzaChannel(), notifier_, client_->getMUCRegistry(), client_->getAvatarManager(), client_->getNickResolver(), client_->getPresenceOracle(), networkFactories_->getTimerFactory()); presenceNotifier_->onNotificationActivated.connect(boost::bind(&MainController::handleNotificationClicked, this, _1)); eventNotifier_ = new EventNotifier(eventController_, notifier_, client_->getAvatarManager(), client_->getNickResolver()); eventNotifier_->onNotificationActivated.connect(boost::bind(&MainController::handleNotificationClicked, this, _1)); if (!certificateFile_.empty()) { client_->setCertificate(certificateFile_); } boost::shared_ptr<Presence> presence(new Presence()); presence->setShow(static_cast<StatusShow::Type>(profileSettings_->getIntSetting("lastShow", StatusShow::Online))); presence->setStatus(profileSettings_->getStringSetting("lastStatus")); statusTracker_->setRequestedPresence(presence); } else { /* In case we're in the middle of another login, make sure they don't overlap */ client_->disconnect(); } systemTrayController_->setConnecting(); if (rosterController_) { rosterController_->getWindow()->setConnecting(); } ClientOptions clientOptions; - clientOptions.forgetPassword = eagleMode_; - clientOptions.useTLS = eagleMode_ ? ClientOptions::RequireTLS : ClientOptions::UseTLSWhenAvailable; + bool eagle = settings_->getSetting(SettingConstants::FORGET_PASSWORDS); + clientOptions.forgetPassword = eagle; + clientOptions.useTLS = eagle ? ClientOptions::RequireTLS : ClientOptions::UseTLSWhenAvailable; /*if (clientJID.getDomain() == "doomsong.co.uk") { clientOptions.boshURL = URL("https", "channels.doomsong.co.uk", 11443, "http-bind/"); clientOptions.boshHTTPConnectProxyURL = URL("http", "squidproxy.doomsong.co.uk", 8123, ""); }*/ client_->connect(clientOptions); } void MainController::handleDisconnected(const boost::optional<ClientError>& error) { - if (eagleMode_) { + if (settings_->getSetting(SettingConstants::FORGET_PASSWORDS)) { purgeCachedCredentials(); } if (quitRequested_) { resetClient(); loginWindow_->quit(); } else if (error) { std::string message; std::string certificateErrorMessage; switch(error->getType()) { case ClientError::UnknownError: message = QT_TRANSLATE_NOOP("", "Unknown Error"); break; case ClientError::DomainNameResolveError: message = QT_TRANSLATE_NOOP("", "Unable to find server"); break; case ClientError::ConnectionError: message = QT_TRANSLATE_NOOP("", "Error connecting to server"); break; case ClientError::ConnectionReadError: message = QT_TRANSLATE_NOOP("", "Error while receiving server data"); break; case ClientError::ConnectionWriteError: message = QT_TRANSLATE_NOOP("", "Error while sending data to the server"); break; case ClientError::XMLError: message = QT_TRANSLATE_NOOP("", "Error parsing server data"); break; case ClientError::AuthenticationFailedError: message = QT_TRANSLATE_NOOP("", "Login/password invalid"); break; case ClientError::CompressionFailedError: message = QT_TRANSLATE_NOOP("", "Error while compressing stream"); break; case ClientError::ServerVerificationFailedError: message = QT_TRANSLATE_NOOP("", "Server verification failed"); break; case ClientError::NoSupportedAuthMechanismsError: message = QT_TRANSLATE_NOOP("", "Authentication mechanisms not supported"); break; case ClientError::UnexpectedElementError: message = QT_TRANSLATE_NOOP("", "Unexpected response"); break; case ClientError::ResourceBindError: message = QT_TRANSLATE_NOOP("", "Error binding resource"); break; case ClientError::SessionStartError: message = QT_TRANSLATE_NOOP("", "Error starting session"); break; case ClientError::StreamError: message = QT_TRANSLATE_NOOP("", "Stream error"); break; case ClientError::TLSError: message = QT_TRANSLATE_NOOP("", "Encryption error"); break; case ClientError::ClientCertificateLoadError: message = QT_TRANSLATE_NOOP("", "Error loading certificate (Invalid password?)"); break; case ClientError::ClientCertificateError: message = QT_TRANSLATE_NOOP("", "Certificate not authorized"); break; case ClientError::UnknownCertificateError: certificateErrorMessage = QT_TRANSLATE_NOOP("", "Unknown certificate"); break; case ClientError::CertificateExpiredError: certificateErrorMessage = QT_TRANSLATE_NOOP("", "Certificate has expired"); break; case ClientError::CertificateNotYetValidError: certificateErrorMessage = QT_TRANSLATE_NOOP("", "Certificate is not yet valid"); break; case ClientError::CertificateSelfSignedError: certificateErrorMessage = QT_TRANSLATE_NOOP("", "Certificate is self-signed"); break; case ClientError::CertificateRejectedError: certificateErrorMessage = QT_TRANSLATE_NOOP("", "Certificate has been rejected"); break; case ClientError::CertificateUntrustedError: certificateErrorMessage = QT_TRANSLATE_NOOP("", "Certificate is not trusted"); break; case ClientError::InvalidCertificatePurposeError: certificateErrorMessage = QT_TRANSLATE_NOOP("", "Certificate cannot be used for encrypting your connection"); break; case ClientError::CertificatePathLengthExceededError: certificateErrorMessage = QT_TRANSLATE_NOOP("", "Certificate path length constraint exceeded"); break; case ClientError::InvalidCertificateSignatureError: certificateErrorMessage = QT_TRANSLATE_NOOP("", "Invalid certificate signature"); break; case ClientError::InvalidCAError: certificateErrorMessage = QT_TRANSLATE_NOOP("", "Invalid Certificate Authority"); break; case ClientError::InvalidServerIdentityError: certificateErrorMessage = QT_TRANSLATE_NOOP("", "Certificate does not match the host identity"); break; } bool forceReconnectAfterCertificateTrust = false; if (!certificateErrorMessage.empty()) { Certificate::ref certificate = certificateTrustChecker_->getLastCertificate(); if (loginWindow_->askUserToTrustCertificatePermanently(certificateErrorMessage, certificate)) { certificateStorage_->addCertificate(certificate); forceReconnectAfterCertificateTrust = true; } else { message = QT_TRANSLATE_NOOP("", "Certificate error"); } } if (forceReconnectAfterCertificateTrust) { performLoginFromCachedCredentials(); } else if (!rosterController_) { //hasn't been logged in yet signOut(); loginWindow_->setMessage(message); loginWindow_->setIsLoggingIn(false); } else { logout(); - if (eagleMode_) { + if (settings_->getSetting(SettingConstants::FORGET_PASSWORDS)) { message = str(format(QT_TRANSLATE_NOOP("", "Disconnected from %1%: %2%. To reconnect, Sign Out and provide your password again.")) % jid_.getDomain() % message); } else { if (!offlineRequested_) { setReconnectTimer(); } if (lastDisconnectError_) { message = str(format(QT_TRANSLATE_NOOP("", "Reconnect to %1% failed: %2%. Will retry in %3% seconds.")) % jid_.getDomain() % message % boost::lexical_cast<std::string>(timeBeforeNextReconnect_)); lastDisconnectError_->conclude(); } else { message = str(format(QT_TRANSLATE_NOOP("", "Disconnected from %1%: %2%.")) % jid_.getDomain() % message); } lastDisconnectError_ = boost::shared_ptr<ErrorEvent>(new ErrorEvent(JID(jid_.getDomain()), message)); eventController_->handleIncomingEvent(lastDisconnectError_); } } } else if (!rosterController_) { //hasn't been logged in yet loginWindow_->setIsLoggingIn(false); } } void MainController::setReconnectTimer() { if (timeBeforeNextReconnect_ < 0) { timeBeforeNextReconnect_ = 1; } else { timeBeforeNextReconnect_ = timeBeforeNextReconnect_ >= 150 ? 300 : timeBeforeNextReconnect_ * 2; // Randomly selected by roll of a die, as required by 3920bis } if (reconnectTimer_) { reconnectTimer_->stop(); } reconnectTimer_ = networkFactories_->getTimerFactory()->createTimer(timeBeforeNextReconnect_ * 1000); reconnectTimer_->onTick.connect(boost::bind(&MainController::reconnectAfterError, this)); reconnectTimer_->start(); } void MainController::handleCancelLoginRequest() { signOut(); } void MainController::signOut() { - if (eagleMode_) { + if (settings_->getSetting(SettingConstants::FORGET_PASSWORDS)) { purgeCachedCredentials(); } eventController_->clear(); logout(); loginWindow_->loggedOut(); resetClient(); } void MainController::logout() { - if (eagleMode_) { + if (settings_->getSetting(SettingConstants::FORGET_PASSWORDS)) { purgeCachedCredentials(); } systemTrayController_->setMyStatusType(StatusShow::None); if (clientInitialized_ /*&& client_->isAvailable()*/) { client_->disconnect(); } if (rosterController_ && myStatusLooksOnline_) { rosterController_->getWindow()->setMyStatusType(StatusShow::None); rosterController_->getWindow()->setMyStatusText(""); myStatusLooksOnline_ = false; } setManagersOffline(); } void MainController::setManagersOffline() { if (chatsManager_) { chatsManager_->setOnline(false); } if (rosterController_) { rosterController_->setEnabled(false); } if (profileController_) { profileController_->setAvailable(false); } if (contactEditController_) { contactEditController_->setAvailable(false); } } void MainController::handleServerDiscoInfoResponse(boost::shared_ptr<DiscoInfo> info, ErrorPayload::ref error) { if (!error) { chatsManager_->setServerDiscoInfo(info); adHocManager_->setServerDiscoInfo(info); } } diff --git a/Swift/Controllers/MainController.h b/Swift/Controllers/MainController.h index 013f8bb..45e4ccf 100644 --- a/Swift/Controllers/MainController.h +++ b/Swift/Controllers/MainController.h @@ -1,37 +1,37 @@ /* - * Copyright (c) 2010-2011 Kevin Smith + * Copyright (c) 2010-2012 Kevin Smith * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. */ #pragma once #include <Swiften/Base/boost_bsignals.h> #include <boost/shared_ptr.hpp> #include <vector> #include "Swiften/Network/Timer.h" #include <string> #include "Swiften/Client/ClientError.h" #include "Swiften/JID/JID.h" #include "Swiften/Elements/DiscoInfo.h" #include "Swiften/Elements/VCard.h" #include "Swiften/Elements/ErrorPayload.h" #include "Swiften/Elements/Presence.h" #include "Swift/Controllers/Settings/SettingsProvider.h" #include "Swift/Controllers/ProfileSettingsProvider.h" #include "Swiften/Elements/CapsInfo.h" #include "Swift/Controllers/XMPPEvents/ErrorEvent.h" #include "Swift/Controllers/UIEvents/UIEvent.h" #include "Swiften/Client/ClientXMLTracer.h" namespace Swift { class IdleDetector; class UIFactory; class EventLoop; class Client; class ChatController; class ChatsManager; class CertificateStorageFactory; class CertificateStorage; class CertificateStorageTrustChecker; @@ -52,121 +52,119 @@ namespace Swift { class SoundEventController; class SoundPlayer; class XMLConsoleController; class FileTransferListController; class UIEventStream; class EventWindowFactory; class EventWindowController; class MUCSearchController; class UserSearchController; class StatusTracker; class Dock; class Storages; class StoragesFactory; class NetworkFactories; class URIHandler; class XMPPURIController; class AdHocManager; class AdHocCommandWindowFactory; class FileTransferOverview; class MainController { public: MainController( EventLoop* eventLoop, NetworkFactories* networkFactories, UIFactory* uiFactories, SettingsProvider *settings, SystemTray* systemTray, SoundPlayer* soundPlayer, StoragesFactory* storagesFactory, CertificateStorageFactory* certificateStorageFactory, Dock* dock, Notifier* notifier, URIHandler* uriHandler, IdleDetector* idleDetector, - bool useDelayForLatency, - bool eagleMode); + bool useDelayForLatency); ~MainController(); private: void resetClient(); void handleConnected(); void handleLoginRequest(const std::string& username, const std::string& password, const std::string& certificateFile, bool remember, bool loginAutomatically); void handleCancelLoginRequest(); void handleQuitRequest(); void handleChangeStatusRequest(StatusShow::Type show, const std::string &statusText); void handleDisconnected(const boost::optional<ClientError>& error); void handleServerDiscoInfoResponse(boost::shared_ptr<DiscoInfo>, ErrorPayload::ref); void handleEventQueueLengthChange(int count); void handleVCardReceived(const JID& j, VCard::ref vCard); - void handleUIEvent(boost::shared_ptr<UIEvent> event); + void handleSettingChanged(const std::string& settingPath); void handlePurgeSavedLoginRequest(const std::string& username); void sendPresence(boost::shared_ptr<Presence> presence); void handleInputIdleChanged(bool); void logout(); void signOut(); void setReconnectTimer(); void resetPendingReconnects(); void resetCurrentError(); void performLoginFromCachedCredentials(); void reconnectAfterError(); void setManagersOffline(); void handleNotificationClicked(const JID& jid); void handleForceQuit(); void purgeCachedCredentials(); private: EventLoop* eventLoop_; NetworkFactories* networkFactories_; UIFactory* uiFactory_; StoragesFactory* storagesFactory_; Storages* storages_; CertificateStorageFactory* certificateStorageFactory_; CertificateStorage* certificateStorage_; CertificateStorageTrustChecker* certificateTrustChecker_; bool clientInitialized_; boost::shared_ptr<Client> client_; SettingsProvider *settings_; ProfileSettingsProvider* profileSettings_; Dock* dock_; URIHandler* uriHandler_; IdleDetector* idleDetector_; TogglableNotifier* notifier_; PresenceNotifier* presenceNotifier_; EventNotifier* eventNotifier_; RosterController* rosterController_; EventController* eventController_; EventWindowController* eventWindowController_; AdHocManager* adHocManager_; LoginWindow* loginWindow_; UIEventStream* uiEventStream_; XMLConsoleController* xmlConsoleController_; FileTransferListController* fileTransferListController_; ChatsManager* chatsManager_; ProfileController* profileController_; ContactEditController* contactEditController_; JID jid_; JID boundJID_; SystemTrayController* systemTrayController_; SoundEventController* soundEventController_; XMPPURIController* xmppURIController_; std::string vCardPhotoHash_; std::string password_; std::string certificateFile_; boost::shared_ptr<ErrorEvent> lastDisconnectError_; bool useDelayForLatency_; UserSearchController* userSearchControllerChat_; UserSearchController* userSearchControllerAdd_; int timeBeforeNextReconnect_; Timer::ref reconnectTimer_; StatusTracker* statusTracker_; bool myStatusLooksOnline_; bool quitRequested_; bool offlineRequested_; static const int SecondsToWaitBeforeForceQuitting; - bool eagleMode_; FileTransferOverview* ftOverview_; }; } diff --git a/Swift/Controllers/ProfileSettingsProvider.cpp b/Swift/Controllers/ProfileSettingsProvider.cpp new file mode 100644 index 0000000..c1b4b13 --- /dev/null +++ b/Swift/Controllers/ProfileSettingsProvider.cpp @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2010-2012 Kevin Smith + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#include "Swift/Controllers/ProfileSettingsProvider.h" + +namespace Swift { + +ProfileSettingsProvider::ProfileSettingsProvider(const std::string& profile, SettingsProvider* provider) : + profile_(profile) { + provider_ = provider; + bool found = false; + foreach (std::string existingProfile, provider->getAvailableProfiles()) { + if (existingProfile == profile) { + found = true; + } + } + if (!found) { + provider_->createProfile(profile); + } +} + +ProfileSettingsProvider::~ProfileSettingsProvider() { +} + +std::string ProfileSettingsProvider::getStringSetting(const std::string &settingPath) { + //FIXME: Remove shim + SettingsProvider::Setting<std::string> setting(profileSettingPath(settingPath), ""); + return provider_->getSetting(setting); +} + +void ProfileSettingsProvider::storeString(const std::string &settingPath, const std::string &settingValue) { + //FIXME: Remove shim + if (!getIsSettingFinal(settingPath)) { + SettingsProvider::Setting<std::string> setting(profileSettingPath(settingPath), ""); + provider_->storeSetting(setting, settingValue); + } +} + +int ProfileSettingsProvider::getIntSetting(const std::string& settingPath, int defaultValue) { + //FIXME: Remove shim + SettingsProvider::Setting<int> setting(profileSettingPath(settingPath), defaultValue); + return provider_->getSetting(setting); +} +void ProfileSettingsProvider::storeInt(const std::string& settingPath, int settingValue) { + //FIXME: Remove shim + if (!getIsSettingFinal(settingPath)) { + SettingsProvider::Setting<int> setting(profileSettingPath(settingPath), 0); + provider_->storeSetting(setting, settingValue); + } +} + +bool ProfileSettingsProvider::getIsSettingFinal(const std::string& settingPath) { + //FIXME: Remove shim + SettingsProvider::Setting<int> setting(settingPath, 0); + return provider_->getIsSettingFinal(setting); +} + + +std::string ProfileSettingsProvider::profileSettingPath(const std::string &settingPath) { + return profile_ + ":" + settingPath; +} + + +} + diff --git a/Swift/Controllers/ProfileSettingsProvider.h b/Swift/Controllers/ProfileSettingsProvider.h index 8ba250c..ebc515a 100644 --- a/Swift/Controllers/ProfileSettingsProvider.h +++ b/Swift/Controllers/ProfileSettingsProvider.h @@ -1,42 +1,33 @@ /* - * Copyright (c) 2010 Kevin Smith + * Copyright (c) 2010-2012 Kevin Smith * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. */ #pragma once -#include "Swift/Controllers/Settings/SettingsProvider.h" +#include <Swift/Controllers/Settings/SettingsProvider.h> #include <Swiften/Base/foreach.h> namespace Swift { class ProfileSettingsProvider { public: - ProfileSettingsProvider(const std::string& profile, SettingsProvider* provider) : profile_(profile) { - provider_ = provider; - bool found = false; - foreach (std::string existingProfile, provider->getAvailableProfiles()) { - if (existingProfile == profile) { - found = true; - } - } - if (!found) { - provider_->createProfile(profile); - } - }; - virtual ~ProfileSettingsProvider() {}; - virtual std::string getStringSetting(const std::string &settingPath) {return provider_->getStringSetting(profileSettingPath(settingPath));}; - virtual void storeString(const std::string &settingPath, const std::string &settingValue) {provider_->storeString(profileSettingPath(settingPath), settingValue);}; - virtual int getIntSetting(const std::string& settingPath, int defaultValue) {return provider_->getIntSetting(settingPath, defaultValue);} - virtual void storeInt(const std::string& settingPath, int settingValue) {provider_->storeInt(settingPath, settingValue);} + ProfileSettingsProvider(const std::string& profile, SettingsProvider* provider); + virtual ~ProfileSettingsProvider(); + virtual std::string getStringSetting(const std::string &settingPath); + virtual void storeString(const std::string &settingPath, const std::string &settingValue); + virtual int getIntSetting(const std::string& settingPath, int defaultValue); + virtual void storeInt(const std::string& settingPath, int settingValue); + /** See @SettingsProvider::getIsSettingFinal for discussion of what this means.*/ + virtual bool getIsSettingFinal(const std::string& settingPath); private: - std::string profileSettingPath(const std::string &settingPath) {return profile_ + ":" + settingPath;}; + std::string profileSettingPath(const std::string &settingPath); SettingsProvider* provider_; std::string profile_; }; } diff --git a/Swift/Controllers/Roster/RosterController.cpp b/Swift/Controllers/Roster/RosterController.cpp index 66948c1..d3a00dd 100644 --- a/Swift/Controllers/Roster/RosterController.cpp +++ b/Swift/Controllers/Roster/RosterController.cpp @@ -1,223 +1,224 @@ /* - * Copyright (c) 2010 Kevin Smith + * Copyright (c) 2010-2012 Kevin Smith * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. */ #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/ToggleShowOfflineUIEvent.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/format.h> #include <Swiften/Elements/DiscoInfo.h> #include <Swiften/Disco/EntityCapsManager.h> #include <Swiften/Jingle/JingleSessionManager.h> +#include <Swift/Controllers/SettingConstants.h> namespace Swift { -static const std::string SHOW_OFFLINE = "showOffline"; - /** * 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) : 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) { assert(fileTransferOverview); iqRouter_ = iqRouter; presenceOracle_ = presenceOracle; subscriptionManager_ = subscriptionManager; eventController_ = eventController; settings_ = settings; expandiness_ = new RosterGroupExpandinessPersister(roster_, settings); roster_->addFilter(offlineFilter_); mainWindow_->setRosterModel(roster_); 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; avatarManager_->onAvatarChanged.connect(boost::bind(&RosterController::handleAvatarChanged, this, _1)); mainWindow_->setMyAvatarPath(avatarManager_->getAvatarPath(myJID_).string()); 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)); - if (settings->getBoolSetting(SHOW_OFFLINE, false)) { - uiEventStream->onUIEvent(boost::shared_ptr<UIEvent>(new ToggleShowOfflineUIEvent(true))); - } + settings_->onSettingChanged.connect(boost::bind(&RosterController::handleSettingChanged, this, _1)); + } 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 roster_; } void RosterController::setEnabled(bool enabled) { if (!enabled) { roster_->applyOnItems(AppearOffline()); } } void RosterController::handleShowOfflineToggled(bool state) { - if (state != settings_->getBoolSetting(SHOW_OFFLINE, false)) { - settings_->storeBool(SHOW_OFFLINE, state); + if (state != settings_->getSetting(SettingConstants::SHOW_OFFLINE)) { + settings_->storeSetting(SettingConstants::SHOW_OFFLINE, state); } if (state) { roster_->removeFilter(offlineFilter_); } else { roster_->addFilter(offlineFilter_); } } void RosterController::handleChangeStatusRequest(StatusShow::Type show, const std::string &statusText) { onChangeStatusRequest(show, statusText); } void RosterController::handleOnJIDAdded(const JID& jid) { std::vector<std::string> groups = xmppRoster_->getGroupsForJID(jid); std::string name = nickResolver_->jidToNick(jid); if (!groups.empty()) { foreach(const std::string& group, groups) { roster_->addContact(jid, jid, name, group, avatarManager_->getAvatarPath(jid).string()); } } else { roster_->addContact(jid, jid, name, QT_TRANSLATE_NOOP("", "Contacts"), avatarManager_->getAvatarPath(jid).string()); } applyAllPresenceTo(jid); } void RosterController::applyAllPresenceTo(const JID& jid) { foreach (Presence::ref presence, presenceOracle_->getAllPresence(jid)) { roster_->applyOnItems(SetPresence(presence)); } } void RosterController::handleRosterCleared() { roster_->removeAll(); } void RosterController::handleOnJIDRemoved(const JID& jid) { roster_->removeContact(jid); } void RosterController::handleOnJIDUpdated(const JID& jid, const std::string& oldName, const std::vector<std::string>& passedOldGroups) { if (oldName != xmppRoster_->getNameForJID(jid)) { roster_->applyOnItems(SetName(nickResolver_->jidToNick(jid), jid)); } std::vector<std::string> groups = xmppRoster_->getGroupsForJID(jid); std::vector<std::string> oldGroups = passedOldGroups; std::string name = nickResolver_->jidToNick(jid); std::string contactsGroup = QT_TRANSLATE_NOOP("", "Contacts"); if (oldGroups.empty()) { oldGroups.push_back(contactsGroup); } if (groups.empty()) { groups.push_back(contactsGroup); } foreach(const std::string& group, groups) { if (std::find(oldGroups.begin(), oldGroups.end(), group) == oldGroups.end()) { roster_->addContact(jid, jid, name, group, avatarManager_->getAvatarPath(jid).string()); } } foreach(const std::string& group, oldGroups) { if (std::find(groups.begin(), groups.end(), group) == groups.end()) { roster_->removeContactFromGroup(jid, group); if (roster_->getGroup(group)->getChildren().size() == 0) { roster_->removeGroup(group); } } } applyAllPresenceTo(jid); } -void RosterController::handleUIEvent(boost::shared_ptr<UIEvent> event) { - if (boost::shared_ptr<ToggleShowOfflineUIEvent> showOfflineEvent = boost::dynamic_pointer_cast<ToggleShowOfflineUIEvent>(event)) { - handleShowOfflineToggled(showOfflineEvent->getShow()); +void RosterController::handleSettingChanged(const std::string& settingPath) { + if (settingPath == SettingConstants::SHOW_OFFLINE.getKey()) { + handleShowOfflineToggled(settings_->getSetting(SettingConstants::SHOW_OFFLINE)); } - else if (boost::shared_ptr<AddContactUIEvent> addContactEvent = boost::dynamic_pointer_cast<AddContactUIEvent>(event)) { +} + +void RosterController::handleUIEvent(boost::shared_ptr<UIEvent> event) { + if (boost::shared_ptr<AddContactUIEvent> addContactEvent = boost::dynamic_pointer_cast<AddContactUIEvent>(event)) { RosterItemPayload item; item.setName(addContactEvent->getName()); item.setJID(addContactEvent->getJID()); item.setGroups(std::vector<std::string>(addContactEvent->getGroups().begin(), addContactEvent->getGroups().end())); boost::shared_ptr<RosterPayload> roster(new RosterPayload()); roster->addItem(item); SetRosterRequest::ref request = SetRosterRequest::create(roster, iqRouter_); request->onResponse.connect(boost::bind(&RosterController::handleRosterSetError, this, _1, roster)); request->send(); subscriptionManager_->requestSubscription(addContactEvent->getJID()); } else if (boost::shared_ptr<RemoveRosterItemUIEvent> removeEvent = boost::dynamic_pointer_cast<RemoveRosterItemUIEvent>(event)) { RosterItemPayload item(removeEvent->getJID(), "", RosterItemPayload::Remove); boost::shared_ptr<RosterPayload> roster(new RosterPayload()); roster->addItem(item); SetRosterRequest::ref request = SetRosterRequest::create(roster, iqRouter_); request->onResponse.connect(boost::bind(&RosterController::handleRosterSetError, this, _1, roster)); request->send(); } else if (boost::shared_ptr<RenameRosterItemUIEvent> renameEvent = boost::dynamic_pointer_cast<RenameRosterItemUIEvent>(event)) { JID contact(renameEvent->getJID()); RosterItemPayload item(contact, renameEvent->getNewName(), xmppRoster_->getSubscriptionStateForJID(contact)); item.setGroups(xmppRoster_->getGroupsForJID(contact)); boost::shared_ptr<RosterPayload> roster(new RosterPayload()); roster->addItem(item); SetRosterRequest::ref request = SetRosterRequest::create(roster, iqRouter_); request->onResponse.connect(boost::bind(&RosterController::handleRosterSetError, this, _1, roster)); request->send(); } else if (boost::shared_ptr<RenameGroupUIEvent> renameGroupEvent = boost::dynamic_pointer_cast<RenameGroupUIEvent>(event)) { std::vector<XMPPRosterItem> items = xmppRoster_->getItems(); std::string group = renameGroupEvent->getGroup(); // FIXME: We should handle contacts groups specially to avoid clashes if (group == QT_TRANSLATE_NOOP("", "Contacts")) { diff --git a/Swift/Controllers/Roster/RosterController.h b/Swift/Controllers/Roster/RosterController.h index 66748ca..5e40124 100644 --- a/Swift/Controllers/Roster/RosterController.h +++ b/Swift/Controllers/Roster/RosterController.h @@ -42,60 +42,61 @@ namespace Swift { 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); ~RosterController(); void showRosterWindow(); MainWindow* getWindow() {return mainWindow_;}; boost::signal<void (StatusShow::Type, const std::string&)> onChangeStatusRequest; boost::signal<void ()> onSignOutRequest; void handleAvatarChanged(const JID& jid); 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&); 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); JID myJID_; XMPPRoster* xmppRoster_; MainWindowFactory* mainWindowFactory_; MainWindow* mainWindow_; Roster* roster_; OfflineRosterFilter* offlineFilter_; AvatarManager* avatarManager_; NickManager* nickManager_; NickResolver* nickResolver_; PresenceOracle* presenceOracle_; SubscriptionManager* subscriptionManager_; EventController* eventController_; RosterGroupExpandinessPersister* expandiness_; IQRouter* iqRouter_; SettingsProvider* settings_; UIEventStream* uiEventStream_; EntityCapsProvider* entityCapsManager_; FileTransferOverview* ftOverview_; boost::bsignals::scoped_connection changeStatusConnection_; boost::bsignals::scoped_connection signOutConnection_; boost::bsignals::scoped_connection uiEventConnection_; }; } diff --git a/Swift/Controllers/Roster/RosterGroupExpandinessPersister.cpp b/Swift/Controllers/Roster/RosterGroupExpandinessPersister.cpp index 0a242ae..81f0c12 100644 --- a/Swift/Controllers/Roster/RosterGroupExpandinessPersister.cpp +++ b/Swift/Controllers/Roster/RosterGroupExpandinessPersister.cpp @@ -1,62 +1,63 @@ /* - * Copyright (c) 2010 Kevin Smith + * Copyright (c) 2010-2012 Kevin Smith * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. */ -#include "RosterGroupExpandinessPersister.h" +#include <Swift/Controllers/Roster/RosterGroupExpandinessPersister.h> #include <boost/bind.hpp> #include <vector> #include <Swiften/Base/foreach.h> -#include "Swiften/Base/String.h" -#include "Swift/Controllers/Roster/GroupRosterItem.h" +#include <Swiften/Base/String.h> +#include <Swift/Controllers/Roster/GroupRosterItem.h> +#include <Swift/Controllers/SettingConstants.h> namespace Swift { RosterGroupExpandinessPersister::RosterGroupExpandinessPersister(Roster* roster, SettingsProvider* settings) : roster_(roster), settings_(settings) { load(); roster_->onGroupAdded.connect(boost::bind(&RosterGroupExpandinessPersister::handleGroupAdded, this, _1)); } void RosterGroupExpandinessPersister::handleGroupAdded(GroupRosterItem* group) { if (collapsed_.find(group->getDisplayName()) != collapsed_.end()) { group->setExpanded(false); } else { group->setExpanded(true); } group->onExpandedChanged.connect(boost::bind(&RosterGroupExpandinessPersister::handleExpandedChanged, this, group, _1)); } void RosterGroupExpandinessPersister::handleExpandedChanged(GroupRosterItem* group, bool expanded) { if (expanded) { std::string displayName = group->getDisplayName(); //collapsed_.erase(std::remove(collapsed_.begin(), collapsed_.end(), displayName), collapsed_.end()); collapsed_.erase(displayName); } else { collapsed_.insert(group->getDisplayName()); } save(); } void RosterGroupExpandinessPersister::save() { std::string setting; foreach (const std::string& group, collapsed_) { if (!setting.empty()) { setting += "\n"; } setting += group; } - settings_->storeString(SettingPath, setting); + settings_->storeSetting(SettingConstants::EXPANDED_ROSTER_GROUPS, setting); } void RosterGroupExpandinessPersister::load() { - std::string saved = settings_->getStringSetting(SettingPath); + std::string saved = settings_->getSetting(SettingConstants::EXPANDED_ROSTER_GROUPS); std::vector<std::string> collapsed = String::split(saved, '\n'); collapsed_.insert(collapsed.begin(), collapsed.end()); } -const std::string RosterGroupExpandinessPersister::SettingPath = "GroupExpandiness"; + } diff --git a/Swift/Controllers/Roster/RosterGroupExpandinessPersister.h b/Swift/Controllers/Roster/RosterGroupExpandinessPersister.h index 63affe4..73c4f29 100644 --- a/Swift/Controllers/Roster/RosterGroupExpandinessPersister.h +++ b/Swift/Controllers/Roster/RosterGroupExpandinessPersister.h @@ -1,27 +1,26 @@ /* - * Copyright (c) 2010 Kevin Smith + * Copyright (c) 2010-2012 Kevin Smith * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. */ #pragma once #include <set> #include "Swift/Controllers/Roster/Roster.h" #include "Swift/Controllers/Settings/SettingsProvider.h" namespace Swift { class RosterGroupExpandinessPersister { public: RosterGroupExpandinessPersister(Roster* roster, SettingsProvider* settings); private: void handleExpandedChanged(GroupRosterItem* group, bool expanded); void handleGroupAdded(GroupRosterItem* group); void load(); void save(); std::set<std::string> collapsed_; Roster* roster_; SettingsProvider* settings_; - static const std::string SettingPath; }; } diff --git a/Swift/Controllers/SConscript b/Swift/Controllers/SConscript index e48f382..02e212b 100644 --- a/Swift/Controllers/SConscript +++ b/Swift/Controllers/SConscript @@ -22,62 +22,66 @@ if env["SCONS_STAGE"] == "build" : myenv.MergeFlags(env["BOOST_FLAGS"]) myenv.StaticLibrary("SwiftControllers", [ "Chat/ChatController.cpp", "Chat/ChatControllerBase.cpp", "Chat/ChatsManager.cpp", "Chat/MUCController.cpp", "Chat/MUCSearchController.cpp", "Chat/UserSearchController.cpp", "MainController.cpp", "ProfileController.cpp", "ContactEditController.cpp", "FileTransfer/FileTransferController.cpp", "FileTransfer/FileTransferOverview.cpp", "FileTransfer/FileTransferProgressInfo.cpp", "Roster/RosterController.cpp", "Roster/RosterGroupExpandinessPersister.cpp", "Roster/ContactRosterItem.cpp", "Roster/GroupRosterItem.cpp", "Roster/RosterItem.cpp", "Roster/Roster.cpp", "Roster/TableRoster.cpp", "EventWindowController.cpp", "SoundEventController.cpp", "SystemTrayController.cpp", "XMLConsoleController.cpp", "FileTransferListController.cpp", "StatusTracker.cpp", "PresenceNotifier.cpp", "EventNotifier.cpp", "AdHocManager.cpp", "XMPPEvents/EventController.cpp", "UIEvents/UIEvent.cpp", "UIInterfaces/XMLConsoleWidget.cpp", "UIInterfaces/ChatListWindow.cpp", "PreviousStatusStore.cpp", + "ProfileSettingsProvider.cpp", + "Settings/SettingsProviderHierachy.cpp", + "Settings/XMLSettingsProvider.cpp", "Storages/CertificateStorageFactory.cpp", "Storages/CertificateStorage.cpp", "Storages/CertificateFileStorage.cpp", "Storages/CertificateMemoryStorage.cpp", "Storages/AvatarFileStorage.cpp", "Storages/FileStorages.cpp", "Storages/RosterFileStorage.cpp", "Storages/CapsFileStorage.cpp", "Storages/VCardFileStorage.cpp", "StatusUtil.cpp", "Translator.cpp", "XMPPURIController.cpp", "ChatMessageSummarizer.cpp", + "SettingConstants.cpp" ]) env.Append(UNITTEST_SOURCES = [ File("Roster/UnitTest/RosterControllerTest.cpp"), File("Roster/UnitTest/RosterTest.cpp"), File("Roster/UnitTest/LeastCommonSubsequenceTest.cpp"), File("Roster/UnitTest/TableRosterTest.cpp"), File("UnitTest/PreviousStatusStoreTest.cpp"), File("UnitTest/PresenceNotifierTest.cpp"), File("Chat/UnitTest/ChatsManagerTest.cpp"), File("Chat/UnitTest/MUCControllerTest.cpp"), File("UnitTest/MockChatWindow.cpp"), File("UnitTest/ChatMessageSummarizerTest.cpp"), ]) diff --git a/Swift/Controllers/SettingConstants.cpp b/Swift/Controllers/SettingConstants.cpp new file mode 100644 index 0000000..7ab4ac4 --- /dev/null +++ b/Swift/Controllers/SettingConstants.cpp @@ -0,0 +1,22 @@ +/* + * Copyright (c) 2012 Kevin Smith + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#include <Swift/Controllers/SettingConstants.h> + +namespace Swift { + +const SettingsProvider::Setting<bool> SettingConstants::IDLE_GOES_OFFLINE = SettingsProvider::Setting<bool>("idleGoesOffline", false); +const SettingsProvider::Setting<int> SettingConstants::IDLE_TIMEOUT = SettingsProvider::Setting<int>("idleTimeout", 600); +const SettingsProvider::Setting<bool> SettingConstants::SHOW_NOTIFICATIONS = SettingsProvider::Setting<bool>("showNotifications", true); +const SettingsProvider::Setting<bool> SettingConstants::REQUEST_DELIVERYRECEIPTS = SettingsProvider::Setting<bool>("requestDeliveryReceipts", false); +const SettingsProvider::Setting<bool> SettingConstants::FORGET_PASSWORDS = SettingsProvider::Setting<bool>("forgetPasswords", false); +const SettingsProvider::Setting<bool> SettingConstants::REMEMBER_RECENT_CHATS = SettingsProvider::Setting<bool>("rememberRecentChats", true); +const SettingsProvider::Setting<std::string> SettingConstants::LAST_LOGIN_JID = SettingsProvider::Setting<std::string>("lastLoginJID", ""); +const SettingsProvider::Setting<bool> SettingConstants::LOGIN_AUTOMATICALLY = SettingsProvider::Setting<bool>("loginAutomatically", false); +const SettingsProvider::Setting<bool> SettingConstants::SHOW_OFFLINE("showOffline", false); +const SettingsProvider::Setting<std::string> SettingConstants::EXPANDED_ROSTER_GROUPS("GroupExpandiness", ""); +const SettingsProvider::Setting<bool> SettingConstants::PLAY_SOUNDS("playSounds", true); +} diff --git a/Swift/Controllers/SettingConstants.h b/Swift/Controllers/SettingConstants.h new file mode 100644 index 0000000..ff1ed72 --- /dev/null +++ b/Swift/Controllers/SettingConstants.h @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2012 Kevin Smith + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma once + +#include <Swift/Controllers/Settings/SettingsProvider.h> + +namespace Swift { + class SettingConstants { + public: + static const SettingsProvider::Setting<bool> IDLE_GOES_OFFLINE; + static const SettingsProvider::Setting<int> IDLE_TIMEOUT; + static const SettingsProvider::Setting<bool> SHOW_NOTIFICATIONS; + static const SettingsProvider::Setting<bool> REQUEST_DELIVERYRECEIPTS; + static const SettingsProvider::Setting<bool> FORGET_PASSWORDS; + static const SettingsProvider::Setting<bool> REMEMBER_RECENT_CHATS; + static const SettingsProvider::Setting<std::string> LAST_LOGIN_JID; + static const SettingsProvider::Setting<bool> LOGIN_AUTOMATICALLY; + static const SettingsProvider::Setting<bool> SHOW_OFFLINE; + static const SettingsProvider::Setting<std::string> EXPANDED_ROSTER_GROUPS; + static const SettingsProvider::Setting<bool> PLAY_SOUNDS; + }; +} diff --git a/Swift/Controllers/Settings/DummySettingsProvider.h b/Swift/Controllers/Settings/DummySettingsProvider.h index 90e1921..bb7d2e6 100644 --- a/Swift/Controllers/Settings/DummySettingsProvider.h +++ b/Swift/Controllers/Settings/DummySettingsProvider.h @@ -1,30 +1,52 @@ /* * 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/Settings/SettingsProvider.h" +#include <Swift/Controllers/Settings/SettingsProvider.h> + +#include <map> namespace Swift { class DummySettingsProvider : public SettingsProvider { public: virtual ~DummySettingsProvider() {} - virtual std::string getStringSetting(const std::string&) {return "";} - virtual void storeString(const std::string &, const std::string &) {} - virtual bool getBoolSetting(const std::string &, bool ) {return true;} - virtual void storeBool(const std::string &, bool ) {} - virtual int getIntSetting(const std::string &, int ) {return 0;} - virtual void storeInt(const std::string &, int ) {} + virtual std::string getSetting(const Setting<std::string>& setting) { + return stringValues.find(setting.getKey()) != stringValues.end() ? stringValues[setting.getKey()] : setting.getDefaultValue(); + }; + virtual void storeSetting(const Setting<std::string>& setting, const std::string& value) { + stringValues[setting.getKey()] = value; + onSettingChanged(setting.getKey()); + }; + virtual bool getSetting(const Setting<bool>& setting) { + return boolValues.find(setting.getKey()) != boolValues.end() ? boolValues[setting.getKey()] : setting.getDefaultValue(); + }; + virtual void storeSetting(const Setting<bool>& setting, const bool& value) { + boolValues[setting.getKey()] = value; + onSettingChanged(setting.getKey()); + }; + virtual int getSetting(const Setting<int>& setting) { + return intValues.find(setting.getKey()) != intValues.end() ? intValues[setting.getKey()] : setting.getDefaultValue(); + }; + virtual void storeSetting(const Setting<int>& setting, const int& value) { + intValues[setting.getKey()] = value; + onSettingChanged(setting.getKey()); + }; virtual std::vector<std::string> getAvailableProfiles() {return std::vector<std::string>();} virtual void createProfile(const std::string& ) {} virtual void removeProfile(const std::string& ) {} + virtual bool getIsSettingFinal(const std::string& ) {return false;} + private: + std::map<std::string, std::string> stringValues; + std::map<std::string, int> intValues; + std::map<std::string, bool> boolValues; }; } diff --git a/Swift/Controllers/Settings/SettingsProvider.h b/Swift/Controllers/Settings/SettingsProvider.h index a5ff4eb..e884add 100644 --- a/Swift/Controllers/Settings/SettingsProvider.h +++ b/Swift/Controllers/Settings/SettingsProvider.h @@ -1,33 +1,73 @@ /* - * Copyright (c) 2010 Remko Tronçon + * Copyright (c) 2010-2012 Remko Tronçon * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. */ -#ifndef SWIFTEN_SettingsProvider_H -#define SWIFTEN_SettingsProvider_H +#pragma once -#include <string> +#include <Swiften/Base/boost_bsignals.h> +#include <string> #include <vector> namespace Swift { class SettingsProvider { + + public: + template <typename T> + class Setting { + public: + Setting(const std::string& key, const T& defaultValue) : key(key), defaultValue(defaultValue) { + + } + + const std::string& getKey() const { + return key; + } + + const T& getDefaultValue() const { + return defaultValue; + } + + private: + std::string key; + T defaultValue; + }; + public: virtual ~SettingsProvider() {} - virtual std::string getStringSetting(const std::string &settingPath) = 0; - virtual void storeString(const std::string &settingPath, const std::string &settingValue) = 0; - virtual bool getBoolSetting(const std::string &settingPath, bool defaultValue) = 0; - virtual void storeBool(const std::string &settingPath, bool settingValue) = 0; - virtual int getIntSetting(const std::string &settingPath, int defaultValue) = 0; - virtual void storeInt(const std::string &settingPath, int settingValue) = 0; + virtual std::string getSetting(const Setting<std::string>& setting) = 0; + virtual void storeSetting(const Setting<std::string>& setting, const std::string& value) = 0; + virtual bool getSetting(const Setting<bool>& setting) = 0; + virtual void storeSetting(const Setting<bool>& setting, const bool& value) = 0; + virtual int getSetting(const Setting<int>& setting) = 0; + virtual void storeSetting(const Setting<int>& setting, const int& value) = 0; + virtual std::vector<std::string> getAvailableProfiles() = 0; virtual void createProfile(const std::string& profile) = 0; virtual void removeProfile(const std::string& profile) = 0; + /** A final setting is one that this settings provider says may not be overriden by lower priority profiles. + * e.g. An Administrator-set configuration to disallow saving user passwords could not be overridden by the user. + */ + template<typename T> + bool getIsSettingFinal(const Setting<T>& setting) { + return getIsSettingFinal(setting.getKey()); + } + + friend class SettingsProviderHierachy; + protected: + virtual bool getIsSettingFinal(const std::string& settingPath) = 0; + + public: + /** + * Emitted when a setting is changed. + */ + boost::signal<void (const std::string& /*Setting's Path*/)> onSettingChanged; }; } -#endif + diff --git a/Swift/Controllers/Settings/SettingsProviderHierachy.cpp b/Swift/Controllers/Settings/SettingsProviderHierachy.cpp new file mode 100644 index 0000000..3b7d13c --- /dev/null +++ b/Swift/Controllers/Settings/SettingsProviderHierachy.cpp @@ -0,0 +1,95 @@ +/* + * Copyright (c) 2012 Kevin Smith + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#include <Swift/Controllers/Settings/SettingsProviderHierachy.h> + +#include <Swiften/Base/foreach.h> +#include <Swiften/Base/Log.h> +namespace Swift { + +SettingsProviderHierachy::~SettingsProviderHierachy() { +} + +std::string SettingsProviderHierachy::getSetting(const Setting<std::string>& setting) { + foreach (SettingsProvider* provider, providers_) { + std::string providerSetting = provider->getSetting(setting); + if (providerSetting != setting.getDefaultValue()) { + return providerSetting; + } + } + return setting.getDefaultValue(); +} + +void SettingsProviderHierachy::storeSetting(const Setting<std::string>& setting, const std::string& settingValue) { + if (!getIsSettingFinal(setting.getKey())) { + getWritableProvider()->storeSetting(setting, settingValue); + } +} + +bool SettingsProviderHierachy::getSetting(const Setting<bool>& setting) { + foreach (SettingsProvider* provider, providers_) { + bool providerSetting = provider->getSetting(setting); + if (providerSetting != setting.getDefaultValue()) { + return providerSetting; + } + } + return setting.getDefaultValue(); +} + +void SettingsProviderHierachy::storeSetting(const Setting<bool>& setting, const bool& settingValue) { + if (!getIsSettingFinal(setting.getKey())) { + getWritableProvider()->storeSetting(setting, settingValue); + } +} + +int SettingsProviderHierachy::getSetting(const Setting<int>& setting) { + foreach (SettingsProvider* provider, providers_) { + int providerSetting = provider->getSetting(setting); + if (providerSetting != setting.getDefaultValue()) { + return providerSetting; + } + } + return setting.getDefaultValue(); +} + +void SettingsProviderHierachy::storeSetting(const Setting<int>& setting, const int& settingValue) { + if (!getIsSettingFinal(setting.getKey())) { + getWritableProvider()->storeSetting(setting, settingValue); + } +} + +std::vector<std::string> SettingsProviderHierachy::getAvailableProfiles() { + /* Always pull profiles from the topmost */ + return getWritableProvider()->getAvailableProfiles(); +} + +void SettingsProviderHierachy::createProfile(const std::string& profile) { + return getWritableProvider()->createProfile(profile); +} + +void SettingsProviderHierachy::removeProfile(const std::string& profile) { + return getWritableProvider()->removeProfile(profile); +} + +bool SettingsProviderHierachy::getIsSettingFinal(const std::string& settingPath) { + bool isFinal = false; + foreach (SettingsProvider* provider, providers_) { + isFinal |= provider->getIsSettingFinal(settingPath); + } + return isFinal; +} + +SettingsProvider* SettingsProviderHierachy::getWritableProvider() { + return providers_.back(); +} + +void SettingsProviderHierachy::addProviderToTopOfStack(SettingsProvider* provider) { + providers_.push_back(provider); + provider->onSettingChanged.connect(onSettingChanged); +} + +} + diff --git a/Swift/Controllers/Settings/SettingsProviderHierachy.h b/Swift/Controllers/Settings/SettingsProviderHierachy.h new file mode 100644 index 0000000..b7f6961 --- /dev/null +++ b/Swift/Controllers/Settings/SettingsProviderHierachy.h @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2012 Kevin Smith + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma once + +#include <Swift/Controllers/Settings/SettingsProvider.h> + +namespace Swift { + +class SettingsProviderHierachy : public SettingsProvider { + public: + virtual ~SettingsProviderHierachy(); + virtual std::string getSetting(const Setting<std::string>& setting); + virtual void storeSetting(const Setting<std::string>& setting, const std::string& value); + virtual bool getSetting(const Setting<bool>& setting); + virtual void storeSetting(const Setting<bool>& setting, const bool& value); + virtual int getSetting(const Setting<int>& setting); + virtual void storeSetting(const Setting<int>& setting, const int& value); + virtual std::vector<std::string> getAvailableProfiles(); + virtual void createProfile(const std::string& profile); + virtual void removeProfile(const std::string& profile); + protected: + virtual bool getIsSettingFinal(const std::string& settingPath); + + public: + /** + * Adds a provider less significant than any already added. + * This means that if an existing provider has a setting, this provider won't be asked. + * Any settings will be pushed into the topmost (least significant) provider. + * Does not take ownership of provider. + */ + void addProviderToTopOfStack(SettingsProvider* provider); + private: + SettingsProvider* getWritableProvider(); + private: + /* Start/Left is most significant (lowest), left overrides right.*/ + std::vector<SettingsProvider*> providers_; +}; + +} + + + diff --git a/Swift/Controllers/Settings/XMLSettingsProvider.cpp b/Swift/Controllers/Settings/XMLSettingsProvider.cpp new file mode 100644 index 0000000..6ad3170 --- /dev/null +++ b/Swift/Controllers/Settings/XMLSettingsProvider.cpp @@ -0,0 +1,124 @@ +/* + * Copyright (c) 2012 Kevin Smith + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#include <Swift/Controllers/Settings/XMLSettingsProvider.h> + +#include <boost/lexical_cast.hpp> +#include <boost/algorithm/string.hpp> + +#include <Swiften/Parser/PlatformXMLParserFactory.h> +#include <Swiften/Parser/XMLParser.h> +#include <Swiften/Base/Log.h> + +namespace Swift { + +XMLSettingsProvider::XMLSettingsProvider(const std::string& xmlConfig) : level_(0) { + if (!xmlConfig.empty()) { + PlatformXMLParserFactory factory; + XMLParser* parser = factory.createXMLParser(this); + if (parser->parse(xmlConfig)) { + SWIFT_LOG(debug) << "Found and parsed system config" << std::endl; + } + else { + SWIFT_LOG(debug) << "Found invalid system config" << std::endl; + } + delete parser; + } + else { + SWIFT_LOG(debug) << "No system config found" << std::endl; + } +} + +XMLSettingsProvider::~XMLSettingsProvider() { + +} + +std::string XMLSettingsProvider::getSetting(const Setting<std::string>& setting) { + if (values_.find(setting.getKey()) != values_.end()) { + std::string value = values_[setting.getKey()]; + return value; + } + return setting.getDefaultValue(); +} + +void XMLSettingsProvider::storeSetting(const Setting<std::string>& /*settingPath*/, const std::string& /*settingValue*/) { + assert(false); +} + +bool XMLSettingsProvider::getSetting(const Setting<bool>& setting) { + if (values_.find(setting.getKey()) != values_.end()) { + std::string value = values_[setting.getKey()]; + return boost::iequals(value, "true") || value == "1"; + } + return setting.getDefaultValue(); +} + +void XMLSettingsProvider::storeSetting(const Setting<bool>& /*settingPath*/, const bool& /*settingValue*/) { + assert(false); +} + +int XMLSettingsProvider::getSetting(const Setting<int>& setting) { + if (values_.find(setting.getKey()) != values_.end()) { + std::string value = values_[setting.getKey()]; + try { + return value.empty() ? setting.getDefaultValue() : boost::lexical_cast<int>(value);; + } + catch(boost::bad_lexical_cast &) {} + } + return setting.getDefaultValue(); +} + +void XMLSettingsProvider::storeSetting(const Setting<int>& /*settingPath*/, const int& /*settingValue*/) { + assert(false); +} + +std::vector<std::string> XMLSettingsProvider::getAvailableProfiles() { + assert(false); +} + +void XMLSettingsProvider::createProfile(const std::string& /*profile*/) { + assert(false); +} + +void XMLSettingsProvider::removeProfile(const std::string& /*profile*/) { + assert(false); +} + +bool XMLSettingsProvider::getIsSettingFinal(const std::string& settingPath) { + return finals_.count(settingPath); +} + +void XMLSettingsProvider::handleStartElement(const std::string& element, const std::string& /*ns*/, const AttributeMap& attributes) { + level_++; + if (level_ == SettingLevel) { + if (attributes.getBoolAttribute("final", false)) { + finals_.insert(element); + } + currentElement_ = element; + currentText_ = ""; + } +} + +void XMLSettingsProvider::handleEndElement(const std::string& /*element*/, const std::string& /*ns*/) { + if (level_ == SettingLevel) { + values_[currentElement_] = currentText_; + SWIFT_LOG(debug) << "Setting value of " << currentElement_ << " to " << currentText_ << std::endl; + } + level_--; +} + +void XMLSettingsProvider::handleCharacterData(const std::string& data) { + if (level_ >= SettingLevel) { + currentText_ += data; + } +} + + +} + + + + diff --git a/Swift/Controllers/Settings/XMLSettingsProvider.h b/Swift/Controllers/Settings/XMLSettingsProvider.h new file mode 100644 index 0000000..61abd11 --- /dev/null +++ b/Swift/Controllers/Settings/XMLSettingsProvider.h @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2012 Kevin Smith + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma once + +#include <Swift/Controllers/Settings/SettingsProvider.h> +#include <Swiften/Parser/XMLParserClient.h> + +#include <map> +#include <set> + +namespace Swift { + +class XMLSettingsProvider : public SettingsProvider, public XMLParserClient { + public: + XMLSettingsProvider(const std::string& xmlConfig); + virtual ~XMLSettingsProvider(); + virtual std::string getSetting(const Setting<std::string>& setting); + virtual void storeSetting(const Setting<std::string>& setting, const std::string& value); + virtual bool getSetting(const Setting<bool>& setting); + virtual void storeSetting(const Setting<bool>& setting, const bool& value); + virtual int getSetting(const Setting<int>& setting); + virtual void storeSetting(const Setting<int>& setting, const int& value); + virtual std::vector<std::string> getAvailableProfiles(); + virtual void createProfile(const std::string& profile); + virtual void removeProfile(const std::string& profile); + + virtual void handleStartElement(const std::string& element, const std::string& ns, const AttributeMap& attributes); + virtual void handleEndElement(const std::string& element, const std::string& ns); + virtual void handleCharacterData(const std::string& data); + + protected: + virtual bool getIsSettingFinal(const std::string& settingPath); + private: + std::map<std::string /*settingPath*/, std::string /*settingValue*/> values_; + /* Settings that are final*/ + std::set<std::string /*settingPath*/> finals_; + + enum Level { + TopLevel = 0, + SettingLevel = 2 + }; + + int level_; + std::string currentElement_; + std::string currentText_; +}; + +} + + + + diff --git a/Swift/Controllers/SoundEventController.cpp b/Swift/Controllers/SoundEventController.cpp index 26847ed..d056990 100644 --- a/Swift/Controllers/SoundEventController.cpp +++ b/Swift/Controllers/SoundEventController.cpp @@ -1,53 +1,45 @@ /* - * Copyright (c) 2010 Kevin Smith + * Copyright (c) 2010-2012 Kevin Smith * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. */ -#include "Swift/Controllers/SoundEventController.h" +#include <Swift/Controllers/SoundEventController.h> #include <boost/bind.hpp> -#include "Swift/Controllers/XMPPEvents/EventController.h" -#include "Swift/Controllers/SoundPlayer.h" -#include "Swift/Controllers/UIEvents/UIEventStream.h" -#include "Swift/Controllers/UIEvents/ToggleSoundsUIEvent.h" +#include <Swift/Controllers/XMPPEvents/EventController.h> +#include <Swift/Controllers/SoundPlayer.h> +#include <Swift/Controllers/UIEvents/UIEventStream.h> +#include <Swift/Controllers/SettingConstants.h> namespace Swift { -SoundEventController::SoundEventController(EventController* eventController, SoundPlayer* soundPlayer, SettingsProvider* settings, UIEventStream* uiEvents) { - uiEvents_ = uiEvents; +SoundEventController::SoundEventController(EventController* eventController, SoundPlayer* soundPlayer, SettingsProvider* settings) { settings_ = settings; eventController_ = eventController; soundPlayer_ = soundPlayer; - uiEvents_->onUIEvent.connect(boost::bind(&SoundEventController::handleUIEvent, this, _1)); eventController_->onEventQueueEventAdded.connect(boost::bind(&SoundEventController::handleEventQueueEventAdded, this, _1)); + settings_->onSettingChanged.connect(boost::bind(&SoundEventController::handleSettingChanged, this, _1)); - bool playSounds = settings->getBoolSetting("playSounds", true); - playSounds_ = !playSounds; - setPlaySounds(playSounds); + playSounds_ = settings->getSetting(SettingConstants::PLAY_SOUNDS); } void SoundEventController::handleEventQueueEventAdded(boost::shared_ptr<StanzaEvent> event) { if (playSounds_ && !event->getConcluded()) { soundPlayer_->playSound(SoundPlayer::MessageReceived); } } void SoundEventController::setPlaySounds(bool playSounds) { - bool transmit = playSounds != playSounds_; playSounds_ = playSounds; - settings_->storeBool("playSounds", playSounds); - if (transmit) { - uiEvents_->send(boost::shared_ptr<ToggleSoundsUIEvent>(new ToggleSoundsUIEvent(playSounds_))); - } + settings_->storeSetting(SettingConstants::PLAY_SOUNDS, playSounds); } -void SoundEventController::handleUIEvent(boost::shared_ptr<UIEvent> event) { - boost::shared_ptr<ToggleSoundsUIEvent> soundEvent = boost::dynamic_pointer_cast<ToggleSoundsUIEvent>(event); - if (soundEvent) { - setPlaySounds(soundEvent->getEnabled()); +void SoundEventController::handleSettingChanged(const std::string& settingPath) { + if (SettingConstants::PLAY_SOUNDS.getKey() == settingPath) { + playSounds_ = settings_->getSetting(SettingConstants::PLAY_SOUNDS); } } } diff --git a/Swift/Controllers/SoundEventController.h b/Swift/Controllers/SoundEventController.h index 5e00fc6..c6dec6f 100644 --- a/Swift/Controllers/SoundEventController.h +++ b/Swift/Controllers/SoundEventController.h @@ -1,33 +1,30 @@ /* - * Copyright (c) 2010 Kevin Smith + * Copyright (c) 2010-2012 Kevin Smith * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. */ #pragma once #include <boost/shared_ptr.hpp> -#include "Swift/Controllers/XMPPEvents/StanzaEvent.h" -#include "Swift/Controllers/Settings/SettingsProvider.h" -#include "Swift/Controllers/UIEvents/UIEvent.h" +#include <Swift/Controllers/XMPPEvents/StanzaEvent.h> +#include <Swift/Controllers/Settings/SettingsProvider.h> namespace Swift { class EventController; class SoundPlayer; - class UIEventStream; class SoundEventController { public: - SoundEventController(EventController* eventController, SoundPlayer* soundPlayer, SettingsProvider* settings, UIEventStream* uiEvents); + SoundEventController(EventController* eventController, SoundPlayer* soundPlayer, SettingsProvider* settings); void setPlaySounds(bool playSounds); bool getSoundEnabled() {return playSounds_;}; private: - void handleUIEvent(boost::shared_ptr<UIEvent> event); + void handleSettingChanged(const std::string& settingPath); void handleEventQueueEventAdded(boost::shared_ptr<StanzaEvent> event); EventController* eventController_; SoundPlayer* soundPlayer_; bool playSounds_; - UIEventStream* uiEvents_; SettingsProvider* settings_; }; } diff --git a/Swift/Controllers/UIEvents/ToggleNotificationsUIEvent.h b/Swift/Controllers/UIEvents/ToggleNotificationsUIEvent.h deleted file mode 100644 index 0f7acc8..0000000 --- a/Swift/Controllers/UIEvents/ToggleNotificationsUIEvent.h +++ /dev/null @@ -1,19 +0,0 @@ -/* - * Copyright (c) 2010 Kevin Smith - * Licensed under the GNU General Public License v3. - * See Documentation/Licenses/GPLv3.txt for more information. - */ - -#pragma once - -#include "Swift/Controllers/UIEvents/UIEvent.h" - -namespace Swift { - class ToggleNotificationsUIEvent : public UIEvent { - public: - ToggleNotificationsUIEvent(bool enable) : enabled_(enable) {}; - bool getEnabled() {return enabled_;}; - private: - bool enabled_; - }; -} diff --git a/Swift/Controllers/UIEvents/ToggleRequestDeliveryReceiptsUIEvent.h b/Swift/Controllers/UIEvents/ToggleRequestDeliveryReceiptsUIEvent.h deleted file mode 100644 index 1ea2db5..0000000 --- a/Swift/Controllers/UIEvents/ToggleRequestDeliveryReceiptsUIEvent.h +++ /dev/null @@ -1,19 +0,0 @@ -/* - * Copyright (c) 2011 Tobias Markmann - * Licensed under the BSD license. - * See http://www.opensource.org/licenses/bsd-license.php for more information. - */ - -#pragma once - -#include "Swift/Controllers/UIEvents/UIEvent.h" - -namespace Swift { - class ToggleRequestDeliveryReceiptsUIEvent : public UIEvent { - public: - ToggleRequestDeliveryReceiptsUIEvent(bool enable) : enabled_(enable) {} - bool getEnabled() {return enabled_;} - private: - bool enabled_; - }; -} diff --git a/Swift/Controllers/UIEvents/ToggleShowOfflineUIEvent.h b/Swift/Controllers/UIEvents/ToggleShowOfflineUIEvent.h deleted file mode 100644 index b45eb83..0000000 --- a/Swift/Controllers/UIEvents/ToggleShowOfflineUIEvent.h +++ /dev/null @@ -1,19 +0,0 @@ -/* - * Copyright (c) 2010 Kevin Smith - * Licensed under the GNU General Public License v3. - * See Documentation/Licenses/GPLv3.txt for more information. - */ - -#pragma once - -#include "Swift/Controllers/UIEvents/UIEvent.h" - -namespace Swift { - class ToggleShowOfflineUIEvent : public UIEvent { - public: - ToggleShowOfflineUIEvent(bool show) : show_(show) {}; - bool getShow() {return show_;}; - private: - bool show_; - }; -} diff --git a/Swift/Controllers/UIEvents/ToggleSoundsUIEvent.h b/Swift/Controllers/UIEvents/ToggleSoundsUIEvent.h deleted file mode 100644 index 9e5cfc6..0000000 --- a/Swift/Controllers/UIEvents/ToggleSoundsUIEvent.h +++ /dev/null @@ -1,19 +0,0 @@ -/* - * Copyright (c) 2010 Kevin Smith - * Licensed under the GNU General Public License v3. - * See Documentation/Licenses/GPLv3.txt for more information. - */ - -#pragma once - -#include "Swift/Controllers/UIEvents/UIEvent.h" - -namespace Swift { - class ToggleSoundsUIEvent : public UIEvent { - public: - ToggleSoundsUIEvent(bool enable) : enabled_(enable) {}; - bool getEnabled() {return enabled_;}; - private: - bool enabled_; - }; -} |