summaryrefslogtreecommitdiffstats
path: root/Swift
diff options
context:
space:
mode:
Diffstat (limited to 'Swift')
-rw-r--r--Swift/Controllers/Chat/ChatsManager.cpp17
-rw-r--r--Swift/Controllers/Chat/ChatsManager.h2
-rw-r--r--Swift/Controllers/Chat/UserSearchController.cpp3
-rw-r--r--Swift/Controllers/Contact.cpp12
-rw-r--r--Swift/Controllers/ContactProvider.h2
-rw-r--r--Swift/Controllers/ContactSuggester.cpp12
-rw-r--r--Swift/Controllers/ContactSuggester.h2
-rw-r--r--Swift/Controllers/ContactsFromXMPPRoster.cpp2
-rw-r--r--Swift/Controllers/ContactsFromXMPPRoster.h2
-rw-r--r--Swift/Controllers/HighlightEditorController.cpp2
-rw-r--r--Swift/QtUI/QtHighlightEditor.cpp8
-rw-r--r--Swift/QtUI/QtHighlightEditor.h2
-rw-r--r--Swift/QtUI/UserSearch/QtSuggestingJIDInput.cpp8
-rw-r--r--Swift/QtUI/UserSearch/QtSuggestingJIDInput.h2
-rw-r--r--Swift/QtUI/UserSearch/QtUserSearchWindow.cpp12
-rw-r--r--Swift/QtUI/UserSearch/QtUserSearchWindow.h3
16 files changed, 67 insertions, 24 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));
}
}
}
diff --git a/Swift/QtUI/QtHighlightEditor.cpp b/Swift/QtUI/QtHighlightEditor.cpp
index 5aa4560..97774be 100644
--- a/Swift/QtUI/QtHighlightEditor.cpp
+++ b/Swift/QtUI/QtHighlightEditor.cpp
@@ -318,73 +318,77 @@ void QtHighlightEditor::widgetClick()
void QtHighlightEditor::disableDialog()
{
ui_.chatRadio->setEnabled(false);
ui_.roomRadio->setEnabled(false);
ui_.allMsgRadio->setEnabled(false);
ui_.nickIsKeyword->setEnabled(false);
ui_.senderRadio->setEnabled(false);
ui_.dummySenderName->setEnabled(false);
ui_.keywordRadio->setEnabled(false);
ui_.keyword->setEnabled(false);
ui_.matchPartialWords->setEnabled(false);
ui_.matchCase->setEnabled(false);
ui_.noColorRadio->setEnabled(false);
ui_.customColorRadio->setEnabled(false);
ui_.foregroundColor->setEnabled(false);
ui_.backgroundColor->setEnabled(false);
ui_.noSoundRadio->setEnabled(false);
ui_.defaultSoundRadio->setEnabled(false);
ui_.customSoundRadio->setEnabled(false);
ui_.soundFile->setEnabled(false);
ui_.soundFileButton->setEnabled(false);
}
void QtHighlightEditor::handleContactSuggestionRequested(const QString& text)
{
std::string stdText = Q2PSTRING(text);
onContactSuggestionsRequested(stdText);
}
void QtHighlightEditor::selectSoundFile()
{
QString path = QFileDialog::getOpenFileName(this, tr("Select sound file..."), QString(), "Sounds (*.wav)");
ui_.soundFile->setText(path);
}
-void QtHighlightEditor::handleOnUserSelected(const JID& jid) {
+void QtHighlightEditor::handleOnUserSelected(const Contact::ref& contact) {
/* this might seem like it should be standard behaviour for the suggesting input box, but is not desirable in all cases */
- jid_->setText(P2QSTRING(jid.toString()));
+ if (contact->jid.isValid()) {
+ jid_->setText(P2QSTRING(contact->jid.toString()));
+ } else {
+ jid_->setText(P2QSTRING(contact->name));
+ }
}
void QtHighlightEditor::populateList()
{
previousRow_ = -1;
ui_.listWidget->clear();
HighlightRulesListPtr rules = highlightManager_->getRules();
for (size_t i = 0; i < rules->getSize(); ++i) {
const HighlightRule& rule = rules->getRule(i);
QListWidgetItem *item = new QListWidgetItem();
item->setText(P2QSTRING(formatShortDescription(rule)));
ui_.listWidget->addItem(item);
}
}
void QtHighlightEditor::selectRow(int row)
{
for (int i = 0; i < ui_.listWidget->count(); ++i) {
if (i == row) {
ui_.listWidget->item(i)->setSelected(true);
onCurrentRowChanged(i);
} else {
ui_.listWidget->item(i)->setSelected(false);
}
}
ui_.listWidget->setCurrentRow(row);
}
int QtHighlightEditor::getSelectedRow() const
{
for (int i = 0; i < ui_.listWidget->count(); ++i) {
if (ui_.listWidget->item(i)->isSelected()) {
return i;
}
}
diff --git a/Swift/QtUI/QtHighlightEditor.h b/Swift/QtUI/QtHighlightEditor.h
index e0595ad..93a19b6 100644
--- a/Swift/QtUI/QtHighlightEditor.h
+++ b/Swift/QtUI/QtHighlightEditor.h
@@ -21,50 +21,50 @@ namespace Swift {
class QtSettingsProvider;
class QtSuggestingJIDInput;
class QtWebKitChatView;
class QtHighlightEditor : public QWidget, public HighlightEditorWindow {
Q_OBJECT
public:
QtHighlightEditor(QtSettingsProvider* settings, QWidget* parent = NULL);
virtual ~QtHighlightEditor();
virtual void show();
virtual void setHighlightManager(HighlightManager* highlightManager);
virtual void setContactSuggestions(const std::vector<Contact::ref>& suggestions);
private slots:
void colorOtherSelect();
void colorCustomSelect();
void soundOtherSelect();
void soundCustomSelect();
void onNewButtonClicked();
void onDeleteButtonClicked();
void onUpButtonClicked();
void onDownButtonClicked();
void onCurrentRowChanged(int currentRow);
void onApplyButtonClick();
void onCancelButtonClick();
void onOkButtonClick();
void setChildWidgetStates();
void widgetClick();
void disableDialog();
void handleContactSuggestionRequested(const QString& text);
void selectSoundFile();
private:
- void handleOnUserSelected(const JID& jid);
+ void handleOnUserSelected(const Contact::ref& contact);
void populateList();
void selectRow(int row);
int getSelectedRow() const;
HighlightRule ruleFromDialog();
void ruleToDialog(const HighlightRule& rule);
Ui::QtHighlightEditor ui_;
QtSettingsProvider* settings_;
HighlightManager* highlightManager_;
QtSuggestingJIDInput* jid_;
int previousRow_;
};
}
diff --git a/Swift/QtUI/UserSearch/QtSuggestingJIDInput.cpp b/Swift/QtUI/UserSearch/QtSuggestingJIDInput.cpp
index 78842a2..57033d8 100644
--- a/Swift/QtUI/UserSearch/QtSuggestingJIDInput.cpp
+++ b/Swift/QtUI/UserSearch/QtSuggestingJIDInput.cpp
@@ -82,101 +82,105 @@ Contact::ref QtSuggestingJIDInput::getContact() {
void QtSuggestingJIDInput::setSuggestions(const std::vector<Contact::ref>& suggestions) {
contactListModel_->setList(suggestions);
positionPopup();
if (!suggestions.empty()) {
treeViewPopup_->setCurrentIndex(contactListModel_->index(0, 0));
showPopup();
} else {
currentContact_.reset();
hidePopup();
}
}
void QtSuggestingJIDInput::clear() {
setText("");
currentContact_.reset();
}
void QtSuggestingJIDInput::keyPressEvent(QKeyEvent* event) {
if (event->key() == Qt::Key_Up) {
if (contactListModel_->rowCount() > 0) {
int row = treeViewPopup_->currentIndex().row();
row = (row + contactListModel_->rowCount() - 1) % contactListModel_->rowCount();
treeViewPopup_->setCurrentIndex(contactListModel_->index(row, 0));
}
} else if (event->key() == Qt::Key_Down) {
if (contactListModel_->rowCount() > 0) {
int row = treeViewPopup_->currentIndex().row();
row = (row + contactListModel_->rowCount() + 1) % contactListModel_->rowCount();
treeViewPopup_->setCurrentIndex(contactListModel_->index(row, 0));
}
} else if (event->key() == Qt::Key_Return && treeViewPopup_->isVisible()) {
QModelIndex index = treeViewPopup_->currentIndex();
if (!contactListModel_->getList().empty() && index.isValid()) {
currentContact_ = contactListModel_->getContact(index.row());
- setText(P2QSTRING(currentContact_->jid.toString()));
+ if (currentContact_->jid.isValid()) {
+ setText(P2QSTRING(currentContact_->jid.toString()));
+ } else {
+ setText(P2QSTRING(currentContact_->name));
+ }
hidePopup();
clearFocus();
} else {
currentContact_.reset();
}
editingDone();
} else {
QLineEdit::keyPressEvent(event);
}
}
void QtSuggestingJIDInput::handleApplicationFocusChanged(QWidget* /*old*/, QWidget* /*now*/) {
/* Using the now argument gives use the wrong widget. This is part of the code needed
to prevent stealing of focus when opening a the suggestion window. */
QWidget* now = qApp->focusWidget();
if (!now || (now != treeViewPopup_ && now != this && !now->isAncestorOf(this) && !now->isAncestorOf(treeViewPopup_) && !this->isAncestorOf(now) && !treeViewPopup_->isAncestorOf(now))) {
hidePopup();
}
}
void QtSuggestingJIDInput::handleSettingsChanged(const std::string& setting) {
if (setting == QtUISettingConstants::COMPACT_ROSTER.getKey()) {
contactListDelegate_->setCompact(settings_->getSetting(QtUISettingConstants::COMPACT_ROSTER));
}
}
void QtSuggestingJIDInput::handleClicked(const QModelIndex& index) {
if (index.isValid()) {
currentContact_ = contactListModel_->getContact(index.row());
- onUserSelected(currentContact_->jid);
+ onUserSelected(currentContact_);
hidePopup();
}
}
void QtSuggestingJIDInput::positionPopup() {
QDesktopWidget* desktop = QApplication::desktop();
int screen = desktop->screenNumber(this);
QPoint point = mapToGlobal(QPoint(0, height()));
QRect geometry = desktop->availableGeometry(screen);
int x = point.x();
int y = point.y();
int width = this->width();
int height = 80;
int screenWidth = geometry.x() + geometry.width();
if (x + width > screenWidth) {
x = screenWidth - width;
}
height = treeViewPopup_->sizeHintForRow(0) * contactListModel_->rowCount();
height = height > 200 ? 200 : height;
int marginLeft;
int marginTop;
int marginRight;
int marginBottom;
treeViewPopup_->getContentsMargins(&marginLeft, &marginTop, &marginRight, &marginBottom);
height += marginTop + marginBottom;
width += marginLeft + marginRight;
treeViewPopup_->setGeometry(x, y, width, height);
treeViewPopup_->move(x, y);
treeViewPopup_->setMaximumWidth(width);
}
diff --git a/Swift/QtUI/UserSearch/QtSuggestingJIDInput.h b/Swift/QtUI/UserSearch/QtSuggestingJIDInput.h
index 71cd87d..23e7b94 100644
--- a/Swift/QtUI/UserSearch/QtSuggestingJIDInput.h
+++ b/Swift/QtUI/UserSearch/QtSuggestingJIDInput.h
@@ -3,64 +3,64 @@
* 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 <QLineEdit>
#include <QTreeView>
#include <Swiften/Base/boost_bsignals.h>
#include <Swift/Controllers/Contact.h>
namespace Swift {
class ContactListDelegate;
class SettingsProvider;
class ContactListModel;
class QtSuggestingJIDInput : public QLineEdit {
Q_OBJECT
public:
QtSuggestingJIDInput(QWidget* parent, SettingsProvider* settings);
virtual ~QtSuggestingJIDInput();
Contact::ref getContact();
void setSuggestions(const std::vector<Contact::ref>& suggestions);
void clear();
- boost::signal<void (const JID&)> onUserSelected;
+ boost::signal<void (const Contact::ref&)> onUserSelected;
signals:
void editingDone();
protected:
virtual void keyPressEvent(QKeyEvent* event);
private:
void handleSettingsChanged(const std::string& setting);
private slots:
void handleClicked(const QModelIndex& index);
void handleApplicationFocusChanged(QWidget* old, QWidget* now);
private:
void positionPopup();
void showPopup();
void hidePopup();
private:
SettingsProvider* settings_;
ContactListModel* contactListModel_;
QTreeView* treeViewPopup_;
ContactListDelegate* contactListDelegate_;
Contact::ref currentContact_;
};
}
diff --git a/Swift/QtUI/UserSearch/QtUserSearchWindow.cpp b/Swift/QtUI/UserSearch/QtUserSearchWindow.cpp
index 17214e4..e5bd5d0 100644
--- a/Swift/QtUI/UserSearch/QtUserSearchWindow.cpp
+++ b/Swift/QtUI/UserSearch/QtUserSearchWindow.cpp
@@ -46,71 +46,71 @@ QtUserSearchWindow::QtUserSearchWindow(UIEventStream* eventStream, UserSearchWin
break;
case ChatToContact:
title = tr("Chat to Users");
break;
case InviteToChat:
title = tr("Add Users to Chat");
break;
}
setWindowTitle(title);
delegate_ = new UserSearchDelegate();
setFirstPage(title);
setSecondPage();
setThirdPage();
detailsPage_ = new QtUserSearchDetailsPage(groups);
setPage(4, detailsPage_);
connect(this, SIGNAL(currentIdChanged(int)), this, SLOT(handleCurrentChanged(int)));
connect(this, SIGNAL(accepted()), this, SLOT(handleAccepted()));
clear();
}
QtUserSearchWindow::~QtUserSearchWindow() {
delete model_;
}
void QtUserSearchWindow::handleCurrentChanged(int page) {
searchNext_ = false;
if (firstMultiJIDPage_) {
firstMultiJIDPage_->reset();
}
resultsPage_->emitCompletenessCheck();
if (page == 1 && lastPage_ == 3) {
- addSearchedJIDToList(getContactJID());
+ addSearchedJIDToList(getContact());
setSecondPage();
}
else if (page == 2 && lastPage_ == 1) {
setError("");
/* next won't be called if JID is selected */
JID server = getServerToSearch();
clearForm();
onFormRequested(server);
setThirdPage();
}
else if (page == 3 && lastPage_ == 2) {
JID server = getServerToSearch();
handleSearch();
if (type_ == AddContact) {
bool remote = firstPage_->byRemoteSearch_->isChecked();
firstPage_->byRemoteSearch_->setChecked(remote);
firstPage_->service_->setEditText(P2QSTRING(server.toString()));
} else {
bool remote = firstMultiJIDPage_->byRemoteSearch_->isChecked();
setFirstPage();
firstMultiJIDPage_->byRemoteSearch_->setChecked(remote);
firstMultiJIDPage_->service_->setEditText(P2QSTRING(server.toString()));
}
}
else if (page == 4) {
detailsPage_->clear();
detailsPage_->setJID(getContactJID());
onNameSuggestionRequested(getContactJID());
}
lastPage_ = page;
}
JID QtUserSearchWindow::getServerToSearch() {
if (type_ == AddContact) {
@@ -238,144 +238,148 @@ JID QtUserSearchWindow::getContactJID() const {
} else {
useSearchResult = true;
}
if (useSearchResult) {
if (dynamic_cast<UserSearchModel*>(model_)) {
UserSearchResult* userItem = static_cast<UserSearchResult*>(resultsPage_->results_->currentIndex().internalPointer());
if (userItem) { /* Remember to leave this if we change to dynamic cast */
jid = userItem->getJID();
}
} else if (dynamic_cast<QtFormResultItemModel*>(model_)) {
int row = resultsPage_->results_->currentIndex().row();
Form::FormItem item = dynamic_cast<QtFormResultItemModel*>(model_)->getForm()->getItems().at(row);
JID fallbackJid;
foreach(FormField::ref field, item) {
if (field->getType() == FormField::JIDSingleType) {
jid = JID(field->getJIDSingleValue());
break;
}
if (field->getName() == "jid") {
fallbackJid = field->getValues()[0];
}
}
if (!jid.isValid()) {
jid = fallbackJid;
}
}
}
else {
jid = JID(Q2PSTRING(firstPage_->jid_->text().trimmed()));
}
return jid;
}
-void QtUserSearchWindow::addSearchedJIDToList(const JID& jid) {
+Contact::ref QtUserSearchWindow::getContact() const {
+ return boost::make_shared<Contact>("", getContactJID(), StatusShow::None, "");
+}
+
+void QtUserSearchWindow::addSearchedJIDToList(const Contact::ref& contact) {
std::vector<JID> jids;
- jids.push_back(jid);
+ jids.push_back(contact->jid);
handleJIDsAdded(jids);
firstMultiJIDPage_->jid_->clear();
}
void QtUserSearchWindow::show() {
clear();
QWidget::show();
}
void QtUserSearchWindow::addSavedServices(const std::vector<JID>& services) {
if (type_ == AddContact) {
firstPage_->service_->clear();
foreach (JID jid, services) {
firstPage_->service_->addItem(P2QSTRING(jid.toString()));
}
firstPage_->service_->clearEditText();
} else {
firstMultiJIDPage_->service_->clear();
foreach (JID jid, services) {
firstMultiJIDPage_->service_->addItem(P2QSTRING(jid.toString()));
}
firstMultiJIDPage_->service_->clearEditText();
}
}
void QtUserSearchWindow::setSearchFields(boost::shared_ptr<SearchPayload> fields) {
fieldsPage_->fetchingThrobber_->hide();
fieldsPage_->fetchingThrobber_->movie()->stop();
fieldsPage_->fetchingLabel_->hide();
fieldsPage_->instructionsLabel_->setText(fields->getInstructions() ? P2QSTRING(fields->getInstructions().get()) : "Enter search terms");
if (fields->getForm()) {
fieldsPage_->setFormWidget(new QtFormWidget(fields->getForm(), fieldsPage_));
} else {
fieldsPage_->setFormWidget(NULL);
bool enabled[8] = {!!fields->getNick(), !!fields->getNick(), !!fields->getFirst(), !!fields->getFirst(), !!fields->getLast(), !!fields->getLast(), !!fields->getEMail(), !!fields->getEMail()};
QWidget* legacySearchWidgets[8] = {fieldsPage_->nickInputLabel_, fieldsPage_->nickInput_, fieldsPage_->firstInputLabel_, fieldsPage_->firstInput_, fieldsPage_->lastInputLabel_, fieldsPage_->lastInput_, fieldsPage_->emailInputLabel_, fieldsPage_->emailInput_};
for (int i = 0; i < 8; i++) {
legacySearchWidgets[i]->setVisible(enabled[i]);
legacySearchWidgets[i]->setEnabled(enabled[i]);
}
}
fieldsPage_->emitCompletenessCheck();
}
void QtUserSearchWindow::setNameSuggestions(const std::vector<std::string>& suggestions) {
if (detailsPage_) {
detailsPage_->setNameSuggestions(suggestions);
}
}
void QtUserSearchWindow::prepopulateJIDAndName(const JID& jid, const std::string& name) {
firstPage_->jid_->setText(P2QSTRING(jid.toBare().toString()));
detailsPage_->setJID(jid);
lastPage_ = 1;
restart();
next();
detailsPage_->setName(name);
}
void QtUserSearchWindow::setContactSuggestions(const std::vector<Contact::ref>& suggestions) {
if (type_ == AddContact) {
firstPage_->jid_->setSuggestions(suggestions);
} else {
firstMultiJIDPage_->jid_->setSuggestions(suggestions);
}
}
void QtUserSearchWindow::setJIDs(const std::vector<JID> &jids) {
foreach(JID jid, jids) {
- addSearchedJIDToList(jid);
+ addSearchedJIDToList(boost::make_shared<Contact>("", jid, StatusShow::None, ""));
}
onJIDUpdateRequested(jids);
}
void QtUserSearchWindow::setRoomJID(const JID& roomJID) {
roomJID_ = roomJID;
}
std::string QtUserSearchWindow::getReason() const {
return Q2PSTRING(firstMultiJIDPage_->reason_->text());
}
std::vector<JID> QtUserSearchWindow::getJIDs() const {
std::vector<JID> jids;
foreach (Contact::ref contact, contactVector_) {
jids.push_back(contact->jid);
}
return jids;
}
void QtUserSearchWindow::setCanStartImpromptuChats(bool supportsImpromptu) {
supportsImpromptu_ = supportsImpromptu;
if (type_ == ChatToContact) {
firstMultiJIDPage_->contactList_->setMaximumNoOfContactsToOne(!supportsImpromptu_);
}
}
void QtUserSearchWindow::updateContacts(const std::vector<Contact::ref>& contacts) {
if (type_ != AddContact) {
firstMultiJIDPage_->contactList_->updateContacts(contacts);
}
}
void QtUserSearchWindow::addContacts(const std::vector<Contact::ref>& contacts) {
if (type_ != AddContact) {
diff --git a/Swift/QtUI/UserSearch/QtUserSearchWindow.h b/Swift/QtUI/UserSearch/QtUserSearchWindow.h
index 0349ba4..0318b3d 100644
--- a/Swift/QtUI/UserSearch/QtUserSearchWindow.h
+++ b/Swift/QtUI/UserSearch/QtUserSearchWindow.h
@@ -45,56 +45,57 @@ namespace Swift {
virtual void prepopulateJIDAndName(const JID& jid, const std::string& name);
virtual void setContactSuggestions(const std::vector<Contact::ref>& suggestions);
virtual void setJIDs(const std::vector<JID> &jids);
virtual void setRoomJID(const JID &roomJID);
virtual std::string getReason() const;
virtual std::vector<JID> getJIDs() const;
virtual void setCanStartImpromptuChats(bool supportsImpromptu);
virtual void updateContacts(const std::vector<Contact::ref> &contacts);
virtual void addContacts(const std::vector<Contact::ref>& contacts);
virtual void setCanSupplyDescription(bool allowed);
protected:
virtual int nextId() const;
private slots:
void handleFirstPageRadioChange();
virtual void handleCurrentChanged(int);
virtual void handleAccepted();
void handleContactSuggestionRequested(const QString& text);
void addContact();
void handleAddViaSearch();
void handleListChanged(std::vector<Contact::ref> list);
void handleJIDsAdded(std::vector<JID> jids);
private:
void setFirstPage(QString title = "");
void setSecondPage();
void setThirdPage();
private:
void clearForm();
void setError(const QString& error);
JID getServerToSearch();
void handleSearch();
JID getContactJID() const;
- void addSearchedJIDToList(const JID& jid);
+ Contact::ref getContact() const;
+ void addSearchedJIDToList(const Contact::ref& contact);
private:
UIEventStream* eventStream_;
UserSearchWindow::Type type_;
QAbstractItemModel* model_;
UserSearchDelegate* delegate_;
QtUserSearchFirstPage* firstPage_;
QtUserSearchFirstMultiJIDPage* firstMultiJIDPage_;
QtUserSearchFieldsPage* fieldsPage_;
QtUserSearchResultsPage* resultsPage_;
QtUserSearchDetailsPage* detailsPage_;
JID myServer_;
JID roomJID_;
int lastPage_;
std::vector<Contact::ref> contactVector_;
SettingsProvider* settings_;
bool searchNext_;
bool supportsImpromptu_;
};
}