diff options
Diffstat (limited to 'Swift/Controllers')
-rw-r--r-- | Swift/Controllers/Chat/ChatsManager.cpp | 17 | ||||
-rw-r--r-- | Swift/Controllers/Chat/ChatsManager.h | 2 | ||||
-rw-r--r-- | Swift/Controllers/Chat/UserSearchController.cpp | 3 | ||||
-rw-r--r-- | Swift/Controllers/Contact.cpp | 12 | ||||
-rw-r--r-- | Swift/Controllers/ContactProvider.h | 2 | ||||
-rw-r--r-- | Swift/Controllers/ContactSuggester.cpp | 12 | ||||
-rw-r--r-- | Swift/Controllers/ContactSuggester.h | 2 | ||||
-rw-r--r-- | Swift/Controllers/ContactsFromXMPPRoster.cpp | 2 | ||||
-rw-r--r-- | Swift/Controllers/ContactsFromXMPPRoster.h | 2 | ||||
-rw-r--r-- | Swift/Controllers/HighlightEditorController.cpp | 2 |
10 files changed, 43 insertions, 13 deletions
diff --git a/Swift/Controllers/Chat/ChatsManager.cpp b/Swift/Controllers/Chat/ChatsManager.cpp index 3db1327..c180024 100644 --- a/Swift/Controllers/Chat/ChatsManager.cpp +++ b/Swift/Controllers/Chat/ChatsManager.cpp @@ -939,52 +939,67 @@ void ChatsManager::handleRecentActivated(const ChatListWindow::Chat& chat) { inviteJIDs.push_back(pair.second); } uiEventStream_->send(boost::make_shared<CreateImpromptuMUCUIEvent>(inviteJIDs, chat.jid, "")); } else if (chat.isMUC) { /* FIXME: This means that recents requiring passwords will just flat-out not work */ uiEventStream_->send(boost::make_shared<JoinMUCUIEvent>(chat.jid, boost::optional<std::string>(), chat.nick)); } else { uiEventStream_->send(boost::make_shared<RequestChatUIEvent>(chat.jid)); } } void ChatsManager::handleLocalServiceFound(const JID& service, boost::shared_ptr<DiscoInfo> info) { foreach (DiscoInfo::Identity identity, info->getIdentities()) { if ((identity.getCategory() == "directory" && identity.getType() == "chatroom") || (identity.getCategory() == "conference" && identity.getType() == "text")) { localMUCServiceJID_ = service; localMUCServiceFinderWalker_->endWalk(); SWIFT_LOG(debug) << "Use following MUC service for impromptu chats: " << localMUCServiceJID_ << std::endl; break; } } } void ChatsManager::handleLocalServiceWalkFinished() { onImpromptuMUCServiceDiscovered(!localMUCServiceJID_.toString().empty()); } std::vector<ChatListWindow::Chat> ChatsManager::getRecentChats() const { return std::vector<ChatListWindow::Chat>(recentChats_.begin(), recentChats_.end()); } -std::vector<Contact::ref> Swift::ChatsManager::getContacts() { +std::vector<Contact::ref> Swift::ChatsManager::getContacts(bool withMUCNicks) { std::vector<Contact::ref> result; foreach (ChatListWindow::Chat chat, recentChats_) { if (!chat.isMUC) { result.push_back(boost::make_shared<Contact>(chat.chatName.empty() ? chat.jid.toString() : chat.chatName, chat.jid, chat.statusType, chat.avatarPath)); } } + if (withMUCNicks) { + /* collect MUC nicks */ + typedef std::map<JID, MUCController*>::value_type Item; + foreach (const Item& item, mucControllers_) { + JID mucJID = item.second->getToJID(); + std::map<std::string, JID> participants = item.second->getParticipantJIDs(); + typedef std::map<std::string, JID>::value_type ParticipantType; + foreach (const ParticipantType& participant, participants) { + const JID nickJID = JID(mucJID.getNode(), mucJID.getDomain(), participant.first); + Presence::ref presence = presenceOracle_->getLastPresence(nickJID); + const boost::filesystem::path avatar = avatarManager_->getAvatarPath(nickJID); + result.push_back(boost::make_shared<Contact>(participant.first, JID(), presence->getShow(), avatar)); + } + } + } return result; } ChatsManager::SingleChatWindowFactoryAdapter::SingleChatWindowFactoryAdapter(ChatWindow* chatWindow) : chatWindow_(chatWindow) {} ChatsManager::SingleChatWindowFactoryAdapter::~SingleChatWindowFactoryAdapter() {} ChatWindow* ChatsManager::SingleChatWindowFactoryAdapter::createChatWindow(const JID &, UIEventStream*) { return chatWindow_; } } diff --git a/Swift/Controllers/Chat/ChatsManager.h b/Swift/Controllers/Chat/ChatsManager.h index 179f536..575b3cb 100644 --- a/Swift/Controllers/Chat/ChatsManager.h +++ b/Swift/Controllers/Chat/ChatsManager.h @@ -41,71 +41,71 @@ namespace Swift { 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 WhiteboardManager; class HistoryController; class HighlightManager; class ClientBlockListManager; class ChatMessageParser; class DiscoServiceWalker; class AutoAcceptMUCInviteDecider; class UserSearchController; class VCardManager; class ChatsManager : public ContactProvider { public: ChatsManager(JID jid, StanzaChannel* stanzaChannel, IQRouter* iqRouter, EventController* eventController, ChatWindowFactory* chatWindowFactory, JoinMUCWindowFactory* joinMUCWindowFactory, NickResolver* nickResolver, PresenceOracle* presenceOracle, PresenceSender* presenceSender, UIEventStream* uiEventStream, ChatListWindowFactory* chatListWindowFactory, bool useDelayForLatency, TimerFactory* timerFactory, MUCRegistry* mucRegistry, EntityCapsProvider* entityCapsProvider, MUCManager* mucManager, MUCSearchWindowFactory* mucSearchWindowFactory, ProfileSettingsProvider* profileSettings, FileTransferOverview* ftOverview, XMPPRoster* roster, bool eagleMode, SettingsProvider* settings, HistoryController* historyController_, WhiteboardManager* whiteboardManager, HighlightManager* highlightManager, ClientBlockListManager* clientBlockListManager, const std::map<std::string, std::string>& emoticons, UserSearchController* inviteUserSearchController, VCardManager* vcardManager); virtual ~ChatsManager(); void setAvatarManager(AvatarManager* avatarManager); void setOnline(bool enabled); void setServerDiscoInfo(boost::shared_ptr<DiscoInfo> info); void handleIncomingMessage(boost::shared_ptr<Message> message); std::vector<ChatListWindow::Chat> getRecentChats() const; - virtual std::vector<Contact::ref> getContacts(); + virtual std::vector<Contact::ref> getContacts(bool withMUCNicks); boost::signal<void (bool supportsImpromptu)> onImpromptuMUCServiceDiscovered; private: class SingleChatWindowFactoryAdapter : public ChatWindowFactory { public: SingleChatWindowFactoryAdapter(ChatWindow* chatWindow); virtual ~SingleChatWindowFactoryAdapter(); virtual ChatWindow* createChatWindow(const JID &, UIEventStream*); private: ChatWindow* chatWindow_; }; private: ChatListWindow::Chat createChatListChatItem(const JID& jid, const std::string& activity, bool privateMessage); void handleChatRequest(const std::string& contact); void finalizeImpromptuJoin(MUC::ref muc, const std::vector<JID>& jidsToInvite, const std::string& reason, const boost::optional<JID>& reuseChatJID = boost::optional<JID>()); MUC::ref handleJoinMUCRequest(const JID& muc, const boost::optional<std::string>& password, const boost::optional<std::string>& nick, bool addAutoJoin, bool createAsReservedIfNew, bool isImpromptu, ChatWindow* reuseChatwindow = 0); 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 handleChatClosed(const JID& jid); void handleNewFileTransferController(FileTransferController*); void handleWhiteboardSessionRequest(const JID& contact, bool senderIsSelf); void handleWhiteboardStateChange(const JID& contact, const ChatWindow::WhiteboardSessionState state); boost::optional<ChatListWindow::Chat> removeExistingChat(const ChatListWindow::Chat& chat); void cleanupPrivateMessageRecents(); diff --git a/Swift/Controllers/Chat/UserSearchController.cpp b/Swift/Controllers/Chat/UserSearchController.cpp index f259a9a..f1849c9 100644 --- a/Swift/Controllers/Chat/UserSearchController.cpp +++ b/Swift/Controllers/Chat/UserSearchController.cpp @@ -164,71 +164,72 @@ void UserSearchController::handleSearch(boost::shared_ptr<SearchPayload> fields, void UserSearchController::handleSearchResponse(boost::shared_ptr<SearchPayload> resultsPayload, ErrorPayload::ref error) { if (error || !resultsPayload) { window_->setSearchError(true); return; } std::vector<UserSearchResult> results; if (resultsPayload->getForm()) { window_->setResultsForm(resultsPayload->getForm()); } else { foreach (SearchPayload::Item item, resultsPayload->getItems()) { JID jid(item.jid); std::map<std::string, std::string> fields; fields["first"] = item.first; fields["last"] = item.last; fields["nick"] = item.nick; fields["email"] = item.email; UserSearchResult result(jid, fields); results.push_back(result); } window_->setResults(results); } } void UserSearchController::handleNameSuggestionRequest(const JID &jid) { suggestionsJID_= jid; VCard::ref vcard = vcardManager_->getVCardAndRequestWhenNeeded(jid); if (vcard) { handleVCardChanged(jid, vcard); } } void UserSearchController::handleContactSuggestionsRequested(std::string text) { const std::vector<JID> existingJIDs = window_->getJIDs(); - std::vector<Contact::ref> suggestions = contactSuggester_->getSuggestions(text); + std::vector<Contact::ref> suggestions = contactSuggester_->getSuggestions(text, false); + /* do not suggest contacts that have already been added to the chat list */ std::vector<Contact::ref>::iterator i = suggestions.begin(); while (i != suggestions.end()) { bool found = false; foreach (const JID& jid, existingJIDs) { if ((*i)->jid == jid) { found = true; break; } } if (found) { i = suggestions.erase(i); } else { i++; } } window_->setContactSuggestions(suggestions); } void UserSearchController::handleVCardChanged(const JID& jid, VCard::ref vcard) { if (jid == suggestionsJID_) { window_->setNameSuggestions(ContactEditController::nameSuggestionsFromVCard(vcard)); suggestionsJID_ = JID(); } handleJIDUpdateRequested(std::vector<JID>(1, jid)); } void UserSearchController::handleAvatarChanged(const JID& jid) { handleJIDUpdateRequested(std::vector<JID>(1, jid)); } void UserSearchController::handlePresenceChanged(Presence::ref presence) { handleJIDUpdateRequested(std::vector<JID>(1, presence->getFrom().toBare())); } void UserSearchController::handleJIDUpdateRequested(const std::vector<JID>& jids) { diff --git a/Swift/Controllers/Contact.cpp b/Swift/Controllers/Contact.cpp index 198443d..be2b83a 100644 --- a/Swift/Controllers/Contact.cpp +++ b/Swift/Controllers/Contact.cpp @@ -1,59 +1,67 @@ /* * Copyright (c) 2013 Tobias Markmann * Licensed under the simplified BSD license. * See Documentation/Licenses/BSD-simplified.txt for more information. */ #include <boost/algorithm/string.hpp> #include <boost/algorithm/string/find.hpp> #include <Swift/Controllers/Contact.h> namespace Swift { Contact::Contact() { } Contact::Contact(const std::string& name, const JID& jid, StatusShow::Type statusType, const boost::filesystem::path& path) : name(name), jid(jid), statusType(statusType), avatarPath(path) { } bool Contact::lexicographicalSortPredicate(const Contact::ref& a, const Contact::ref& b) { - return a->jid < b->jid; + if (a->jid.isValid() && b->jid.isValid()) { + return a->jid < b->jid; + } else { + return a->name < b->name; + } } bool Contact::equalityPredicate(const Contact::ref& a, const Contact::ref& b) { - return a->jid == b->jid; + if (a->jid.isValid() && b->jid.isValid()) { + return a->jid == b->jid; + } else { + return a->name == b->name; + } } bool Contact::sortPredicate(const Contact::ref& a, const Contact::ref& b, const std::string& search) { /* perform case insensitive comparisons */ std::string aLower = a->name; boost::to_lower(aLower); std::string bLower = b->name; boost::to_lower(bLower); std::string searchLower = search; boost::to_lower(searchLower); /* name starts with the search term */ if (aLower.find(searchLower) == 0 && bLower.find(searchLower) != 0) { return true; } else if (bLower.find(searchLower) == 0 && aLower.find(searchLower) != 0) { return false; } /* name contains search term */ if (aLower.find(searchLower) != std::string::npos && bLower.find(searchLower) == std::string::npos) { return true; } else if (bLower.find(searchLower) != std::string::npos && aLower.find(searchLower) == std::string::npos) { return false; } /* Levenshtein should be done here */ /* if edit distances are equal, fall through to the tests below */ /* lexicographical sort */ if (a->statusType == b->statusType) { return aLower.compare(bLower) < 0; } /* online status */ return a->statusType < b->statusType; diff --git a/Swift/Controllers/ContactProvider.h b/Swift/Controllers/ContactProvider.h index 0e56de5..acc2bdc 100644 --- a/Swift/Controllers/ContactProvider.h +++ b/Swift/Controllers/ContactProvider.h @@ -1,27 +1,27 @@ /* * Copyright (c) 2013 Tobias Markmann * Licensed under the simplified BSD license. * See Documentation/Licenses/BSD-simplified.txt for more information. */ /* * Copyright (c) 2014 Kevin Smith and Remko Tronçon * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. */ #pragma once #include <vector> #include <Swift/Controllers/Contact.h> namespace Swift { class ContactProvider { public: virtual ~ContactProvider(); - virtual std::vector<Contact::ref> getContacts() = 0; + virtual std::vector<Contact::ref> getContacts(bool withMUCNicks) = 0; }; } diff --git a/Swift/Controllers/ContactSuggester.cpp b/Swift/Controllers/ContactSuggester.cpp index 42e8308..8627aeb 100644 --- a/Swift/Controllers/ContactSuggester.cpp +++ b/Swift/Controllers/ContactSuggester.cpp @@ -11,71 +11,77 @@ */ #include <Swift/Controllers/ContactSuggester.h> #include <boost/algorithm/string.hpp> #include <boost/algorithm/string/find.hpp> #include <boost/bind.hpp> #include <boost/lambda/lambda.hpp> #include <boost/lambda/bind.hpp> #include <Swiften/Base/Algorithm.h> #include <Swiften/Base/foreach.h> #include <Swiften/JID/JID.h> #include <Swift/Controllers/ContactProvider.h> #include <algorithm> #include <vector> #include <set> namespace lambda = boost::lambda; namespace Swift { ContactSuggester::ContactSuggester() { } ContactSuggester::~ContactSuggester() { } void ContactSuggester::addContactProvider(ContactProvider* provider) { contactProviders_.push_back(provider); } bool ContactSuggester::matchContact(const std::string& search, const Contact::ref& c) { - return fuzzyMatch(c->name, search) || fuzzyMatch(c->jid.toString(), search); + if (fuzzyMatch(c->name, search)) { + return true; + } + else if (c->jid.isValid()) { + return fuzzyMatch(c->jid.toString(), search); + } + return false; } -std::vector<Contact::ref> ContactSuggester::getSuggestions(const std::string& search) const { +std::vector<Contact::ref> ContactSuggester::getSuggestions(const std::string& search, bool withMUCNicks) const { std::vector<Contact::ref> results; foreach(ContactProvider* provider, contactProviders_) { - append(results, provider->getContacts()); + append(results, provider->getContacts(withMUCNicks)); } std::sort(results.begin(), results.end(), Contact::lexicographicalSortPredicate); results.erase(std::unique(results.begin(), results.end(), Contact::equalityPredicate), results.end()); results.erase(std::remove_if(results.begin(), results.end(), !lambda::bind(&matchContact, search, lambda::_1)), results.end()); std::sort(results.begin(), results.end(), boost::bind(&Contact::sortPredicate, _1, _2, search)); return results; } bool ContactSuggester::fuzzyMatch(std::string text, std::string match) { std::string lowerText = text; boost::algorithm::to_lower(lowerText); std::string lowerMatch = match; boost::algorithm::to_lower(lowerMatch); size_t lastMatch = 0; for (size_t i = 0; i < lowerMatch.length(); ++i) { size_t where = lowerText.find_first_of(lowerMatch[i], lastMatch); if (where == std::string::npos) { return false; } lastMatch = where + 1; } return true; } } diff --git a/Swift/Controllers/ContactSuggester.h b/Swift/Controllers/ContactSuggester.h index 1c796c9..ae47766 100644 --- a/Swift/Controllers/ContactSuggester.h +++ b/Swift/Controllers/ContactSuggester.h @@ -1,43 +1,43 @@ /* * Copyright (c) 2013 Tobias Markmann * Licensed under the simplified BSD license. * See Documentation/Licenses/BSD-simplified.txt for more information. */ /* * Copyright (c) 2014 Kevin Smith and Remko Tronçon * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. */ #pragma once #include <string> #include <vector> #include <Swift/Controllers/Contact.h> class ContactSuggesterTest; namespace Swift { class ContactProvider; class ContactSuggester { public: ContactSuggester(); ~ContactSuggester(); void addContactProvider(ContactProvider* provider); - std::vector<Contact::ref> getSuggestions(const std::string& search) const; + std::vector<Contact::ref> getSuggestions(const std::string& search, bool withMUCNicks) const; public: static bool matchContact(const std::string& search, const Contact::ref& c); /** * Performs fuzzy matching on the string text. Matches when each character of match string is present in sequence in text string. */ static bool fuzzyMatch(std::string text, std::string match); private: std::vector<ContactProvider*> contactProviders_; }; } diff --git a/Swift/Controllers/ContactsFromXMPPRoster.cpp b/Swift/Controllers/ContactsFromXMPPRoster.cpp index 7559962..abd62bd 100644 --- a/Swift/Controllers/ContactsFromXMPPRoster.cpp +++ b/Swift/Controllers/ContactsFromXMPPRoster.cpp @@ -1,42 +1,42 @@ /* * Copyright (c) 2013 Tobias Markmann * Licensed under the simplified BSD license. * See Documentation/Licenses/BSD-simplified.txt for more information. */ /* * Copyright (c) 2014 Kevin Smith and Remko Tronçon * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. */ #include <Swift/Controllers/ContactsFromXMPPRoster.h> #include <Swiften/Base/foreach.h> #include <Swiften/Avatars/AvatarManager.h> #include <Swiften/Presence/PresenceOracle.h> #include <Swiften/Roster/XMPPRoster.h> #include <Swiften/Roster/XMPPRosterItem.h> namespace Swift { ContactsFromXMPPRoster::ContactsFromXMPPRoster(XMPPRoster* roster, AvatarManager* avatarManager, PresenceOracle* presenceOracle) : roster_(roster), avatarManager_(avatarManager), presenceOracle_(presenceOracle) { } ContactsFromXMPPRoster::~ContactsFromXMPPRoster() { } -std::vector<Contact::ref> ContactsFromXMPPRoster::getContacts() { +std::vector<Contact::ref> ContactsFromXMPPRoster::getContacts(bool /*withMUCNicks*/) { std::vector<Contact::ref> results; std::vector<XMPPRosterItem> rosterItems = roster_->getItems(); foreach(const XMPPRosterItem& rosterItem, rosterItems) { Contact::ref contact = boost::make_shared<Contact>(rosterItem.getName().empty() ? rosterItem.getJID().toString() : rosterItem.getName(), rosterItem.getJID(), StatusShow::None,""); contact->statusType = presenceOracle_->getHighestPriorityPresence(contact->jid) ? presenceOracle_->getHighestPriorityPresence(contact->jid)->getShow() : StatusShow::None; contact->avatarPath = avatarManager_->getAvatarPath(contact->jid); results.push_back(contact); } return results; } } diff --git a/Swift/Controllers/ContactsFromXMPPRoster.h b/Swift/Controllers/ContactsFromXMPPRoster.h index 4adc606..b76adc4 100644 --- a/Swift/Controllers/ContactsFromXMPPRoster.h +++ b/Swift/Controllers/ContactsFromXMPPRoster.h @@ -1,35 +1,35 @@ /* * Copyright (c) 2013 Tobias Markmann * Licensed under the simplified BSD license. * See Documentation/Licenses/BSD-simplified.txt for more information. */ /* * Copyright (c) 2014 Kevin Smith and Remko Tronçon * Licensed under the GNU General Public License v3. * See Documentation/Licenses/GPLv3.txt for more information. */ #pragma once #include <Swift/Controllers/ContactProvider.h> namespace Swift { class PresenceOracle; class AvatarManager; class XMPPRoster; class ContactsFromXMPPRoster : public ContactProvider { public: ContactsFromXMPPRoster(XMPPRoster* roster, AvatarManager* avatarManager, PresenceOracle* presenceOracle); virtual ~ContactsFromXMPPRoster(); - virtual std::vector<Contact::ref> getContacts(); + virtual std::vector<Contact::ref> getContacts(bool withMUCNicks); private: XMPPRoster* roster_; AvatarManager* avatarManager_; PresenceOracle* presenceOracle_; }; } diff --git a/Swift/Controllers/HighlightEditorController.cpp b/Swift/Controllers/HighlightEditorController.cpp index 38007f0..efa3ba2 100644 --- a/Swift/Controllers/HighlightEditorController.cpp +++ b/Swift/Controllers/HighlightEditorController.cpp @@ -17,40 +17,40 @@ #include <Swift/Controllers/UIEvents/UIEventStream.h> #include <Swift/Controllers/UIInterfaces/HighlightEditorWindowFactory.h> #include <Swift/Controllers/UIInterfaces/HighlightEditorWindow.h> #include <Swift/Controllers/ContactSuggester.h> namespace Swift { HighlightEditorController::HighlightEditorController(UIEventStream* uiEventStream, HighlightEditorWindowFactory* highlightEditorWindowFactory, HighlightManager* highlightManager) : highlightEditorWindowFactory_(highlightEditorWindowFactory), highlightEditorWindow_(NULL), highlightManager_(highlightManager), contactSuggester_(0) { uiEventStream->onUIEvent.connect(boost::bind(&HighlightEditorController::handleUIEvent, this, _1)); } HighlightEditorController::~HighlightEditorController() { delete highlightEditorWindow_; highlightEditorWindow_ = NULL; } void HighlightEditorController::handleUIEvent(boost::shared_ptr<UIEvent> rawEvent) { boost::shared_ptr<RequestHighlightEditorUIEvent> event = boost::dynamic_pointer_cast<RequestHighlightEditorUIEvent>(rawEvent); if (event) { if (!highlightEditorWindow_) { highlightEditorWindow_ = highlightEditorWindowFactory_->createHighlightEditorWindow(); highlightEditorWindow_->setHighlightManager(highlightManager_); highlightEditorWindow_->onContactSuggestionsRequested.connect(boost::bind(&HighlightEditorController::handleContactSuggestionsRequested, this, _1)); } highlightEditorWindow_->show(); } } void HighlightEditorController::handleContactSuggestionsRequested(const std::string& text) { if (contactSuggester_) { - highlightEditorWindow_->setContactSuggestions(contactSuggester_->getSuggestions(text)); + highlightEditorWindow_->setContactSuggestions(contactSuggester_->getSuggestions(text, true)); } } } |