diff options
| author | Richard Maudsley <richard.maudsley@isode.com> | 2014-04-07 09:19:50 (GMT) |
|---|---|---|
| committer | Richard Maudsley <richard.maudsley@isode.com> | 2014-04-07 13:07:43 (GMT) |
| commit | a7c7602e89d58056940885112f8764a31e9991da (patch) | |
| tree | e713e2d7eed2c2ba2925ec0a70fe93eb707c077a /Swift/QtUI | |
| parent | 1a35178bcad7c30e50a19e4017d021fb0485ccf0 (diff) | |
| download | swift-contrib-a7c7602e89d58056940885112f8764a31e9991da.zip swift-contrib-a7c7602e89d58056940885112f8764a31e9991da.tar.bz2 | |
Allow contacts to be dragged from the Chats tab into the search window
Change-Id: Ib1ecd2f95fb26269d8aa19094aac6e1f691cdf35
Diffstat (limited to 'Swift/QtUI')
| -rw-r--r-- | Swift/QtUI/ChatList/ChatListModel.cpp | 42 | ||||
| -rw-r--r-- | Swift/QtUI/ChatList/ChatListModel.h | 4 | ||||
| -rw-r--r-- | Swift/QtUI/ChatList/QtChatListWindow.cpp | 27 | ||||
| -rw-r--r-- | Swift/QtUI/ChatList/QtChatListWindow.h | 3 | ||||
| -rw-r--r-- | Swift/QtUI/QtChatWindow.cpp | 20 | ||||
| -rw-r--r-- | Swift/QtUI/Roster/RosterModel.cpp | 11 | ||||
| -rw-r--r-- | Swift/QtUI/UserSearch/ContactListModel.cpp | 43 | ||||
| -rw-r--r-- | Swift/QtUI/UserSearch/ContactListModel.h | 7 | ||||
| -rw-r--r-- | Swift/QtUI/UserSearch/QtContactListWidget.cpp | 23 | ||||
| -rw-r--r-- | Swift/QtUI/UserSearch/QtContactListWidget.h | 9 | ||||
| -rw-r--r-- | Swift/QtUI/UserSearch/QtUserSearchFirstMultiJIDPage.cpp | 40 | ||||
| -rw-r--r-- | Swift/QtUI/UserSearch/QtUserSearchFirstMultiJIDPage.h | 11 | ||||
| -rw-r--r-- | Swift/QtUI/UserSearch/QtUserSearchWindow.cpp | 25 | ||||
| -rw-r--r-- | Swift/QtUI/UserSearch/QtUserSearchWindow.h | 3 |
14 files changed, 177 insertions, 91 deletions
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_; |
Swift