summaryrefslogtreecommitdiffstats
path: root/Swift
diff options
context:
space:
mode:
Diffstat (limited to 'Swift')
-rw-r--r--Swift/Controllers/Chat/UserSearchController.cpp12
-rw-r--r--Swift/Controllers/Chat/UserSearchController.h3
-rw-r--r--Swift/Controllers/UIInterfaces/UserSearchWindow.h4
-rw-r--r--Swift/QtUI/ChatList/ChatListModel.cpp42
-rw-r--r--Swift/QtUI/ChatList/ChatListModel.h4
-rw-r--r--Swift/QtUI/ChatList/QtChatListWindow.cpp27
-rw-r--r--Swift/QtUI/ChatList/QtChatListWindow.h3
-rw-r--r--Swift/QtUI/QtChatWindow.cpp20
-rw-r--r--Swift/QtUI/Roster/RosterModel.cpp11
-rw-r--r--Swift/QtUI/UserSearch/ContactListModel.cpp43
-rw-r--r--Swift/QtUI/UserSearch/ContactListModel.h7
-rw-r--r--Swift/QtUI/UserSearch/QtContactListWidget.cpp23
-rw-r--r--Swift/QtUI/UserSearch/QtContactListWidget.h9
-rw-r--r--Swift/QtUI/UserSearch/QtUserSearchFirstMultiJIDPage.cpp40
-rw-r--r--Swift/QtUI/UserSearch/QtUserSearchFirstMultiJIDPage.h11
-rw-r--r--Swift/QtUI/UserSearch/QtUserSearchWindow.cpp25
-rw-r--r--Swift/QtUI/UserSearch/QtUserSearchWindow.h3
17 files changed, 193 insertions, 94 deletions
diff --git a/Swift/Controllers/Chat/UserSearchController.cpp b/Swift/Controllers/Chat/UserSearchController.cpp
index 3c7eb67..7844c1b 100644
--- a/Swift/Controllers/Chat/UserSearchController.cpp
+++ b/Swift/Controllers/Chat/UserSearchController.cpp
@@ -1,82 +1,83 @@
/*
- * Copyright (c) 2010 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/UserSearchController.h>
#include <boost/bind.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/smart_ptr/make_shared.hpp>
#include <Swiften/Base/foreach.h>
#include <Swiften/Disco/GetDiscoInfoRequest.h>
#include <Swiften/Disco/GetDiscoItemsRequest.h>
#include <Swiften/Disco/DiscoServiceWalker.h>
#include <Swiften/VCards/VCardManager.h>
#include <Swiften/Presence/PresenceOracle.h>
#include <Swiften/Avatars/AvatarManager.h>
#include <Swift/Controllers/ContactEditController.h>
#include <Swift/Controllers/UIEvents/UIEventStream.h>
#include <Swift/Controllers/UIEvents/RequestChatWithUserDialogUIEvent.h>
#include <Swift/Controllers/UIEvents/RequestAddUserDialogUIEvent.h>
#include <Swift/Controllers/UIEvents/RequestInviteToMUCUIEvent.h>
#include <Swift/Controllers/UIInterfaces/UserSearchWindow.h>
#include <Swift/Controllers/UIInterfaces/UserSearchWindowFactory.h>
#include <Swift/Controllers/Roster/RosterController.h>
#include <Swift/Controllers/ContactSuggester.h>
namespace Swift {
UserSearchController::UserSearchController(Type type, const JID& jid, UIEventStream* uiEventStream, VCardManager* vcardManager, UserSearchWindowFactory* factory, IQRouter* iqRouter, RosterController* rosterController, ContactSuggester* contactSuggester, AvatarManager* avatarManager, PresenceOracle* presenceOracle) : type_(type), jid_(jid), uiEventStream_(uiEventStream), vcardManager_(vcardManager), factory_(factory), iqRouter_(iqRouter), rosterController_(rosterController), contactSuggester_(contactSuggester), avatarManager_(avatarManager), presenceOracle_(presenceOracle) {
uiEventStream_->onUIEvent.connect(boost::bind(&UserSearchController::handleUIEvent, this, _1));
vcardManager_->onVCardChanged.connect(boost::bind(&UserSearchController::handleVCardChanged, this, _1, _2));
avatarManager_->onAvatarChanged.connect(boost::bind(&UserSearchController::handleAvatarChanged, this, _1));
presenceOracle_->onPresenceChange.connect(boost::bind(&UserSearchController::handlePresenceChanged, this, _1));
window_ = NULL;
discoWalker_ = NULL;
}
UserSearchController::~UserSearchController() {
endDiscoWalker();
delete discoWalker_;
if (window_) {
window_->onNameSuggestionRequested.disconnect(boost::bind(&UserSearchController::handleNameSuggestionRequest, this, _1));
window_->onFormRequested.disconnect(boost::bind(&UserSearchController::handleFormRequested, this, _1));
window_->onSearchRequested.disconnect(boost::bind(&UserSearchController::handleSearch, this, _1, _2));
window_->onJIDUpdateRequested.disconnect(boost::bind(&UserSearchController::handleJIDUpdateRequested, this, _1));
+ window_->onJIDAddRequested.disconnect(boost::bind(&UserSearchController::handleJIDAddRequested, this, _1));
delete window_;
}
presenceOracle_->onPresenceChange.disconnect(boost::bind(&UserSearchController::handlePresenceChanged, this, _1));
avatarManager_->onAvatarChanged.disconnect(boost::bind(&UserSearchController::handleAvatarChanged, this, _1));
vcardManager_->onVCardChanged.disconnect(boost::bind(&UserSearchController::handleVCardChanged, this, _1, _2));
uiEventStream_->onUIEvent.disconnect(boost::bind(&UserSearchController::handleUIEvent, this, _1));
}
UserSearchWindow* UserSearchController::getUserSearchWindow() {
initializeUserWindow();
assert(window_);
return window_;
}
void UserSearchController::setCanInitiateImpromptuMUC(bool supportsImpromptu) {
if (!window_) {
initializeUserWindow();
}
window_->setCanStartImpromptuChats(supportsImpromptu);
}
void UserSearchController::handleUIEvent(boost::shared_ptr<UIEvent> event) {
bool handle = false;
boost::shared_ptr<RequestAddUserDialogUIEvent> addUserRequest = boost::shared_ptr<RequestAddUserDialogUIEvent>();
RequestInviteToMUCUIEvent::ref inviteToMUCRequest = RequestInviteToMUCUIEvent::ref();
switch (type_) {
case AddContact:
if ((addUserRequest = boost::dynamic_pointer_cast<RequestAddUserDialogUIEvent>(event))) {
handle = true;
}
break;
case StartChat:
if (boost::dynamic_pointer_cast<RequestChatWithUserDialogUIEvent>(event)) {
handle = true;
}
@@ -190,97 +191,106 @@ void UserSearchController::handleNameSuggestionRequest(const JID &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;
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;
+ foreach(const JID& jid, jids) {
+ contacts.push_back(convertJIDtoContact(jid));
+ }
+ window_->addContacts(contacts);
+}
+
Contact UserSearchController::convertJIDtoContact(const JID& jid) {
Contact contact;
contact.jid = jid;
// name lookup
boost::optional<XMPPRosterItem> rosterItem = rosterController_->getItem(jid);
if (rosterItem && !rosterItem->getName().empty()) {
contact.name = rosterItem->getName();
} else {
VCard::ref vcard = vcardManager_->getVCard(jid);
if (vcard && !vcard->getFullName().empty()) {
contact.name = vcard->getFullName();
} else {
contact.name = jid.toString();
}
}
// presence lookup
Presence::ref presence = presenceOracle_->getHighestPriorityPresence(jid);
if (presence) {
contact.statusType = presence->getShow();
} else {
contact.statusType = StatusShow::None;
}
// avatar lookup
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 21cad5e..fc4c8e9 100644
--- a/Swift/Controllers/Chat/UserSearchController.h
+++ b/Swift/Controllers/Chat/UserSearchController.h
@@ -1,89 +1,90 @@
/*
- * Copyright (c) 2010 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 <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 <Swiften/Elements/DiscoInfo.h>
#include <Swiften/Elements/DiscoItems.h>
#include <Swiften/Elements/ErrorPayload.h>
#include <Swiften/Elements/VCard.h>
#include <Swiften/Elements/Presence.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);
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/UIInterfaces/UserSearchWindow.h b/Swift/Controllers/UIInterfaces/UserSearchWindow.h
index 9dd1811..0245f34 100644
--- a/Swift/Controllers/UIInterfaces/UserSearchWindow.h
+++ b/Swift/Controllers/UIInterfaces/UserSearchWindow.h
@@ -1,51 +1,53 @@
/*
- * Copyright (c) 2010 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 <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 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 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/ChatList/ChatListModel.cpp b/Swift/QtUI/ChatList/ChatListModel.cpp
index 7913c61..d09b0dd 100644
--- a/Swift/QtUI/ChatList/ChatListModel.cpp
+++ b/Swift/QtUI/ChatList/ChatListModel.cpp
@@ -1,117 +1,157 @@
/*
- * Copyright (c) 2010-2011 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/QtUI/ChatList/ChatListModel.h>
+#include <QMimeData>
+#include <QUrl>
+
#include <Swift/QtUI/ChatList/ChatListMUCItem.h>
#include <Swift/QtUI/ChatList/ChatListRecentItem.h>
#include <Swift/QtUI/ChatList/ChatListWhiteboardItem.h>
+#include <Swift/QtUI/QtSwiftUtil.h>
namespace Swift {
ChatListModel::ChatListModel() : whiteboards_(NULL) {
root_ = new ChatListGroupItem("", NULL, false);
mucBookmarks_ = new ChatListGroupItem(tr("Bookmarked Rooms"), root_);
recents_ = new ChatListGroupItem(tr("Recent Chats"), root_, false);
#ifdef SWIFT_EXPERIMENTAL_WB
whiteboards_ = new ChatListGroupItem(tr("Opened Whiteboards"), root_, false);
root_->addItem(whiteboards_);
#endif
root_->addItem(recents_);
root_->addItem(mucBookmarks_);
}
+Qt::ItemFlags ChatListModel::flags(const QModelIndex& index) const {
+ Qt::ItemFlags flags = QAbstractItemModel::flags(index);
+ if (dynamic_cast<ChatListRecentItem*>(getItemForIndex(index))) {
+ flags |= Qt::ItemIsDragEnabled;
+ }
+ return flags;
+}
+
void ChatListModel::clearBookmarks() {
emit layoutAboutToBeChanged();
mucBookmarks_->clear();
emit layoutChanged();
}
void ChatListModel::addMUCBookmark(const Swift::MUCBookmark& bookmark) {
emit layoutAboutToBeChanged();
mucBookmarks_->addItem(new ChatListMUCItem(bookmark, mucBookmarks_));
emit layoutChanged();
//QModelIndex index = createIndex(mucBookmarks_->rowCount() - 1, 0, mucBookmarks_);
//emit dataChanged(index, index);
//emit dataChanged(parent(index), parent(index));
}
void ChatListModel::removeMUCBookmark(const Swift::MUCBookmark& bookmark) {
for (int i = 0; i < mucBookmarks_->rowCount(); i++) {
ChatListMUCItem* item = dynamic_cast<ChatListMUCItem*>(mucBookmarks_->item(i));
if (item->getBookmark() == bookmark) {
emit layoutAboutToBeChanged();
mucBookmarks_->remove(i);
emit layoutChanged();
break;
}
}
}
void ChatListModel::addWhiteboardSession(const ChatListWindow::Chat& chat) {
emit layoutAboutToBeChanged();
whiteboards_->addItem(new ChatListWhiteboardItem(chat, whiteboards_));
emit layoutChanged();
}
void ChatListModel::removeWhiteboardSession(const JID& jid) {
for (int i = 0; i < whiteboards_->rowCount(); i++) {
ChatListWhiteboardItem* item = dynamic_cast<ChatListWhiteboardItem*>(whiteboards_->item(i));
if (item->getChat().jid == jid) {
emit layoutAboutToBeChanged();
whiteboards_->remove(i);
emit layoutChanged();
break;
}
}
}
void ChatListModel::setRecents(const std::list<ChatListWindow::Chat>& recents) {
emit layoutAboutToBeChanged();
recents_->clear();
foreach (const ChatListWindow::Chat chat, recents) {
recents_->addItem(new ChatListRecentItem(chat, recents_));
//whiteboards_->addItem(new ChatListRecentItem(chat, whiteboards_));
}
emit layoutChanged();
}
+QMimeData* ChatListModel::mimeData(const QModelIndexList& indexes) const {
+ QMimeData* data = QAbstractItemModel::mimeData(indexes);
+ ChatListRecentItem *item = dynamic_cast<ChatListRecentItem*>(getItemForIndex(indexes.first()));
+ if (item == NULL) {
+ return data;
+ }
+
+ QByteArray itemData;
+ QDataStream dataStream(&itemData, QIODevice::WriteOnly);
+ const ChatListWindow::Chat& chat = item->getChat();
+
+ QString mimeType = "application/vnd.swift.contact-jid-list";
+ if (!chat.impromptuJIDs.size()) {
+ if (chat.isMUC) {
+ mimeType = "application/vnd.swift.contact-jid-muc";
+ }
+ dataStream << P2QSTRING(chat.jid.toString());
+ } else {
+ typedef std::map<std::string, JID> JIDMap;
+ foreach (const JIDMap::value_type& jid, chat.impromptuJIDs) {
+ dataStream << P2QSTRING(jid.second.toString());
+ }
+ }
+
+ data->setData(mimeType, itemData);
+ return data;
+}
+
int ChatListModel::columnCount(const QModelIndex& /*parent*/) const {
return 1;
}
ChatListItem* ChatListModel::getItemForIndex(const QModelIndex& index) const {
return index.isValid() ? static_cast<ChatListItem*>(index.internalPointer()) : NULL;
}
QVariant ChatListModel::data(const QModelIndex& index, int role) const {
ChatListItem* item = getItemForIndex(index);
return item ? item->data(role) : QVariant();
}
QModelIndex ChatListModel::index(int row, int column, const QModelIndex & parent) const {
if (!hasIndex(row, column, parent)) {
return QModelIndex();
}
ChatListGroupItem *parentItem = parent.isValid() ? static_cast<ChatListGroupItem*>(parent.internalPointer()) : root_;
return row < parentItem->rowCount() ? createIndex(row, column, parentItem->item(row)) : QModelIndex();
}
QModelIndex ChatListModel::parent(const QModelIndex& index) const {
if (!index.isValid()) {
return QModelIndex();
}
ChatListGroupItem* parent = static_cast<ChatListGroupItem*>(index.internalPointer())->parent();
return (parent == root_) ? QModelIndex() : createIndex(parent->parent()->row(parent), 0, parent);
}
int ChatListModel::rowCount(const QModelIndex& parentIndex) const {
ChatListGroupItem* parent = NULL;
if (parentIndex.isValid()) {
parent = dynamic_cast<ChatListGroupItem*>(static_cast<ChatListItem*>(parentIndex.internalPointer()));
diff --git a/Swift/QtUI/ChatList/ChatListModel.h b/Swift/QtUI/ChatList/ChatListModel.h
index 04e369a..a15cbcd 100644
--- a/Swift/QtUI/ChatList/ChatListModel.h
+++ b/Swift/QtUI/ChatList/ChatListModel.h
@@ -1,41 +1,43 @@
/*
- * Copyright (c) 2010-2011 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 <QAbstractItemModel>
#include <QList>
#include <Swiften/MUC/MUCBookmark.h>
#include <Swift/Controllers/UIInterfaces/ChatListWindow.h>
#include <Swift/QtUI/ChatList/ChatListGroupItem.h>
namespace Swift {
class ChatListModel : public QAbstractItemModel {
Q_OBJECT
public:
ChatListModel();
+ Qt::ItemFlags flags(const QModelIndex& index) const;
void addMUCBookmark(const MUCBookmark& bookmark);
void removeMUCBookmark(const MUCBookmark& bookmark);
void addWhiteboardSession(const ChatListWindow::Chat& chat);
void removeWhiteboardSession(const JID& jid);
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;
ChatListItem* getItemForIndex(const QModelIndex& index) const;
void clearBookmarks();
void setRecents(const std::list<ChatListWindow::Chat>& recents);
+ QMimeData* mimeData(const QModelIndexList& indexes) const;
private:
ChatListGroupItem* mucBookmarks_;
ChatListGroupItem* recents_;
ChatListGroupItem* whiteboards_;
ChatListGroupItem* root_;
};
}
diff --git a/Swift/QtUI/ChatList/QtChatListWindow.cpp b/Swift/QtUI/ChatList/QtChatListWindow.cpp
index 4d1f19b..7455fb5 100644
--- a/Swift/QtUI/ChatList/QtChatListWindow.cpp
+++ b/Swift/QtUI/ChatList/QtChatListWindow.cpp
@@ -1,80 +1,82 @@
/*
- * Copyright (c) 2010-2011 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/QtUI/ChatList/QtChatListWindow.h"
#include <boost/bind.hpp>
-#include <QMenu>
#include <QContextMenuEvent>
+#include <QMenu>
+#include <QMimeData>
+#include <QUrl>
+#include <Swift/Controllers/Settings/SettingsProvider.h>
+#include <Swift/Controllers/UIEvents/AddMUCBookmarkUIEvent.h>
+#include <Swift/Controllers/UIEvents/EditMUCBookmarkUIEvent.h>
+#include <Swift/Controllers/UIEvents/JoinMUCUIEvent.h>
+#include <Swift/Controllers/UIEvents/RemoveMUCBookmarkUIEvent.h>
+#include <Swift/Controllers/UIEvents/RequestChatUIEvent.h>
+#include <Swift/Controllers/UIEvents/ShowWhiteboardUIEvent.h>
#include <Swift/QtUI/ChatList/ChatListMUCItem.h>
#include <Swift/QtUI/ChatList/ChatListRecentItem.h>
#include <Swift/QtUI/ChatList/ChatListWhiteboardItem.h>
#include <Swift/QtUI/QtAddBookmarkWindow.h>
#include <Swift/QtUI/QtEditBookmarkWindow.h>
#include <Swift/QtUI/QtUISettingConstants.h>
-#include <Swift/Controllers/UIEvents/JoinMUCUIEvent.h>
-#include <Swift/Controllers/UIEvents/RequestChatUIEvent.h>
-#include <Swift/Controllers/UIEvents/AddMUCBookmarkUIEvent.h>
-#include <Swift/Controllers/UIEvents/RemoveMUCBookmarkUIEvent.h>
-#include <Swift/Controllers/UIEvents/EditMUCBookmarkUIEvent.h>
-#include <Swift/Controllers/UIEvents/ShowWhiteboardUIEvent.h>
-#include <Swift/Controllers/Settings/SettingsProvider.h>
-
namespace Swift {
QtChatListWindow::QtChatListWindow(UIEventStream *uiEventStream, SettingsProvider* settings, QWidget* parent) : QTreeView(parent) {
eventStream_ = uiEventStream;
settings_ = settings;
bookmarksEnabled_ = false;
model_ = new ChatListModel();
setModel(model_);
delegate_ = new ChatListDelegate(settings_->getSetting(QtUISettingConstants::COMPACT_ROSTER));
setItemDelegate(delegate_);
setHeaderHidden(true);
#ifdef SWIFT_PLATFORM_MACOSX
setAlternatingRowColors(true);
#endif
expandAll();
setAnimated(true);
setIndentation(0);
+ setDragEnabled(true);
setRootIsDecorated(true);
setupContextMenus();
connect(this, SIGNAL(activated(const QModelIndex&)), this, SLOT(handleItemActivated(const QModelIndex&)));
connect(this, SIGNAL(clicked(const QModelIndex&)), this, SLOT(handleClicked(const QModelIndex&)));
settings_->onSettingChanged.connect(boost::bind(&QtChatListWindow::handleSettingChanged, this, _1));
}
QtChatListWindow::~QtChatListWindow() {
settings_->onSettingChanged.disconnect(boost::bind(&QtChatListWindow::handleSettingChanged, this, _1));
delete model_;
delete delegate_;
delete mucMenu_;
delete emptyMenu_;
}
void QtChatListWindow::handleSettingChanged(const std::string& setting) {
if (setting == QtUISettingConstants::COMPACT_ROSTER.getKey()) {
delegate_->setCompact(settings_->getSetting(QtUISettingConstants::COMPACT_ROSTER));
repaint();
}
}
void QtChatListWindow::setBookmarksEnabled(bool enabled) {
bookmarksEnabled_ = enabled;
}
void QtChatListWindow::handleClicked(const QModelIndex& index) {
ChatListGroupItem* item = dynamic_cast<ChatListGroupItem*>(static_cast<ChatListItem*>(index.internalPointer()));
if (item) {
setExpanded(index, !isExpanded(index));
}
}
void QtChatListWindow::setupContextMenus() {
@@ -120,63 +122,68 @@ void QtChatListWindow::removeMUCBookmark(const MUCBookmark& bookmark) {
void QtChatListWindow::addWhiteboardSession(const ChatListWindow::Chat& chat) {
model_->addWhiteboardSession(chat);
}
void QtChatListWindow::removeWhiteboardSession(const JID& jid) {
model_->removeWhiteboardSession(jid);
}
void QtChatListWindow::setRecents(const std::list<ChatListWindow::Chat>& recents) {
model_->setRecents(recents);
}
void QtChatListWindow::setUnreadCount(int unread) {
emit onCountUpdated(unread);
}
void QtChatListWindow::handleRemoveBookmark() {
ChatListMUCItem* mucItem = dynamic_cast<ChatListMUCItem*>(contextMenuItem_);
if (!mucItem) return;
eventStream_->send(boost::shared_ptr<UIEvent>(new RemoveMUCBookmarkUIEvent(mucItem->getBookmark())));
}
void QtChatListWindow::handleAddBookmark() {
(new QtAddBookmarkWindow(eventStream_))->show();
}
void QtChatListWindow::handleEditBookmark() {
ChatListMUCItem* mucItem = dynamic_cast<ChatListMUCItem*>(contextMenuItem_);
if (!mucItem) return;
QtEditBookmarkWindow* window = new QtEditBookmarkWindow(eventStream_, mucItem->getBookmark());
window->show();
}
+void QtChatListWindow::dragEnterEvent(QDragEnterEvent *event) {
+ if (event->mimeData()->hasUrls() && event->mimeData()->urls().size() == 1) {
+ event->acceptProposedAction();
+ }
+}
void QtChatListWindow::contextMenuEvent(QContextMenuEvent* event) {
QModelIndex index = indexAt(event->pos());
ChatListItem* baseItem = index.isValid() ? static_cast<ChatListItem*>(index.internalPointer()) : NULL;
contextMenuItem_ = baseItem;
if (!baseItem) {
emptyMenu_->exec(QCursor::pos());
return;
}
ChatListMUCItem* mucItem = dynamic_cast<ChatListMUCItem*>(baseItem);
if (mucItem) {
if (!bookmarksEnabled_) {
return;
}
mucMenu_->exec(QCursor::pos());
}
else {
QMenu menu;
QAction* clearRecents = menu.addAction(tr("Clear recents"));
menu.addAction(clearRecents);
QAction* result = menu.exec(event->globalPos());
if (result == clearRecents) {
onClearRecentsRequested();
}
}
}
}
diff --git a/Swift/QtUI/ChatList/QtChatListWindow.h b/Swift/QtUI/ChatList/QtChatListWindow.h
index ef4ce0f..e218266 100644
--- a/Swift/QtUI/ChatList/QtChatListWindow.h
+++ b/Swift/QtUI/ChatList/QtChatListWindow.h
@@ -1,57 +1,58 @@
/*
- * Copyright (c) 2010-2011 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 <QTreeView>
#include "Swift/Controllers/UIInterfaces/ChatListWindow.h"
#include "Swift/Controllers/UIEvents/UIEventStream.h"
#include "Swift/QtUI/ChatList/ChatListModel.h"
#include "Swift/QtUI/ChatList/ChatListDelegate.h"
namespace Swift {
class SettingsProvider;
class QtChatListWindow : public QTreeView, public ChatListWindow {
Q_OBJECT
public:
QtChatListWindow(UIEventStream *uiEventStream, SettingsProvider* settings, QWidget* parent = NULL);
virtual ~QtChatListWindow();
void addMUCBookmark(const MUCBookmark& bookmark);
void removeMUCBookmark(const MUCBookmark& bookmark);
void addWhiteboardSession(const ChatListWindow::Chat& chat);
void removeWhiteboardSession(const JID& jid);
void setBookmarksEnabled(bool enabled);
void setRecents(const std::list<ChatListWindow::Chat>& recents);
void setUnreadCount(int unread);
void clearBookmarks();
signals:
void onCountUpdated(int count);
private slots:
void handleItemActivated(const QModelIndex&);
void handleAddBookmark();
void handleEditBookmark();
void handleRemoveBookmark();
void handleClicked(const QModelIndex& index);
void handleSettingChanged(const std::string& setting);
protected:
+ void dragEnterEvent(QDragEnterEvent* event);
void contextMenuEvent(QContextMenuEvent* event);
private:
void setupContextMenus();
bool bookmarksEnabled_;
UIEventStream* eventStream_;
ChatListModel* model_;
ChatListDelegate* delegate_;
QMenu* mucMenu_;
QMenu* emptyMenu_;
ChatListItem* contextMenuItem_;
SettingsProvider* settings_;
};
}
diff --git a/Swift/QtUI/QtChatWindow.cpp b/Swift/QtUI/QtChatWindow.cpp
index bd7c817..d3cce6d 100644
--- a/Swift/QtUI/QtChatWindow.cpp
+++ b/Swift/QtUI/QtChatWindow.cpp
@@ -1,68 +1,69 @@
/*
- * 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/QtUI/QtChatWindow.h>
#include <boost/cstdint.hpp>
#include <boost/lexical_cast.hpp>
#include <boost/smart_ptr/make_shared.hpp>
#include <qdebug.h>
#include <QApplication>
#include <QBoxLayout>
#include <QCloseEvent>
#include <QComboBox>
#include <QFileDialog>
#include <QFileInfo>
#include <QInputDialog>
#include <QLabel>
#include <QLineEdit>
#include <QMenu>
#include <QMessageBox>
#include <QMimeData>
#include <QPushButton>
#include <QSplitter>
#include <QString>
#include <QTextDocument>
#include <QTextEdit>
#include <QTime>
#include <QToolButton>
#include <QUrl>
+#include <QMimeData>
#include <Swiften/Base/Log.h>
#include <Swift/Controllers/Roster/ContactRosterItem.h>
#include <Swift/Controllers/Roster/Roster.h>
#include <Swift/Controllers/Roster/RosterItem.h>
#include <Swift/Controllers/Settings/SettingsProvider.h>
#include <Swift/Controllers/UIEvents/UIEventStream.h>
#include <Swift/Controllers/UIEvents/SendFileUIEvent.h>
#include <Swift/Controllers/UIEvents/JoinMUCUIEvent.h>
#include <SwifTools/TabComplete.h>
#include <Swift/QtUI/Roster/QtOccupantListWidget.h>
#include <Swift/QtUI/QtPlainChatView.h>
#include <Swift/QtUI/QtSettingsProvider.h>
#include <Swift/QtUI/QtScaledAvatarCache.h>
#include <Swift/QtUI/QtTextEdit.h>
#include <Swift/QtUI/QtUISettingConstants.h>
#include <Swift/QtUI/QtUtilities.h>
#include <Swift/QtUI/QtWebKitChatView.h>
namespace Swift {
QtChatWindow::QtChatWindow(const QString &contact, QtChatTheme* theme, UIEventStream* eventStream, SettingsProvider* settings) : QtTabbable(), contact_(contact), eventStream_(eventStream), blockingState_(BlockingUnsupported), isMUC_(false), supportsImpromptuChat_(false) {
settings_ = settings;
unreadCount_ = 0;
inputEnabled_ = true;
completer_ = NULL;
affiliationEditor_ = NULL;
theme_ = theme;
isCorrection_ = false;
labelModel_ = NULL;
correctionEnabled_ = Maybe;
updateTitleWithUnreadCount();
@@ -508,97 +509,100 @@ void QtChatWindow::handleCursorPositionChanged() {
if (tabCompletion_) {
return;
}
tabCompleteCursor_.clearSelection();
}
void QtChatWindow::show() {
if (parentWidget() == NULL) {
QWidget::show();
}
emit windowOpening();
}
void QtChatWindow::activate() {
if (isWindow()) {
QWidget::show();
}
emit wantsToActivate();
input_->setFocus();
}
void QtChatWindow::resizeEvent(QResizeEvent*) {
emit geometryChanged();
}
void QtChatWindow::moveEvent(QMoveEvent*) {
emit geometryChanged();
}
void QtChatWindow::dragEnterEvent(QDragEnterEvent *event) {
if (event->mimeData()->hasUrls() && event->mimeData()->urls().size() == 1) {
// TODO: check whether contact actually supports file transfer
if (!isMUC_) {
event->acceptProposedAction();
}
- } else if (event->mimeData()->hasFormat("application/vnd.swift.contact-jid")) {
+ } else if (event->mimeData()->hasFormat("application/vnd.swift.contact-jid-list")) {
if (isMUC_ || supportsImpromptuChat_) {
event->acceptProposedAction();
}
}
}
void QtChatWindow::dropEvent(QDropEvent *event) {
if (event->mimeData()->hasUrls()) {
if (event->mimeData()->urls().size() == 1) {
onSendFileRequest(Q2PSTRING(event->mimeData()->urls().at(0).toLocalFile()));
} else {
std::string messageText(Q2PSTRING(tr("Sending of multiple files at once isn't supported at this time.")));
ChatMessage message;
message.append(boost::make_shared<ChatTextMessagePart>(messageText));
addSystemMessage(message, DefaultDirection);
}
- } else if (event->mimeData()->hasFormat("application/vnd.swift.contact-jid")) {
- QByteArray dataBytes = event->mimeData()->data("application/vnd.swift.contact-jid");
+ } else 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);
- QString jidString;
- dataStream >> jidString;
- onInviteToChat(std::vector<JID>(1, JID(Q2PSTRING(jidString))));
+ std::vector<JID> invites;
+ while (!dataStream.atEnd()) {
+ QString jidString;
+ dataStream >> jidString;
+ invites.push_back(Q2PSTRING(jidString));
+ }
+ onInviteToChat(invites);
}
}
-
void QtChatWindow::setAvailableOccupantActions(const std::vector<OccupantAction>& actions) {
treeWidget_->setAvailableOccupantActions(actions);
}
void QtChatWindow::setSubject(const std::string& subject) {
//subject_->setVisible(!subject.empty());
subject_->setText(P2QSTRING(subject));
subject_->setToolTip(P2QSTRING(subject));
subject_->setCursorPosition(0);
}
void QtChatWindow::handleActionButtonClicked() {
QMenu contextMenu;
QAction* changeSubject = NULL;
QAction* configure = NULL;
QAction* affiliations = NULL;
QAction* destroy = NULL;
QAction* invite = NULL;
QAction* block = NULL;
QAction* unblock = NULL;
if (availableRoomActions_.empty()) {
if (blockingState_ == IsBlocked) {
unblock = contextMenu.addAction(tr("Unblock"));
} else if (blockingState_ == IsUnblocked) {
block = contextMenu.addAction(tr("Block"));
}
if (supportsImpromptuChat_) {
invite = contextMenu.addAction(tr("Invite person to this chat…"));
}
} else {
foreach(ChatWindow::RoomAction availableAction, availableRoomActions_)
diff --git a/Swift/QtUI/Roster/RosterModel.cpp b/Swift/QtUI/Roster/RosterModel.cpp
index 2bd0d09..d8108ba 100644
--- a/Swift/QtUI/Roster/RosterModel.cpp
+++ b/Swift/QtUI/Roster/RosterModel.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/QtUI/Roster/RosterModel.h>
#include <boost/bind.hpp>
#include <QColor>
#include <QIcon>
#include <QMimeData>
#include <qdebug.h>
#include <Swiften/Elements/StatusShow.h>
#include <Swiften/Base/Path.h>
#include <Swift/Controllers/Roster/ContactRosterItem.h>
#include <Swift/Controllers/Roster/GroupRosterItem.h>
#include <Swift/Controllers/StatusUtil.h>
#include <Swift/QtUI/Roster/QtTreeWidget.h>
#include <Swift/QtUI/Roster/RosterTooltip.h>
#include <Swift/QtUI/QtResourceHelper.h>
#include <Swift/QtUI/QtSwiftUtil.h>
namespace Swift {
RosterModel::RosterModel(QtTreeWidget* view, bool screenReaderMode) : roster_(NULL), view_(view), screenReader_(screenReaderMode) {
const int tooltipAvatarSize = 96; // maximal suggested size according to XEP-0153
cachedImageScaler_ = new QtScaledAvatarCache(tooltipAvatarSize);
}
RosterModel::~RosterModel() {
delete cachedImageScaler_;
}
@@ -231,49 +231,44 @@ QModelIndex RosterModel::index(RosterItem* item) const {
for (size_t i = 0; i < parent->getDisplayedChildren().size(); i++) {
if (parent->getDisplayedChildren()[i] == item) {
return createIndex(i, 0, item);
}
}
return QModelIndex();
}
QModelIndex RosterModel::parent(const QModelIndex& child) const {
if (!roster_ || !child.isValid()) {
return QModelIndex();
}
GroupRosterItem* parent = getItem(child)->getParent();
return (parent != roster_->getRoot()) ? index(parent) : QModelIndex();
}
int RosterModel::rowCount(const QModelIndex& parent) const {
if (!roster_) return 0;
RosterItem* item = parent.isValid() ? static_cast<RosterItem*>(parent.internalPointer()) : roster_->getRoot();
Q_ASSERT(item);
GroupRosterItem* group = dynamic_cast<GroupRosterItem*>(item);
int count = group ? group->getDisplayedChildren().size() : 0;
// qDebug() << "rowCount = " << count << " where parent.isValid() == " << parent.isValid() << ", group == " << (group ? P2QSTRING(group->getDisplayName()) : "*contact*");
return count;
}
QMimeData* RosterModel::mimeData(const QModelIndexList& indexes) const {
QMimeData* data = QAbstractItemModel::mimeData(indexes);
ContactRosterItem *item = dynamic_cast<ContactRosterItem*>(getItem(indexes.first()));
if (item == NULL) {
return data;
}
+ /* only a single JID in this list */
QByteArray itemData;
QDataStream dataStream(&itemData, QIODevice::WriteOnly);
-
- // jid, chatName, activity, statusType, avatarPath
dataStream << P2QSTRING(item->getJID().toString());
- dataStream << P2QSTRING(item->getDisplayName());
- dataStream << P2QSTRING(item->getStatusText());
- dataStream << item->getSimplifiedStatusShow();
- dataStream << P2QSTRING(item->getAvatarPath().string());
- data->setData("application/vnd.swift.contact-jid", itemData);
+ data->setData("application/vnd.swift.contact-jid-list", itemData);
return data;
}
}
diff --git a/Swift/QtUI/UserSearch/ContactListModel.cpp b/Swift/QtUI/UserSearch/ContactListModel.cpp
index 4c4a3ea..907142f 100644
--- a/Swift/QtUI/UserSearch/ContactListModel.cpp
+++ b/Swift/QtUI/UserSearch/ContactListModel.cpp
@@ -1,41 +1,47 @@
/*
* 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/ContactListModel.h>
#include <QMimeData>
#include <Swiften/Base/Path.h>
#include <Swiften/Base/foreach.h>
#include <Swiften/Elements/StatusShow.h>
#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;
@@ -50,107 +56,70 @@ void ContactListModel::setList(const std::vector<Contact>& list) {
emit layoutAboutToBeChanged();
contacts_ = list;
emit layoutChanged();
}
const std::vector<Contact>& ContactListModel::getList() const {
return contacts_;
}
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()];
if (role == Qt::EditRole) {
return P2QSTRING(contact.jid.toString());
}
return dataForContact(contact, role);
} else {
return QVariant();
}
}
-bool ContactListModel::dropMimeData(const QMimeData* data, Qt::DropAction /*action*/, int /*row*/, int /*column*/, const QModelIndex& /*parent*/) {
- if (!data->hasFormat("application/vnd.swift.contact-jid")) {
- return false;
- }
-
- QByteArray dataBytes = data->data("application/vnd.swift.contact-jid");
- QDataStream dataStream(&dataBytes, QIODevice::ReadOnly);
- QString jidString;
- QString displayName;
- QString statusText;
- StatusShow::Type statusType;
- QString avatarPath;
-
- dataStream >> jidString;
- dataStream >> displayName;
- dataStream >> statusText;
- dataStream >> statusType;
- dataStream >> avatarPath;
-
- JID jid = JID(Q2PSTRING(jidString));
-
- foreach(const Contact& contact, contacts_) {
- if (contact.jid == jid) {
- return false;
- }
- }
-
- emit layoutAboutToBeChanged();
- contacts_.push_back(Contact(Q2PSTRING(displayName), jid, statusType, Q2PSTRING(avatarPath)));
- emit layoutChanged();
-
- onJIDsDropped(std::vector<JID>(1, jid));
- onListChanged(getList());
-
- return true;
-}
-
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();
}
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 {
switch (role) {
case Qt::DisplayRole: return P2QSTRING(contact.name);
case DetailTextRole: return P2QSTRING(contact.jid.toString());
case AvatarRole: return QVariant(P2QSTRING(pathToString(contact.avatarPath)));
diff --git a/Swift/QtUI/UserSearch/ContactListModel.h b/Swift/QtUI/UserSearch/ContactListModel.h
index e7f4a0b..6ca505e 100644
--- a/Swift/QtUI/UserSearch/ContactListModel.h
+++ b/Swift/QtUI/UserSearch/ContactListModel.h
@@ -1,58 +1,63 @@
/*
* 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 <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;
Qt::ItemFlags flags(const QModelIndex& index) const;
int columnCount(const QModelIndex& parent = QModelIndex()) const;
QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const;
- bool dropMimeData(const QMimeData* data, Qt::DropAction action, int row, int column, const QModelIndex& parent);
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;
signals:
void onListChanged(std::vector<Contact> list);
void onJIDsDropped(const std::vector<JID>& contact);
private:
bool editable_;
std::vector<Contact> contacts_;
};
}
diff --git a/Swift/QtUI/UserSearch/QtContactListWidget.cpp b/Swift/QtUI/UserSearch/QtContactListWidget.cpp
index 90adc11..6ad1169 100644
--- a/Swift/QtUI/UserSearch/QtContactListWidget.cpp
+++ b/Swift/QtUI/UserSearch/QtContactListWidget.cpp
@@ -1,104 +1,93 @@
/*
* 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, SLOT(handleListChanged(std::vector<Contact>)));
connect(contactListModel_, SIGNAL(onListChanged(std::vector<Contact>)), this, SIGNAL(onListChanged(std::vector<Contact>)));
connect(contactListModel_, SIGNAL(onJIDsDropped(std::vector<JID>)), this, SIGNAL(onJIDsAdded(std::vector<JID>)));
setSelectionMode(QAbstractItemView::SingleSelection);
setSelectionBehavior(QAbstractItemView::SelectRows);
- setDragEnabled(true);
- setAcceptDrops(true);
- setDropIndicatorShown(true);
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) {
contactListModel_->setList(list);
}
std::vector<Contact> QtContactListWidget::getList() const {
return contactListModel_->getList();
}
void QtContactListWidget::setMaximumNoOfContactsToOne(bool limited) {
limited_ = limited;
- if (limited) {
- handleListChanged(getList());
- } else {
- setAcceptDrops(true);
- setDropIndicatorShown(true);
- }
}
void QtContactListWidget::updateContacts(const std::vector<Contact>& contactUpdates) {
std::vector<Contact> contacts = contactListModel_->getList();
foreach(const Contact& contactUpdate, contactUpdates) {
for(size_t n = 0; n < contacts.size(); n++) {
if (contactUpdate.jid == contacts[n].jid) {
contacts[n] = contactUpdate;
break;
}
}
}
contactListModel_->setList(contacts);
}
-void QtContactListWidget::handleListChanged(std::vector<Contact> list) {
- if (limited_) {
- setAcceptDrops(list.size() <= 1);
- setDropIndicatorShown(list.size() <= 1);
- }
-}
-
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 f360a91..a83b47a 100644
--- a/Swift/QtUI/UserSearch/QtContactListWidget.h
+++ b/Swift/QtUI/UserSearch/QtContactListWidget.h
@@ -1,58 +1,61 @@
/*
* 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 <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 setMaximumNoOfContactsToOne(bool limited);
public slots:
void updateContacts(const std::vector<Contact>& contactUpdates);
signals:
void onListChanged(std::vector<Contact> list);
void onJIDsAdded(const std::vector<JID>& jids);
-private slots:
- void handleListChanged(std::vector<Contact> list);
-
private:
void handleSettingsChanged(const std::string&);
private:
SettingsProvider* settings_;
ContactListModel* contactListModel_;
ContactListDelegate* contactListDelegate_;
QtRemovableItemDelegate* removableItemDelegate_;
bool limited_;
};
}
diff --git a/Swift/QtUI/UserSearch/QtUserSearchFirstMultiJIDPage.cpp b/Swift/QtUI/UserSearch/QtUserSearchFirstMultiJIDPage.cpp
index b1e9a12..360ce0a 100644
--- a/Swift/QtUI/UserSearch/QtUserSearchFirstMultiJIDPage.cpp
+++ b/Swift/QtUI/UserSearch/QtUserSearchFirstMultiJIDPage.cpp
@@ -1,56 +1,94 @@
/*
* 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/QtUserSearchFirstMultiJIDPage.h"
+#include <QMessageBox>
+#include <QMimeData>
+#include <QUrl>
+
#include "Swift/QtUI/QtSwiftUtil.h"
-#include <Swift/QtUI/UserSearch/QtContactListWidget.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(jid_, SIGNAL(editingDone()), this, SLOT(handleEditingDone()));
+
+ setAcceptDrops(true);
}
bool QtUserSearchFirstMultiJIDPage::isComplete() const {
return !contactList_->getList().empty();
}
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;
+ dataStream >> jidString;
+ jids.push_back(Q2PSTRING(jidString));
+ }
+ onJIDsDropped(jids);
+ } else if (event->mimeData()->hasFormat("application/vnd.swift.contact-jid-muc")) {
+ QMessageBox* messageBox = new QMessageBox(this);
+ messageBox->setText(tr("You can't invite a room to chat."));
+ messageBox->setWindowTitle(tr("Error inviting room to chat"));
+ messageBox->show();
+ }
+}
+
}
diff --git a/Swift/QtUI/UserSearch/QtUserSearchFirstMultiJIDPage.h b/Swift/QtUI/UserSearch/QtUserSearchFirstMultiJIDPage.h
index 427995e..9905f21 100644
--- a/Swift/QtUI/UserSearch/QtUserSearchFirstMultiJIDPage.h
+++ b/Swift/QtUI/UserSearch/QtUserSearchFirstMultiJIDPage.h
@@ -1,40 +1,51 @@
/*
* 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 <QWizardPage>
#include <Swift/QtUI/UserSearch/ui_QtUserSearchFirstMultiJIDPage.h>
#include <Swift/Controllers/UIInterfaces/UserSearchWindow.h>
namespace Swift {
class UserSearchModel;
class UserSearchDelegate;
class UserSearchResult;
class UIEventStream;
class QtContactListWidget;
class ContactSuggester;
class AvatarManager;
class VCardManager;
class SettingsProvider;
class QtSuggestingJIDInput;
class QtUserSearchFirstMultiJIDPage : public QWizardPage, public Ui::QtUserSearchFirstMultiJIDPage {
Q_OBJECT
public:
QtUserSearchFirstMultiJIDPage(UserSearchWindow::Type type, const QString& title, SettingsProvider* settings);
virtual bool isComplete() const;
+ signals:
+ void onJIDsDropped(std::vector<JID> jid);
+
public slots:
void emitCompletenessCheck();
void handleEditingDone();
+ virtual void dragEnterEvent(QDragEnterEvent *event);
+ virtual void dropEvent(QDropEvent *event);
public:
QtContactListWidget* contactList_;
QtSuggestingJIDInput* jid_;
};
}
diff --git a/Swift/QtUI/UserSearch/QtUserSearchWindow.cpp b/Swift/QtUI/UserSearch/QtUserSearchWindow.cpp
index c0c7972..ec5dd39 100644
--- a/Swift/QtUI/UserSearch/QtUserSearchWindow.cpp
+++ b/Swift/QtUI/UserSearch/QtUserSearchWindow.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/QtUI/UserSearch/QtUserSearchWindow.h"
#include <QItemDelegate>
#include <QModelIndex>
#include <QWizardPage>
#include <QMovie>
#include <boost/bind.hpp>
#include <boost/smart_ptr/make_shared.hpp>
#include <Swiften/Base/foreach.h>
#include <Swift/Controllers/UIEvents/UIEventStream.h>
#include <Swift/Controllers/UIEvents/RequestChatUIEvent.h>
#include <Swift/Controllers/UIEvents/AddContactUIEvent.h>
#include <Swift/Controllers/UIEvents/CreateImpromptuMUCUIEvent.h>
#include <Swift/Controllers/UIEvents/InviteToMUCUIEvent.h>
#include <Swift/QtUI/UserSearch/UserSearchModel.h>
#include <Swift/QtUI/UserSearch/UserSearchDelegate.h>
#include <Swift/QtUI/QtSwiftUtil.h>
#include <Swift/QtUI/QtFormResultItemModel.h>
#include <Swift/QtUI/UserSearch/QtUserSearchFirstPage.h>
#include <Swift/QtUI/UserSearch/QtUserSearchFirstMultiJIDPage.h>
#include <Swift/QtUI/UserSearch/QtUserSearchFieldsPage.h>
#include <Swift/QtUI/UserSearch/QtUserSearchResultsPage.h>
#include <Swift/QtUI/UserSearch/QtUserSearchDetailsPage.h>
#include <Swift/QtUI/UserSearch/QtContactListWidget.h>
#include <Swiften/Base/Log.h>
namespace Swift {
QtUserSearchWindow::QtUserSearchWindow(UIEventStream* eventStream, UserSearchWindow::Type type, const std::set<std::string>& groups, SettingsProvider* settingsProvider) : eventStream_(eventStream), type_(type), model_(NULL), settings_(settingsProvider), searchNext_(false), supportsImpromptu_(false) {
@@ -345,142 +345,163 @@ 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);
}
return jids;
}
void QtUserSearchWindow::setCanStartImpromptuChats(bool supportsImpromptu) {
supportsImpromptu_ = supportsImpromptu;
if (type_ == ChatToContact) {
firstMultiJIDPage_->contactList_->setMaximumNoOfContactsToOne(!supportsImpromptu_);
}
}
void QtUserSearchWindow::updateContacts(const std::vector<Contact>& contacts) {
if (type_ != AddContact) {
firstMultiJIDPage_->contactList_->updateContacts(contacts);
}
}
+void QtUserSearchWindow::addContacts(const std::vector<Contact>& contacts) {
+ if (type_ != AddContact) {
+ /* prevent duplicate JIDs from appearing in the contact list */
+ foreach (const Contact& newContact, contacts) {
+ bool found = false;
+ foreach (const Contact& 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) {
contactVector_ = list;
if (type_ == ChatToContact) {
firstMultiJIDPage_->groupBox->setEnabled(supportsImpromptu_ ? 1 : (contactVector_.size() < 1));
}
}
void QtUserSearchWindow::handleJIDsAdded(std::vector<JID> jids) {
- onJIDUpdateRequested(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(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() {
fieldsPage_->fetchingThrobber_->show();
fieldsPage_->fetchingThrobber_->movie()->start();
diff --git a/Swift/QtUI/UserSearch/QtUserSearchWindow.h b/Swift/QtUI/UserSearch/QtUserSearchWindow.h
index e5a9f80..941e455 100644
--- a/Swift/QtUI/UserSearch/QtUserSearchWindow.h
+++ b/Swift/QtUI/UserSearch/QtUserSearchWindow.h
@@ -1,87 +1,88 @@
/*
- * Copyright (c) 2010 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 <QWizard>
#include <set>
#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 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);
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 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_;