summaryrefslogtreecommitdiffstats
path: root/Swift
diff options
context:
space:
mode:
authorRichard Maudsley <richard.maudsley@isode.com>2014-04-09 07:53:12 (GMT)
committerSwift Review <review@swift.im>2014-04-22 21:12:21 (GMT)
commita7fb55381ab4a5c470bf891b31ac6e201611a2c1 (patch)
tree475b3b7fc0142946863580506b00aa250ef8ca14 /Swift
parent4444aeb255f8d1712b794c31166f362bb3ec335a (diff)
downloadswift-contrib-a7fb55381ab4a5c470bf891b31ac6e201611a2c1.zip
swift-contrib-a7fb55381ab4a5c470bf891b31ac6e201611a2c1.tar.bz2
Fix crash in QtUserSearchWindow.
Avoid storing pointers to items in vectors. Using shared_ptr for Contact items. Change-Id: I3baa05fc058011b2beca14dc620ab794988a2b37
Diffstat (limited to 'Swift')
-rw-r--r--Swift/Controllers/Chat/ChatsManager.cpp8
-rw-r--r--Swift/Controllers/Chat/ChatsManager.h4
-rw-r--r--Swift/Controllers/Chat/UserSearchController.cpp22
-rw-r--r--Swift/Controllers/Chat/UserSearchController.h15
-rw-r--r--Swift/Controllers/Contact.h11
-rw-r--r--Swift/Controllers/ContactProvider.h8
-rw-r--r--Swift/Controllers/ContactSuggester.cpp39
-rw-r--r--Swift/Controllers/ContactSuggester.h14
-rw-r--r--Swift/Controllers/ContactsFromXMPPRoster.cpp16
-rw-r--r--Swift/Controllers/ContactsFromXMPPRoster.h8
-rw-r--r--Swift/Controllers/UIInterfaces/UserSearchWindow.h6
-rw-r--r--Swift/QtUI/UserSearch/ContactListDelegate.cpp8
-rw-r--r--Swift/QtUI/UserSearch/ContactListModel.cpp26
-rw-r--r--Swift/QtUI/UserSearch/ContactListModel.h13
-rw-r--r--Swift/QtUI/UserSearch/QtContactListWidget.cpp18
-rw-r--r--Swift/QtUI/UserSearch/QtContactListWidget.h9
-rw-r--r--Swift/QtUI/UserSearch/QtSuggestingJIDInput.cpp41
-rw-r--r--Swift/QtUI/UserSearch/QtSuggestingJIDInput.h13
-rw-r--r--Swift/QtUI/UserSearch/QtUserSearchFirstMultiJIDPage.cpp2
-rw-r--r--Swift/QtUI/UserSearch/QtUserSearchWindow.cpp37
-rw-r--r--Swift/QtUI/UserSearch/QtUserSearchWindow.h10
21 files changed, 201 insertions, 127 deletions
diff --git a/Swift/Controllers/Chat/ChatsManager.cpp b/Swift/Controllers/Chat/ChatsManager.cpp
index 919a3d6..654f735 100644
--- a/Swift/Controllers/Chat/ChatsManager.cpp
+++ b/Swift/Controllers/Chat/ChatsManager.cpp
@@ -1,37 +1,37 @@
/*
- * Copyright (c) 2010-2013 Kevin Smith
+ * Copyright (c) 2010-2014 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 <boost/smart_ptr/make_shared.hpp>
#include <boost/archive/text_oarchive.hpp>
#include <boost/archive/text_iarchive.hpp>
#include <boost/serialization/vector.hpp>
#include <boost/serialization/map.hpp>
#include <boost/serialization/string.hpp>
#include <boost/serialization/split_free.hpp>
#include <Swiften/Base/foreach.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 <Swiften/Avatars/AvatarManager.h>
#include <Swiften/Elements/MUCInvitationPayload.h>
#include <Swiften/Roster/XMPPRoster.h>
#include <Swiften/Client/ClientBlockListManager.h>
#include <Swiften/Client/StanzaChannel.h>
#include <Swiften/VCards/VCardManager.h>
#include <Swift/Controllers/Chat/ChatController.h>
#include <Swift/Controllers/Chat/ChatControllerBase.h>
#include <Swift/Controllers/Chat/MUCSearchController.h>
@@ -897,52 +897,52 @@ 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> Swift::ChatsManager::getContacts() {
- std::vector<Contact> result;
+std::vector<Contact::ref> Swift::ChatsManager::getContacts() {
+ std::vector<Contact::ref> result;
foreach (ChatListWindow::Chat chat, recentChats_) {
if (!chat.isMUC) {
- result.push_back(Contact(chat.chatName.empty() ? chat.jid.toString() : chat.chatName, chat.jid, chat.statusType, chat.avatarPath));
+ result.push_back(boost::make_shared<Contact>(chat.chatName.empty() ? chat.jid.toString() : chat.chatName, chat.jid, chat.statusType, chat.avatarPath));
}
}
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 979d52a..88a0986 100644
--- a/Swift/Controllers/Chat/ChatsManager.h
+++ b/Swift/Controllers/Chat/ChatsManager.h
@@ -1,37 +1,37 @@
/*
- * Copyright (c) 2010-2013 Kevin Smith
+ * Copyright (c) 2010-2014 Kevin Smith
* Licensed under the GNU General Public License v3.
* See Documentation/Licenses/GPLv3.txt for more information.
*/
#pragma once
#include <map>
#include <string>
#include <boost/shared_ptr.hpp>
#include <Swiften/Base/IDGenerator.h>
#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 <Swiften/MUC/MUCBookmark.h>
#include <Swiften/MUC/MUC.h>
#include <Swift/Controllers/ContactProvider.h>
#include <Swift/Controllers/UIEvents/UIEventStream.h>
#include <Swift/Controllers/UIInterfaces/ChatListWindow.h>
#include <Swift/Controllers/UIInterfaces/ChatWindow.h>
#include <Swift/Controllers/UIInterfaces/ChatWindowFactory.h>
namespace Swift {
class EventController;
class ChatController;
class ChatControllerBase;
class MUCController;
class MUCManager;
class JoinMUCWindow;
@@ -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> getContacts();
+ virtual std::vector<Contact::ref> getContacts();
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);
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 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 appendRecent(const ChatListWindow::Chat& chat);
void prependRecent(const ChatListWindow::Chat& chat);
diff --git a/Swift/Controllers/Chat/UserSearchController.cpp b/Swift/Controllers/Chat/UserSearchController.cpp
index 7844c1b..8503609 100644
--- a/Swift/Controllers/Chat/UserSearchController.cpp
+++ b/Swift/Controllers/Chat/UserSearchController.cpp
@@ -183,113 +183,113 @@ void UserSearchController::handleSearchResponse(boost::shared_ptr<SearchPayload>
}
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) {
window_->setContactSuggestions(contactSuggester_->getSuggestions(text));
}
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) {
if (window_) {
- std::vector<Contact> updates;
+ std::vector<Contact::ref> updates;
foreach(const JID& jid, jids) {
updates.push_back(convertJIDtoContact(jid));
}
window_->updateContacts(updates);
}
}
void UserSearchController::handleJIDAddRequested(const std::vector<JID>& jids) {
- std::vector<Contact> contacts;
+ std::vector<Contact::ref> contacts;
foreach(const JID& jid, jids) {
contacts.push_back(convertJIDtoContact(jid));
}
window_->addContacts(contacts);
}
-Contact UserSearchController::convertJIDtoContact(const JID& jid) {
- Contact contact;
- contact.jid = jid;
+Contact::ref UserSearchController::convertJIDtoContact(const JID& jid) {
+ Contact::ref contact = boost::make_shared<Contact>();
+ contact->jid = jid;
// name lookup
boost::optional<XMPPRosterItem> rosterItem = rosterController_->getItem(jid);
if (rosterItem && !rosterItem->getName().empty()) {
- contact.name = rosterItem->getName();
+ contact->name = rosterItem->getName();
} else {
VCard::ref vcard = vcardManager_->getVCard(jid);
if (vcard && !vcard->getFullName().empty()) {
- contact.name = vcard->getFullName();
+ contact->name = vcard->getFullName();
} else {
- contact.name = jid.toString();
+ contact->name = jid.toString();
}
}
// presence lookup
Presence::ref presence = presenceOracle_->getHighestPriorityPresence(jid);
if (presence) {
- contact.statusType = presence->getShow();
+ contact->statusType = presence->getShow();
} else {
- contact.statusType = StatusShow::None;
+ contact->statusType = StatusShow::None;
}
// avatar lookup
- contact.avatarPath = avatarManager_->getAvatarPath(jid);
+ contact->avatarPath = avatarManager_->getAvatarPath(jid);
return contact;
}
void UserSearchController::handleDiscoWalkFinished() {
window_->setServerSupportsSearch(false);
endDiscoWalker();
}
void UserSearchController::initializeUserWindow() {
if (!window_) {
UserSearchWindow::Type windowType = UserSearchWindow::AddContact;
switch(type_) {
case AddContact:
windowType = UserSearchWindow::AddContact;
break;
case StartChat:
windowType = UserSearchWindow::ChatToContact;
break;
case InviteToChat:
windowType = UserSearchWindow::InviteToChat;
break;
}
window_ = factory_->createUserSearchWindow(windowType, uiEventStream_, rosterController_->getGroups());
window_->onNameSuggestionRequested.connect(boost::bind(&UserSearchController::handleNameSuggestionRequest, this, _1));
window_->onFormRequested.connect(boost::bind(&UserSearchController::handleFormRequested, this, _1));
window_->onSearchRequested.connect(boost::bind(&UserSearchController::handleSearch, this, _1, _2));
window_->onContactSuggestionsRequested.connect(boost::bind(&UserSearchController::handleContactSuggestionsRequested, this, _1));
window_->onJIDUpdateRequested.connect(boost::bind(&UserSearchController::handleJIDUpdateRequested, this, _1));
window_->onJIDAddRequested.connect(boost::bind(&UserSearchController::handleJIDAddRequested, this, _1));
window_->setSelectedService(JID(jid_.getDomain()));
window_->clear();
}
}
diff --git a/Swift/Controllers/Chat/UserSearchController.h b/Swift/Controllers/Chat/UserSearchController.h
index fc4c8e9..d630580 100644
--- a/Swift/Controllers/Chat/UserSearchController.h
+++ b/Swift/Controllers/Chat/UserSearchController.h
@@ -1,90 +1,91 @@
/*
* Copyright (c) 2010-2014 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 <map>
#include <vector>
-#include <Swiften/Base/boost_bsignals.h>
-
-#include <Swiften/Elements/SearchPayload.h>
#include <string>
-#include <Swiften/JID/JID.h>
+
+#include <Swift/Controllers/Contact.h>
+#include <Swiften/Base/boost_bsignals.h>
#include <Swiften/Elements/DiscoInfo.h>
#include <Swiften/Elements/DiscoItems.h>
#include <Swiften/Elements/ErrorPayload.h>
-#include <Swiften/Elements/VCard.h>
#include <Swiften/Elements/Presence.h>
+#include <Swiften/Elements/SearchPayload.h>
+#include <Swiften/Elements/VCard.h>
+#include <Swiften/JID/JID.h>
namespace Swift {
class UIEventStream;
class UIEvent;
class UserSearchWindow;
class UserSearchWindowFactory;
class IQRouter;
class DiscoServiceWalker;
class RosterController;
class VCardManager;
class ContactSuggester;
class AvatarManager;
class PresenceOracle;
- class Contact;
class UserSearchResult {
public:
UserSearchResult(const JID& jid, const std::map<std::string, std::string>& fields) : jid_(jid), fields_(fields) {}
const JID& getJID() const {return jid_;}
const std::map<std::string, std::string>& getFields() const {return fields_;}
private:
JID jid_;
std::map<std::string, std::string> fields_;
};
class UserSearchController {
public:
enum Type {AddContact, StartChat, InviteToChat};
UserSearchController(Type type, const JID& jid, UIEventStream* uiEventStream, VCardManager* vcardManager, UserSearchWindowFactory* userSearchWindowFactory, IQRouter* iqRouter, RosterController* rosterController, ContactSuggester* contactSuggester, AvatarManager* avatarManager, PresenceOracle* presenceOracle);
~UserSearchController();
UserSearchWindow* getUserSearchWindow();
void setCanInitiateImpromptuMUC(bool supportsImpromptu);
private:
void handleUIEvent(boost::shared_ptr<UIEvent> event);
void handleFormRequested(const JID& service);
void handleDiscoServiceFound(const JID& jid, boost::shared_ptr<DiscoInfo> info);
void handleDiscoWalkFinished();
void handleFormResponse(boost::shared_ptr<SearchPayload> items, ErrorPayload::ref error);
void handleSearch(boost::shared_ptr<SearchPayload> fields, const JID& jid);
void handleSearchResponse(boost::shared_ptr<SearchPayload> results, ErrorPayload::ref error);
void handleNameSuggestionRequest(const JID& jid);
void handleContactSuggestionsRequested(std::string text);
void handleVCardChanged(const JID& jid, VCard::ref vcard);
void handleAvatarChanged(const JID& jid);
void handlePresenceChanged(Presence::ref presence);
void handleJIDUpdateRequested(const std::vector<JID>& jids);
void handleJIDAddRequested(const std::vector<JID>& jids);
- Contact convertJIDtoContact(const JID& jid);
+ Contact::ref convertJIDtoContact(const JID& jid);
void endDiscoWalker();
void initializeUserWindow();
private:
Type type_;
JID jid_;
JID suggestionsJID_;
UIEventStream* uiEventStream_;
VCardManager* vcardManager_;
UserSearchWindowFactory* factory_;
IQRouter* iqRouter_;
RosterController* rosterController_;
UserSearchWindow* window_;
DiscoServiceWalker* discoWalker_;
ContactSuggester* contactSuggester_;
AvatarManager* avatarManager_;
PresenceOracle* presenceOracle_;
};
}
diff --git a/Swift/Controllers/Contact.h b/Swift/Controllers/Contact.h
index 039cd23..ceba152 100644
--- a/Swift/Controllers/Contact.h
+++ b/Swift/Controllers/Contact.h
@@ -1,28 +1,37 @@
/*
* 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 <boost/enable_shared_from_this.hpp>
#include <boost/filesystem/path.hpp>
#include <Swiften/Elements/StatusShow.h>
#include <Swiften/JID/JID.h>
namespace Swift {
-class Contact {
+class Contact : public boost::enable_shared_from_this<Contact> {
public:
+ typedef boost::shared_ptr<Contact> ref;
+
Contact();
Contact(const std::string& name, const JID& jid, StatusShow::Type statusType, const boost::filesystem::path& path);
public:
std::string name;
JID jid;
StatusShow::Type statusType;
boost::filesystem::path avatarPath;
};
}
diff --git a/Swift/Controllers/ContactProvider.h b/Swift/Controllers/ContactProvider.h
index 9ce371f..0e56de5 100644
--- a/Swift/Controllers/ContactProvider.h
+++ b/Swift/Controllers/ContactProvider.h
@@ -1,21 +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> getContacts() = 0;
+ virtual std::vector<Contact::ref> getContacts() = 0;
};
}
diff --git a/Swift/Controllers/ContactSuggester.cpp b/Swift/Controllers/ContactSuggester.cpp
index f1104b0..41e0261 100644
--- a/Swift/Controllers/ContactSuggester.cpp
+++ b/Swift/Controllers/ContactSuggester.cpp
@@ -1,80 +1,91 @@
/*
* 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/ContactSuggester.h>
#include <boost/algorithm/string/find.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& c) {
- return fuzzyMatch(c.name, search) || fuzzyMatch(c.jid.toString(), search);
+bool ContactSuggester::matchContact(const std::string& search, const Contact::ref& c) {
+ return fuzzyMatch(c->name, search) || fuzzyMatch(c->jid.toString(), search);
}
-std::vector<Contact> ContactSuggester::getSuggestions(const std::string& search) const {
- std::vector<Contact> results;
+std::vector<Contact::ref> ContactSuggester::getSuggestions(const std::string& search) const {
+ std::vector<Contact::ref> results;
foreach(ContactProvider* provider, contactProviders_) {
append(results, provider->getContacts());
}
- std::sort(results.begin(), results.end(),
- lambda::bind(&Contact::jid, lambda::_1) < lambda::bind(&Contact::jid, lambda::_2));
- results.erase(std::unique(results.begin(), results.end(),
- lambda::bind(&Contact::jid, lambda::_1) == lambda::bind(&Contact::jid, lambda::_2)),
- results.end());
+ std::sort(results.begin(), results.end(), ContactSuggester::contactLexicographicalSortPredicate);
+ results.erase(std::unique(results.begin(), results.end(), ContactSuggester::contactEqualityPredicate), results.end());
results.erase(std::remove_if(results.begin(), results.end(), !lambda::bind(&ContactSuggester::matchContact, search, lambda::_1)),
results.end());
- std::sort(results.begin(), results.end(), ContactSuggester::chatSortPredicate);
+ std::sort(results.begin(), results.end(), ContactSuggester::contactSmartSortPredicate);
return results;
}
bool ContactSuggester::fuzzyMatch(std::string text, std::string match) {
for (std::string::iterator currentQueryChar = match.begin(); currentQueryChar != match.end(); currentQueryChar++) {
//size_t result = text.find(*currentQueryChar);
std::string::iterator result = boost::algorithm::ifind_first(text, std::string(currentQueryChar, currentQueryChar+1)).begin();
if (result == text.end()) {
return false;
}
text.erase(result);
}
return true;
}
-bool ContactSuggester::chatSortPredicate(const Contact& a, const Contact& b) {
- if (a.statusType == b.statusType) {
- return a.name.compare(b.name) < 0;
+bool ContactSuggester::contactLexicographicalSortPredicate(const Contact::ref& a, const Contact::ref& b) {
+ return a->jid < b->jid;
+}
+
+bool ContactSuggester::contactEqualityPredicate(const Contact::ref& a, const Contact::ref& b) {
+ return a->jid == b->jid;
+}
+
+bool ContactSuggester::contactSmartSortPredicate(const Contact::ref& a, const Contact::ref& b) {
+ if (a->statusType == b->statusType) {
+ return a->name.compare(b->name) < 0;
} else {
- return a.statusType < b.statusType;
+ return a->statusType < b->statusType;
}
}
}
diff --git a/Swift/Controllers/ContactSuggester.h b/Swift/Controllers/ContactSuggester.h
index 137e5d3..67b912c 100644
--- a/Swift/Controllers/ContactSuggester.h
+++ b/Swift/Controllers/ContactSuggester.h
@@ -1,36 +1,44 @@
/*
* 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>
namespace Swift {
class ContactProvider;
class ContactSuggester {
public:
ContactSuggester();
~ContactSuggester();
void addContactProvider(ContactProvider* provider);
- std::vector<Contact> getSuggestions(const std::string& search) const;
+ std::vector<Contact::ref> getSuggestions(const std::string& search) const;
private:
- static bool matchContact(const std::string& search, const Contact& c);
+ 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);
- static bool chatSortPredicate(const Contact& a, const Contact& b);
+ static bool contactLexicographicalSortPredicate(const Contact::ref& a, const Contact::ref& b);
+ static bool contactEqualityPredicate(const Contact::ref& a, const Contact::ref& b);
+ static bool contactSmartSortPredicate(const Contact::ref& a, const Contact::ref& b);
private:
std::vector<ContactProvider*> contactProviders_;
};
}
diff --git a/Swift/Controllers/ContactsFromXMPPRoster.cpp b/Swift/Controllers/ContactsFromXMPPRoster.cpp
index 15a7767..7559962 100644
--- a/Swift/Controllers/ContactsFromXMPPRoster.cpp
+++ b/Swift/Controllers/ContactsFromXMPPRoster.cpp
@@ -1,36 +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> ContactsFromXMPPRoster::getContacts() {
- std::vector<Contact> results;
+std::vector<Contact::ref> ContactsFromXMPPRoster::getContacts() {
+ std::vector<Contact::ref> results;
std::vector<XMPPRosterItem> rosterItems = roster_->getItems();
foreach(const XMPPRosterItem& rosterItem, rosterItems) {
- Contact 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);
+ 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 3815a99..4adc606 100644
--- a/Swift/Controllers/ContactsFromXMPPRoster.h
+++ b/Swift/Controllers/ContactsFromXMPPRoster.h
@@ -1,29 +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> getContacts();
+ virtual std::vector<Contact::ref> getContacts();
private:
XMPPRoster* roster_;
AvatarManager* avatarManager_;
PresenceOracle* presenceOracle_;
};
}
diff --git a/Swift/Controllers/UIInterfaces/UserSearchWindow.h b/Swift/Controllers/UIInterfaces/UserSearchWindow.h
index 0245f34..56992cc 100644
--- a/Swift/Controllers/UIInterfaces/UserSearchWindow.h
+++ b/Swift/Controllers/UIInterfaces/UserSearchWindow.h
@@ -1,53 +1,53 @@
/*
* Copyright (c) 2010-2014 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 <vector>
#include <string>
#include <Swiften/JID/JID.h>
#include <Swift/Controllers/Chat/UserSearchController.h>
#include <Swift/Controllers/Contact.h>
namespace Swift {
class UserSearchWindow {
public:
enum Type {AddContact, ChatToContact, InviteToChat};
virtual ~UserSearchWindow() {}
virtual void clear() = 0;
virtual void setResults(const std::vector<UserSearchResult>& results) = 0;
virtual void setResultsForm(const Form::ref results) = 0;
virtual void addSavedServices(const std::vector<JID>& services) = 0;
virtual void setSelectedService(const JID& service) = 0;
virtual void setServerSupportsSearch(bool support) = 0;
virtual void setSearchError(bool support) = 0;
virtual void setSearchFields(boost::shared_ptr<SearchPayload> fields) = 0;
virtual void setNameSuggestions(const std::vector<std::string>& suggestions) = 0;
virtual void prepopulateJIDAndName(const JID& jid, const std::string& name) = 0;
- virtual void setContactSuggestions(const std::vector<Contact>& suggestions) = 0;
+ virtual void setContactSuggestions(const std::vector<Contact::ref>& suggestions) = 0;
virtual void setJIDs(const std::vector<JID>&) = 0;
virtual void setRoomJID(const JID& roomJID) = 0;
virtual std::string getReason() const = 0;
virtual std::vector<JID> getJIDs() const = 0;
virtual void setCanStartImpromptuChats(bool supportsImpromptu) = 0;
- virtual void updateContacts(const std::vector<Contact>& contacts) = 0;
- virtual void addContacts(const std::vector<Contact>& contacts) = 0;
+ virtual void updateContacts(const std::vector<Contact::ref>& contacts) = 0;
+ virtual void addContacts(const std::vector<Contact::ref>& contacts) = 0;
virtual void show() = 0;
boost::signal<void (const JID&)> onFormRequested;
boost::signal<void (boost::shared_ptr<SearchPayload>, const JID&)> onSearchRequested;
boost::signal<void (const JID&)> onNameSuggestionRequested;
boost::signal<void (const std::string&)> onContactSuggestionsRequested;
boost::signal<void (const std::vector<JID>&)> onJIDUpdateRequested;
boost::signal<void (const std::vector<JID>&)> onJIDAddRequested;
};
}
diff --git a/Swift/QtUI/UserSearch/ContactListDelegate.cpp b/Swift/QtUI/UserSearch/ContactListDelegate.cpp
index 29cab83..56c479b 100644
--- a/Swift/QtUI/UserSearch/ContactListDelegate.cpp
+++ b/Swift/QtUI/UserSearch/ContactListDelegate.cpp
@@ -1,46 +1,52 @@
/*
* 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/QtUI/UserSearch/ContactListDelegate.h>
#include <Swift/QtUI/UserSearch/ContactListModel.h>
#include <Swift/Controllers/Contact.h>
#include <Swift/QtUI/QtSwiftUtil.h>
namespace Swift {
ContactListDelegate::ContactListDelegate(bool compact) : compact_(compact) {
}
ContactListDelegate::~ContactListDelegate() {
}
void ContactListDelegate::paint(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const {
if (!index.isValid()) {
return;
}
- const Contact* contact = static_cast<Contact*>(index.internalPointer());
+ const Contact::ref contact = static_cast<Contact*>(index.internalPointer())->shared_from_this();
QColor nameColor = index.data(Qt::TextColorRole).value<QColor>();
QString avatarPath = index.data(ContactListModel::AvatarRole).value<QString>();
QIcon presenceIcon =index.data(ChatListRecentItem::PresenceIconRole).isValid() && !index.data(ChatListRecentItem::PresenceIconRole).value<QIcon>().isNull()
? index.data(ChatListRecentItem::PresenceIconRole).value<QIcon>()
: QIcon(":/icons/offline.png");
QString name = P2QSTRING(contact->name);
QString statusText = P2QSTRING(contact->jid.toString());
common_.paintContact(painter, option, nameColor, avatarPath, presenceIcon, name, statusText, false, 0, compact_);
}
QSize ContactListDelegate::sizeHint(const QStyleOptionViewItem& /*option*/, const QModelIndex& /*index*/ ) const {
QFontMetrics nameMetrics(common_.nameFont);
QFontMetrics statusMetrics(common_.detailFont);
int sizeByText = 2 * common_.verticalMargin + nameMetrics.height() + statusMetrics.height();
return QSize(150, sizeByText);
}
void ContactListDelegate::setCompact(bool compact) {
compact_ = compact;
}
}
diff --git a/Swift/QtUI/UserSearch/ContactListModel.cpp b/Swift/QtUI/UserSearch/ContactListModel.cpp
index 907142f..ef6383c 100644
--- a/Swift/QtUI/UserSearch/ContactListModel.cpp
+++ b/Swift/QtUI/UserSearch/ContactListModel.cpp
@@ -20,116 +20,120 @@
#include <Swift/QtUI/QtSwiftUtil.h>
#include <Swift/QtUI/QtResourceHelper.h>
namespace Swift {
QDataStream& operator >>(QDataStream& in, StatusShow::Type& e){
quint32 buffer;
in >> buffer;
switch(buffer) {
case StatusShow::Online:
e = StatusShow::Online;
break;
case StatusShow::Away:
e = StatusShow::Away;
break;
case StatusShow::FFC:
e = StatusShow::FFC;
break;
case StatusShow::XA:
e = StatusShow::XA;
break;
case StatusShow::DND:
e = StatusShow::DND;
break;
default:
e = StatusShow::None;
break;
}
return in;
}
ContactListModel::ContactListModel(bool editable) : QAbstractItemModel(), editable_(editable) {
}
-void ContactListModel::setList(const std::vector<Contact>& list) {
+void ContactListModel::setList(const std::vector<Contact::ref>& list) {
emit layoutAboutToBeChanged();
contacts_ = list;
emit layoutChanged();
}
-const std::vector<Contact>& ContactListModel::getList() const {
+const std::vector<Contact::ref>& ContactListModel::getList() const {
return contacts_;
}
+Contact::ref ContactListModel::getContact(const size_t i) const {
+ return contacts_[i];
+}
+
Qt::ItemFlags ContactListModel::flags(const QModelIndex& index) const {
Qt::ItemFlags flags = QAbstractItemModel::flags(index);
if (index.isValid()) {
flags = flags & ~Qt::ItemIsDropEnabled;
} else {
flags = Qt::ItemIsDropEnabled | flags;
}
return flags;
}
int ContactListModel::columnCount(const QModelIndex&) const {
return editable_ ? 2 : 1;
}
QVariant ContactListModel::data(const QModelIndex& index, int role) const {
if (boost::numeric_cast<size_t>(index.row()) < contacts_.size()) {
- const Contact& contact = contacts_[index.row()];
+ const Contact::ref& contact = contacts_[index.row()];
if (role == Qt::EditRole) {
- return P2QSTRING(contact.jid.toString());
+ return P2QSTRING(contact->jid.toString());
}
return dataForContact(contact, role);
} else {
return QVariant();
}
}
QModelIndex ContactListModel::index(int row, int column, const QModelIndex& parent) const {
if (!hasIndex(row, column, parent)) {
return QModelIndex();
}
- return boost::numeric_cast<size_t>(row) < contacts_.size() ? createIndex(row, column, (void*)&(contacts_[row])) : QModelIndex();
+ return boost::numeric_cast<size_t>(row) < contacts_.size() ? createIndex(row, column, contacts_[row].get()) : QModelIndex();
}
QModelIndex ContactListModel::parent(const QModelIndex& index) const {
if (!index.isValid()) {
return QModelIndex();
}
return QModelIndex();
}
int ContactListModel::rowCount(const QModelIndex& /*parent*/) const {
return contacts_.size();
}
bool ContactListModel::removeRows(int row, int /*count*/, const QModelIndex& /*parent*/) {
if (boost::numeric_cast<size_t>(row) < contacts_.size()) {
emit layoutAboutToBeChanged();
contacts_.erase(contacts_.begin() + row);
emit layoutChanged();
onListChanged(getList());
return true;
}
return false;
}
-QVariant ContactListModel::dataForContact(const Contact& contact, int role) const {
+QVariant ContactListModel::dataForContact(const Contact::ref& contact, int role) const {
switch (role) {
- case Qt::DisplayRole: return P2QSTRING(contact.name);
- case DetailTextRole: return P2QSTRING(contact.jid.toString());
- case AvatarRole: return QVariant(P2QSTRING(pathToString(contact.avatarPath)));
+ case Qt::DisplayRole: return P2QSTRING(contact->name);
+ case DetailTextRole: return P2QSTRING(contact->jid.toString());
+ case AvatarRole: return QVariant(P2QSTRING(pathToString(contact->avatarPath)));
case PresenceIconRole: return getPresenceIconForContact(contact);
default: return QVariant();
}
}
-QIcon ContactListModel::getPresenceIconForContact(const Contact& contact) const {
- return QIcon(statusShowTypeToIconPath(contact.statusType));
+QIcon ContactListModel::getPresenceIconForContact(const Contact::ref& contact) const {
+ return QIcon(statusShowTypeToIconPath(contact->statusType));
}
}
diff --git a/Swift/QtUI/UserSearch/ContactListModel.h b/Swift/QtUI/UserSearch/ContactListModel.h
index 6ca505e..e582ac4 100644
--- a/Swift/QtUI/UserSearch/ContactListModel.h
+++ b/Swift/QtUI/UserSearch/ContactListModel.h
@@ -4,60 +4,61 @@
* 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 <boost/bind.hpp>
#include <Swiften/Base/boost_bsignals.h>
#include <QAbstractItemModel>
#include <Swift/Controllers/Contact.h>
#include <Swift/QtUI/ChatList/ChatListItem.h>
#include <Swift/QtUI/ChatList/ChatListGroupItem.h>
#include <Swift/QtUI/ChatList/ChatListRecentItem.h>
namespace Swift {
class ContactListModel : public QAbstractItemModel {
Q_OBJECT
public:
enum ContactRoles {
DetailTextRole = Qt::UserRole,
AvatarRole = Qt::UserRole + 1,
PresenceIconRole = Qt::UserRole + 2
};
public:
ContactListModel(bool editable);
- void setList(const std::vector<Contact>& list);
- const std::vector<Contact>& getList() const;
+ void setList(const std::vector<Contact::ref>& list);
+ const std::vector<Contact::ref>& getList() const;
+ Contact::ref getContact(const size_t i) const;
Qt::ItemFlags flags(const QModelIndex& index) const;
int columnCount(const QModelIndex& parent = QModelIndex()) const;
QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const;
QModelIndex index(int row, int column, const QModelIndex & parent = QModelIndex()) const;
QModelIndex parent(const QModelIndex& index) const;
int rowCount(const QModelIndex& parent = QModelIndex()) const;
bool removeRows(int row, int count, const QModelIndex& parent = QModelIndex());
private:
- QVariant dataForContact(const Contact& contact, int role) const;
- QIcon getPresenceIconForContact(const Contact& contact) const;
+ QVariant dataForContact(const Contact::ref& contact, int role) const;
+ QIcon getPresenceIconForContact(const Contact::ref& contact) const;
signals:
- void onListChanged(std::vector<Contact> list);
+ void onListChanged(std::vector<Contact::ref> list);
void onJIDsDropped(const std::vector<JID>& contact);
private:
bool editable_;
- std::vector<Contact> contacts_;
+ std::vector<Contact::ref> contacts_;
};
}
diff --git a/Swift/QtUI/UserSearch/QtContactListWidget.cpp b/Swift/QtUI/UserSearch/QtContactListWidget.cpp
index 6ad1169..4adc929 100644
--- a/Swift/QtUI/UserSearch/QtContactListWidget.cpp
+++ b/Swift/QtUI/UserSearch/QtContactListWidget.cpp
@@ -1,93 +1,97 @@
/*
* 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/QtUI/UserSearch/QtContactListWidget.h>
#include <Swift/QtUI/UserSearch/ContactListModel.h>
#include <Swift/QtUI/UserSearch/ContactListDelegate.h>
#include <Swift/QtUI/QtUISettingConstants.h>
#include <Swift/Controllers/Settings/SettingsProvider.h>
#include <Swift/QtUI/QtVCardWidget/QtRemovableItemDelegate.h>
#include <QHeaderView>
namespace Swift {
QtContactListWidget::QtContactListWidget(QWidget* parent, SettingsProvider* settings) : QTreeView(parent), settings_(settings), limited_(false) {
contactListModel_ = new ContactListModel(true);
setModel(contactListModel_);
- connect(contactListModel_, SIGNAL(onListChanged(std::vector<Contact>)), this, SIGNAL(onListChanged(std::vector<Contact>)));
+ connect(contactListModel_, SIGNAL(onListChanged(std::vector<Contact::ref>)), this, SIGNAL(onListChanged(std::vector<Contact::ref>)));
connect(contactListModel_, SIGNAL(onJIDsDropped(std::vector<JID>)), this, SIGNAL(onJIDsAdded(std::vector<JID>)));
setSelectionMode(QAbstractItemView::SingleSelection);
setSelectionBehavior(QAbstractItemView::SelectRows);
setUniformRowHeights(true);
setAlternatingRowColors(true);
setIndentation(0);
setHeaderHidden(true);
setExpandsOnDoubleClick(false);
setItemsExpandable(false);
setEditTriggers(QAbstractItemView::DoubleClicked);
contactListDelegate_ = new ContactListDelegate(settings->getSetting(QtUISettingConstants::COMPACT_ROSTER));
removableItemDelegate_ = new QtRemovableItemDelegate(style());
setItemDelegateForColumn(0, contactListDelegate_);
setItemDelegateForColumn(1, removableItemDelegate_);
header()->resizeSection(1, removableItemDelegate_->sizeHint(QStyleOptionViewItem(), QModelIndex()).width());
header()->setStretchLastSection(false);
#if QT_VERSION >= 0x050000
header()->setSectionResizeMode(0, QHeaderView::Stretch);
#else
header()->setResizeMode(0, QHeaderView::Stretch);
#endif
}
QtContactListWidget::~QtContactListWidget() {
delete contactListDelegate_;
delete removableItemDelegate_;
}
-void QtContactListWidget::setList(const std::vector<Contact>& list) {
+void QtContactListWidget::setList(const std::vector<Contact::ref>& list) {
contactListModel_->setList(list);
}
-std::vector<Contact> QtContactListWidget::getList() const {
+std::vector<Contact::ref> QtContactListWidget::getList() const {
return contactListModel_->getList();
}
+Contact::ref QtContactListWidget::getContact(const size_t i) {
+ return contactListModel_->getContact(i);
+}
+
void QtContactListWidget::setMaximumNoOfContactsToOne(bool limited) {
limited_ = limited;
}
-void QtContactListWidget::updateContacts(const std::vector<Contact>& contactUpdates) {
- std::vector<Contact> contacts = contactListModel_->getList();
- foreach(const Contact& contactUpdate, contactUpdates) {
+void QtContactListWidget::updateContacts(const std::vector<Contact::ref>& contactUpdates) {
+ std::vector<Contact::ref> contacts = contactListModel_->getList();
+ foreach(const Contact::ref& contactUpdate, contactUpdates) {
for(size_t n = 0; n < contacts.size(); n++) {
- if (contactUpdate.jid == contacts[n].jid) {
+ if (contactUpdate->jid == contacts[n]->jid) {
contacts[n] = contactUpdate;
break;
}
}
}
contactListModel_->setList(contacts);
}
void QtContactListWidget::handleSettingsChanged(const std::string&) {
contactListDelegate_->setCompact(settings_->getSetting(QtUISettingConstants::COMPACT_ROSTER));
}
}
diff --git a/Swift/QtUI/UserSearch/QtContactListWidget.h b/Swift/QtUI/UserSearch/QtContactListWidget.h
index a83b47a..601d320 100644
--- a/Swift/QtUI/UserSearch/QtContactListWidget.h
+++ b/Swift/QtUI/UserSearch/QtContactListWidget.h
@@ -4,58 +4,59 @@
* 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 <QTreeView>
#include <Swift/Controllers/Contact.h>
#include <Swiften/Base/Log.h>
#include <QDragEnterEvent>
#include <QDragMoveEvent>
#include <QDropEvent>
namespace Swift {
class ContactListDelegate;
class ContactListModel;
class SettingsProvider;
class QtRemovableItemDelegate;
class QtContactListWidget : public QTreeView {
Q_OBJECT
public:
QtContactListWidget(QWidget* parent, SettingsProvider* settings);
virtual ~QtContactListWidget();
- void setList(const std::vector<Contact>& list);
- std::vector<Contact> getList() const;
+ void setList(const std::vector<Contact::ref>& list);
+ std::vector<Contact::ref> getList() const;
+ Contact::ref getContact(const size_t i);
void setMaximumNoOfContactsToOne(bool limited);
public slots:
- void updateContacts(const std::vector<Contact>& contactUpdates);
+ void updateContacts(const std::vector<Contact::ref>& contactUpdates);
signals:
- void onListChanged(std::vector<Contact> list);
+ void onListChanged(std::vector<Contact::ref> list);
void onJIDsAdded(const std::vector<JID>& jids);
private:
void handleSettingsChanged(const std::string&);
private:
SettingsProvider* settings_;
ContactListModel* contactListModel_;
ContactListDelegate* contactListDelegate_;
QtRemovableItemDelegate* removableItemDelegate_;
bool limited_;
};
}
diff --git a/Swift/QtUI/UserSearch/QtSuggestingJIDInput.cpp b/Swift/QtUI/UserSearch/QtSuggestingJIDInput.cpp
index de935d9..a4a4610 100644
--- a/Swift/QtUI/UserSearch/QtSuggestingJIDInput.cpp
+++ b/Swift/QtUI/UserSearch/QtSuggestingJIDInput.cpp
@@ -1,168 +1,175 @@
/*
* 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/QtUI/UserSearch/QtSuggestingJIDInput.h>
#include <Swift/QtUI/UserSearch/ContactListDelegate.h>
#include <Swift/Controllers/Settings/SettingsProvider.h>
#include <Swift/QtUI/QtUISettingConstants.h>
#include <Swift/QtUI/UserSearch/ContactListModel.h>
#include <Swiften/Base/boost_bsignals.h>
#include <boost/bind.hpp>
#include <Swift/QtUI/QtSwiftUtil.h>
#include <QAbstractItemView>
#include <QApplication>
#include <QDesktopWidget>
#include <QKeyEvent>
namespace Swift {
-QtSuggestingJIDInput::QtSuggestingJIDInput(QWidget* parent, SettingsProvider* settings) : QLineEdit(parent), settings_(settings), currentContact_(NULL) {
+QtSuggestingJIDInput::QtSuggestingJIDInput(QWidget* parent, SettingsProvider* settings) : QLineEdit(parent), settings_(settings) {
treeViewPopup_ = new QTreeView();
treeViewPopup_->setWindowFlags(Qt::FramelessWindowHint | Qt::WindowStaysOnTopHint | Qt::X11BypassWindowManagerHint);
//treeViewPopup_->setAttribute(Qt::WA_ShowWithoutActivating);
treeViewPopup_->setAlternatingRowColors(true);
treeViewPopup_->setIndentation(0);
treeViewPopup_->setHeaderHidden(true);
treeViewPopup_->setExpandsOnDoubleClick(false);
treeViewPopup_->setItemsExpandable(false);
treeViewPopup_->setSelectionMode(QAbstractItemView::SingleSelection);
treeViewPopup_->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn);
treeViewPopup_->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
QSizePolicy policy(treeViewPopup_->sizePolicy());
policy.setVerticalPolicy(QSizePolicy::Expanding);
treeViewPopup_->setSizePolicy(policy);
treeViewPopup_->hide();
treeViewPopup_->setFocusProxy(this);
connect(treeViewPopup_, SIGNAL(clicked(QModelIndex)), this, SLOT(handleClicked(QModelIndex)));
connect(treeViewPopup_, SIGNAL(doubleClicked(QModelIndex)), this, SLOT(handleClicked(QModelIndex)));
contactListModel_ = new ContactListModel(false);
treeViewPopup_->setModel(contactListModel_);
contactListDelegate_ = new ContactListDelegate(settings->getSetting(QtUISettingConstants::COMPACT_ROSTER));
treeViewPopup_->setItemDelegate(contactListDelegate_);
settings_->onSettingChanged.connect(boost::bind(&QtSuggestingJIDInput::handleSettingsChanged, this, _1));
}
QtSuggestingJIDInput::~QtSuggestingJIDInput() {
settings_->onSettingChanged.disconnect(boost::bind(&QtSuggestingJIDInput::handleSettingsChanged, this, _1));
delete treeViewPopup_;
}
-const Contact* QtSuggestingJIDInput::getContact() {
- if (currentContact_ != NULL) {
+Contact::ref QtSuggestingJIDInput::getContact() {
+ if (!!currentContact_) {
return currentContact_;
- } else {
- if (!text().isEmpty()) {
- JID jid(Q2PSTRING(text()));
- if (jid.isValid()) {
- manualContact_.name = jid.toString();
- manualContact_.jid = jid;
- return &manualContact_;
- }
+ }
+
+ if (!text().isEmpty()) {
+ JID jid(Q2PSTRING(text()));
+ if (jid.isValid()) {
+ Contact::ref manualContact = boost::make_shared<Contact>();
+ manualContact->name = jid.toString();
+ manualContact->jid = jid;
+ return manualContact;
}
- return NULL;
}
+ return boost::shared_ptr<Contact>();
}
-void QtSuggestingJIDInput::setSuggestions(const std::vector<Contact>& suggestions) {
+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_ = NULL;
+ 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_->getList()[index.row()];
+ currentContact_ = contactListModel_->getContact(index.row());
setText(P2QSTRING(currentContact_->jid.toString()));
hidePopup();
clearFocus();
} else {
- currentContact_ = NULL;
+ 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_->getList()[index.row()];
+ currentContact_ = contactListModel_->getContact(index.row());
setText("");
onUserSelected(currentContact_->jid);
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 9ec0512..25e7d42 100644
--- a/Swift/QtUI/UserSearch/QtSuggestingJIDInput.h
+++ b/Swift/QtUI/UserSearch/QtSuggestingJIDInput.h
@@ -1,59 +1,64 @@
/*
* 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 <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();
- const Contact* getContact();
+ Contact::ref getContact();
- void setSuggestions(const std::vector<Contact>& suggestions);
+ void setSuggestions(const std::vector<Contact::ref>& suggestions);
boost::signal<void (const JID&)> 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 manualContact_;
- const Contact* currentContact_;
+ Contact::ref currentContact_;
};
}
diff --git a/Swift/QtUI/UserSearch/QtUserSearchFirstMultiJIDPage.cpp b/Swift/QtUI/UserSearch/QtUserSearchFirstMultiJIDPage.cpp
index 47d62d9..597c88b 100644
--- a/Swift/QtUI/UserSearch/QtUserSearchFirstMultiJIDPage.cpp
+++ b/Swift/QtUI/UserSearch/QtUserSearchFirstMultiJIDPage.cpp
@@ -15,71 +15,71 @@
#include <QMessageBox>
#include <QMimeData>
#include <QUrl>
#include "Swift/QtUI/QtSwiftUtil.h"
#include <Swift/Controllers/Settings/SettingsProvider.h>
#include <Swift/QtUI/UserSearch/QtContactListWidget.h>
#include <Swift/QtUI/UserSearch/QtSuggestingJIDInput.h>
namespace Swift {
QtUserSearchFirstMultiJIDPage::QtUserSearchFirstMultiJIDPage(UserSearchWindow::Type type, const QString& title, SettingsProvider* settings) {
setupUi(this);
setTitle(title);
QString introText = "";
switch (type) {
case UserSearchWindow::AddContact:
introText = tr("Add another user to your contact list");
break;
case UserSearchWindow::ChatToContact:
introText = tr("Chat to another user");
break;
case UserSearchWindow::InviteToChat:
introText = tr("Invite contact to chat");
break;
}
setSubTitle(QString(tr("%1. If you know their address you can enter it directly, or you can search for them.")).arg(introText));
contactList_ = new QtContactListWidget(this, settings);
horizontalLayout_5->addWidget(contactList_);
jid_ = new QtSuggestingJIDInput(this, settings);
horizontalLayout_6->insertWidget(0, jid_);
- connect(contactList_, SIGNAL(onListChanged(std::vector<Contact>)), this, SLOT(emitCompletenessCheck()));
+ connect(contactList_, SIGNAL(onListChanged(std::vector<Contact::ref>)), this, SLOT(emitCompletenessCheck()));
connect(jid_, SIGNAL(editingDone()), this, SLOT(handleEditingDone()));
setAcceptDrops(true);
}
bool QtUserSearchFirstMultiJIDPage::isComplete() const {
return !contactList_->getList().empty();
}
void QtUserSearchFirstMultiJIDPage::reset() {
reason_->clear();
}
void QtUserSearchFirstMultiJIDPage::emitCompletenessCheck() {
emit completeChanged();
}
void QtUserSearchFirstMultiJIDPage::handleEditingDone() {
addContactButton_->setFocus();
}
void QtUserSearchFirstMultiJIDPage::dragEnterEvent(QDragEnterEvent *event) {
if (event->mimeData()->hasFormat("application/vnd.swift.contact-jid-list")
|| event->mimeData()->hasFormat("application/vnd.swift.contact-jid-muc")) {
event->acceptProposedAction();
}
}
void QtUserSearchFirstMultiJIDPage::dropEvent(QDropEvent *event) {
if (event->mimeData()->hasFormat("application/vnd.swift.contact-jid-list")) {
QByteArray dataBytes = event->mimeData()->data("application/vnd.swift.contact-jid-list");
QDataStream dataStream(&dataBytes, QIODevice::ReadOnly);
std::vector<JID> jids;
while (!dataStream.atEnd()) {
QString jidString;
diff --git a/Swift/QtUI/UserSearch/QtUserSearchWindow.cpp b/Swift/QtUI/UserSearch/QtUserSearchWindow.cpp
index ed0fae2..c154c8f 100644
--- a/Swift/QtUI/UserSearch/QtUserSearchWindow.cpp
+++ b/Swift/QtUI/UserSearch/QtUserSearchWindow.cpp
@@ -98,99 +98,98 @@ void QtUserSearchWindow::handleCurrentChanged(int page) {
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) {
return firstPage_->byRemoteSearch_->isChecked() ? JID(Q2PSTRING(firstPage_->service_->currentText().trimmed())) : myServer_;
} else {
return firstMultiJIDPage_->byRemoteSearch_->isChecked() ? JID(Q2PSTRING(firstMultiJIDPage_->service_->currentText().trimmed())) : myServer_;
}
}
void QtUserSearchWindow::handleAccepted() {
JID jid;
std::vector<JID> jids;
switch(type_) {
case AddContact:
jid = getContactJID();
eventStream_->send(boost::make_shared<AddContactUIEvent>(jid, detailsPage_->getName(), detailsPage_->getSelectedGroups()));
break;
case ChatToContact:
if (contactVector_.size() == 1) {
- boost::shared_ptr<UIEvent> event(new RequestChatUIEvent(contactVector_[0].jid));
+ boost::shared_ptr<UIEvent> event(new RequestChatUIEvent(contactVector_[0]->jid));
eventStream_->send(event);
break;
}
- foreach(const Contact& contact, contactVector_) {
- jids.push_back(contact.jid);
+ foreach(Contact::ref contact, contactVector_) {
+ jids.push_back(contact->jid);
}
eventStream_->send(boost::make_shared<CreateImpromptuMUCUIEvent>(jids, JID(), Q2PSTRING(firstMultiJIDPage_->reason_->text())));
break;
case InviteToChat:
- foreach(const Contact& contact, contactVector_) {
- jids.push_back(contact.jid);
+ foreach(Contact::ref contact, contactVector_) {
+ jids.push_back(contact->jid);
}
eventStream_->send(boost::make_shared<InviteToMUCUIEvent>(roomJID_, jids, Q2PSTRING(firstMultiJIDPage_->reason_->text())));
break;
}
}
void QtUserSearchWindow::handleContactSuggestionRequested(const QString& text) {
std::string stdText = Q2PSTRING(text);
onContactSuggestionsRequested(stdText);
}
void QtUserSearchWindow::addContact() {
- if (firstMultiJIDPage_->jid_->getContact() != 0) {
- Contact contact = *(firstMultiJIDPage_->jid_->getContact());
- contactVector_.push_back(contact);
+ if (!!firstMultiJIDPage_->jid_->getContact()) {
+ contactVector_.push_back(firstMultiJIDPage_->jid_->getContact());
}
firstMultiJIDPage_->contactList_->setList(contactVector_);
firstMultiJIDPage_->emitCompletenessCheck();
if (type_ == ChatToContact) {
firstMultiJIDPage_->groupBox->setEnabled(supportsImpromptu_ ? 1 : (contactVector_.size() < 1));
}
}
int QtUserSearchWindow::nextId() const {
if (type_ == AddContact) {
switch (currentId()) {
case 1: return firstPage_->byJID_->isChecked() ? (type_ == AddContact ? 4 : -1) : 2;
case 2: return 3;
case 3: return type_ == AddContact ? 4 : -1;
case 4: return -1;
default: return -1;
}
} else {
switch (currentId()) {
case 1: return searchNext_ ? 2 : -1;
case 2: return 3;
case 3: return 1;
case 4: return -1;
default: return -1;
}
}
}
void QtUserSearchWindow::handleFirstPageRadioChange() {
if (firstPage_->byJID_->isChecked()) {
firstPage_->jid_->setText("");
firstPage_->jid_->setEnabled(true);
firstPage_->service_->setEnabled(false);
restart();
}
@@ -239,270 +238,270 @@ JID QtUserSearchWindow::getContactJID() const {
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 {
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 contact(jid, jid.toString(), StatusShow::None, "");
+ Contact::ref contact = boost::make_shared<Contact>(jid, jid.toString(), StatusShow::None, "");
contactVector_.push_back(contact);
firstMultiJIDPage_->contactList_->setList(contactVector_);
firstMultiJIDPage_->emitCompletenessCheck();
if (type_ == ChatToContact) {
firstMultiJIDPage_->groupBox->setEnabled(supportsImpromptu_ ? 1 : (contactVector_.size() < 1));
}
}
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>& suggestions) {
+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);
}
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 (const Contact& contact, contactVector_) {
- jids.push_back(contact.jid);
+ 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>& contacts) {
+void QtUserSearchWindow::updateContacts(const std::vector<Contact::ref>& contacts) {
if (type_ != AddContact) {
firstMultiJIDPage_->contactList_->updateContacts(contacts);
}
}
-void QtUserSearchWindow::addContacts(const std::vector<Contact>& contacts) {
+void QtUserSearchWindow::addContacts(const std::vector<Contact::ref>& contacts) {
if (type_ != AddContact) {
/* prevent duplicate JIDs from appearing in the contact list */
- foreach (const Contact& newContact, contacts) {
+ foreach (Contact::ref newContact, contacts) {
bool found = false;
- foreach (const Contact& oldContact, contactVector_) {
- if (newContact.jid == oldContact.jid) {
+ foreach (Contact::ref oldContact, contactVector_) {
+ if (newContact->jid == oldContact->jid) {
found = true;
break;
}
}
if (!found) {
contactVector_.push_back(newContact);
}
}
firstMultiJIDPage_->contactList_->setList(contactVector_);
firstMultiJIDPage_->emitCompletenessCheck();
}
}
void QtUserSearchWindow::handleAddViaSearch() {
searchNext_ = true;
next();
}
-void QtUserSearchWindow::handleListChanged(std::vector<Contact> list) {
+void QtUserSearchWindow::handleListChanged(std::vector<Contact::ref> list) {
contactVector_ = list;
if (type_ == ChatToContact) {
firstMultiJIDPage_->groupBox->setEnabled(supportsImpromptu_ ? 1 : (contactVector_.size() < 1));
}
}
void QtUserSearchWindow::handleJIDsAdded(std::vector<JID> jids) {
onJIDAddRequested(jids);
}
void QtUserSearchWindow::setResults(const std::vector<UserSearchResult>& results) {
UserSearchModel *newModel = new UserSearchModel();
newModel->setResults(results);
resultsPage_->results_->setModel(newModel);
resultsPage_->results_->setItemDelegate(delegate_);
resultsPage_->results_->setHeaderHidden(true);
delete model_;
model_ = newModel;
resultsPage_->setNoResults(model_->rowCount() == 0);
resultsPage_->emitCompletenessCheck();
}
void QtUserSearchWindow::setResultsForm(Form::ref results) {
QtFormResultItemModel *newModel = new QtFormResultItemModel(this);
newModel->setForm(results);
resultsPage_->results_->setModel(newModel);
resultsPage_->results_->setItemDelegate(new QItemDelegate());
resultsPage_->results_->setHeaderHidden(false);
#if QT_VERSION >= 0x050000
resultsPage_->results_->header()->setSectionResizeMode(QHeaderView::ResizeToContents);
#else
resultsPage_->results_->header()->setResizeMode(QHeaderView::ResizeToContents);
#endif
delete model_;
model_ = newModel;
resultsPage_->setNoResults(model_->rowCount() == 0);
resultsPage_->emitCompletenessCheck();
}
void QtUserSearchWindow::setSelectedService(const JID& jid) {
myServer_ = jid;
}
void QtUserSearchWindow::setFirstPage(QString title) {
if (page(1) != 0) {
removePage(1);
}
if (type_ == AddContact) {
firstPage_ = new QtUserSearchFirstPage(type_, title.isEmpty() ? firstPage_->title() : title, settings_);
connect(firstPage_->jid_, SIGNAL(textEdited(QString)), this, SLOT(handleContactSuggestionRequested(QString)));
connect(firstPage_->byJID_, SIGNAL(toggled(bool)), this, SLOT(handleFirstPageRadioChange()));
connect(firstPage_->byLocalSearch_, SIGNAL(toggled(bool)), this, SLOT(handleFirstPageRadioChange()));
connect(firstPage_->byRemoteSearch_, SIGNAL(toggled(bool)), this, SLOT(handleFirstPageRadioChange()));
#if QT_VERSION >= 0x040700
firstPage_->jid_->setPlaceholderText(tr("alice@wonderland.lit"));
#endif
firstPage_->service_->setEnabled(false);
setPage(1, firstPage_);
} else {
firstMultiJIDPage_ = new QtUserSearchFirstMultiJIDPage(type_, title.isEmpty() ? firstMultiJIDPage_->title() : title, settings_);
connect(firstMultiJIDPage_->addContactButton_, SIGNAL(clicked()), this, SLOT(addContact()));
connect(firstMultiJIDPage_->jid_, SIGNAL(textEdited(QString)), this, SLOT(handleContactSuggestionRequested(QString)));
firstMultiJIDPage_->jid_->onUserSelected.connect(boost::bind(&QtUserSearchWindow::addSearchedJIDToList, this, _1));
connect(firstMultiJIDPage_->addViaSearchButton_, SIGNAL(clicked()), this, SLOT(handleAddViaSearch()));
- connect(firstMultiJIDPage_->contactList_, SIGNAL(onListChanged(std::vector<Contact>)), this, SLOT(handleListChanged(std::vector<Contact>)));
+ connect(firstMultiJIDPage_->contactList_, SIGNAL(onListChanged(std::vector<Contact::ref>)), this, SLOT(handleListChanged(std::vector<Contact::ref>)));
connect(firstMultiJIDPage_->contactList_, SIGNAL(onJIDsAdded(std::vector<JID>)), this, SLOT(handleJIDsAdded(std::vector<JID>)));
connect(firstMultiJIDPage_, SIGNAL(onJIDsDropped(std::vector<JID>)), this, SLOT(handleJIDsAdded(std::vector<JID>)));
setPage(1, firstMultiJIDPage_);
}
}
void QtUserSearchWindow::setSecondPage() {
if (page(2) != 0) {
removePage(2);
}
fieldsPage_ = new QtUserSearchFieldsPage();
fieldsPage_->fetchingThrobber_->setMovie(new QMovie(":/icons/throbber.gif", QByteArray(), this));
fieldsPage_->fetchingThrobber_->movie()->stop();
setPage(2, fieldsPage_);
}
void QtUserSearchWindow::setThirdPage() {
if (page(3) != 0) {
removePage(3);
}
resultsPage_ = new QtUserSearchResultsPage();
#ifdef SWIFT_PLATFORM_MACOSX
resultsPage_->results_->setAlternatingRowColors(true);
#endif
if (type_ == AddContact) {
connect(resultsPage_, SIGNAL(onUserTriggersContinue()), this, SLOT(next()));
}
else {
connect(resultsPage_, SIGNAL(onUserTriggersContinue()), this, SLOT(next()));
}
setPage(3, resultsPage_);
}
void QtUserSearchWindow::clearForm() {
diff --git a/Swift/QtUI/UserSearch/QtUserSearchWindow.h b/Swift/QtUI/UserSearch/QtUserSearchWindow.h
index 941e455..bb89e51 100644
--- a/Swift/QtUI/UserSearch/QtUserSearchWindow.h
+++ b/Swift/QtUI/UserSearch/QtUserSearchWindow.h
@@ -11,89 +11,89 @@
#include <Swift/QtUI/UserSearch/ui_QtUserSearchWizard.h>
#include <Swift/Controllers/UIInterfaces/UserSearchWindow.h>
namespace Swift {
class UserSearchModel;
class UserSearchDelegate;
class UserSearchResult;
class UIEventStream;
class QtUserSearchFirstPage;
class QtUserSearchFirstMultiJIDPage;
class QtUserSearchFieldsPage;
class QtUserSearchResultsPage;
class QtUserSearchDetailsPage;
class QtFormResultItemModel;
class SettingsProvider;
class QtUserSearchWindow : public QWizard, public UserSearchWindow, private Ui::QtUserSearchWizard {
Q_OBJECT
public:
QtUserSearchWindow(UIEventStream* eventStream, UserSearchWindow::Type type, const std::set<std::string>& groups, SettingsProvider* settingsProvider);
virtual ~QtUserSearchWindow();
virtual void addSavedServices(const std::vector<JID>& services);
virtual void clear();
virtual void show();
virtual void setResults(const std::vector<UserSearchResult>& results);
virtual void setResultsForm(Form::ref results);
virtual void setSelectedService(const JID& jid);
virtual void setServerSupportsSearch(bool error);
virtual void setSearchError(bool error);
virtual void setSearchFields(boost::shared_ptr<SearchPayload> fields);
virtual void setNameSuggestions(const std::vector<std::string>& suggestions);
virtual void prepopulateJIDAndName(const JID& jid, const std::string& name);
- virtual void setContactSuggestions(const std::vector<Contact>& suggestions);
+ 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> &contacts);
- virtual void addContacts(const std::vector<Contact>& contacts);
+ virtual void updateContacts(const std::vector<Contact::ref> &contacts);
+ virtual void addContacts(const std::vector<Contact::ref>& contacts);
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> list);
+ 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);
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> contactVector_;
+ std::vector<Contact::ref> contactVector_;
SettingsProvider* settings_;
bool searchNext_;
bool supportsImpromptu_;
};
}