From 615b87497cd8d4eedc386f002931d6d353f53ccd Mon Sep 17 00:00:00 2001 From: Tobias Markmann Date: Mon, 5 Sep 2016 17:44:24 +0200 Subject: Add ability to filter results in "Search Room" dialog This is implemented with the help of an implementation of QSortFilterProxyModel which filters room names based on a user search string. Test-Information: Tested on OS X 10.11.6 with Qt 5.5.1. Tested UX with different MUC services and search strings. Change-Id: I88085d089493008b2197a4aeb45d8c4d75724b9c diff --git a/Swift/QtUI/MUCSearch/QtLeafSortFilterProxyModel.cpp b/Swift/QtUI/MUCSearch/QtLeafSortFilterProxyModel.cpp new file mode 100644 index 0000000..b8cf15a --- /dev/null +++ b/Swift/QtUI/MUCSearch/QtLeafSortFilterProxyModel.cpp @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2016 Isode Limited. + * All rights reserved. + * See the COPYING file for more information. + */ + +#include + +namespace Swift { + +QtLeafSortFilterProxyModel::QtLeafSortFilterProxyModel(QObject* parent) : QSortFilterProxyModel(parent) { + +} + +QtLeafSortFilterProxyModel::~QtLeafSortFilterProxyModel() { + +} + +bool QtLeafSortFilterProxyModel::filterAcceptsRow(int source_row, const QModelIndex& source_parent) const { + if (!sourceModel()->hasChildren(sourceModel()->index(source_row, 0, source_parent))) { + return QSortFilterProxyModel::filterAcceptsRow(source_row, source_parent); + } + else { + return true; + } +} + +} diff --git a/Swift/QtUI/MUCSearch/QtLeafSortFilterProxyModel.h b/Swift/QtUI/MUCSearch/QtLeafSortFilterProxyModel.h new file mode 100644 index 0000000..b4be622 --- /dev/null +++ b/Swift/QtUI/MUCSearch/QtLeafSortFilterProxyModel.h @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2016 Isode Limited. + * All rights reserved. + * See the COPYING file for more information. + */ + +#pragma once + +#include + +namespace Swift { + +/** + * @brief The QtLeafSortFilterProxyModel class is similar to the QSortFilterProxyModel + * class. While the basic QSortFilterProxyModel class filters all hierarchical items, + * the QtLeafSortFilterProxyModel class will only filter on items without children. + */ +class QtLeafSortFilterProxyModel : public QSortFilterProxyModel { + Q_OBJECT + +public: + QtLeafSortFilterProxyModel(QObject* parent = nullptr); + virtual ~QtLeafSortFilterProxyModel(); + +protected: + virtual bool filterAcceptsRow(int source_row, const QModelIndex& source_parent) const; +}; + +} diff --git a/Swift/QtUI/MUCSearch/QtMUCSearchWindow.cpp b/Swift/QtUI/MUCSearch/QtMUCSearchWindow.cpp index 114ec1d..f69da41 100644 --- a/Swift/QtUI/MUCSearch/QtMUCSearchWindow.cpp +++ b/Swift/QtUI/MUCSearch/QtMUCSearchWindow.cpp @@ -12,6 +12,7 @@ #include #include #include +#include #include #include @@ -20,6 +21,7 @@ #include #include #include +#include #include namespace Swift { @@ -30,10 +32,12 @@ QtMUCSearchWindow::QtMUCSearchWindow() { setWindowIcon(QIcon(":/logo-icon-16.png")); #endif setModal(true); - ui_.filter_->hide(); model_ = new MUCSearchModel(); + sortFilterProxyModel_ = new QtLeafSortFilterProxyModel(this); + sortFilterProxyModel_->setSourceModel(model_); + sortFilterProxyModel_->setDynamicSortFilter(true); delegate_ = new MUCSearchDelegate(); - ui_.results_->setModel(model_); + ui_.results_->setModel(sortFilterProxyModel_); ui_.results_->setItemDelegate(delegate_); ui_.results_->setHeaderHidden(true); ui_.results_->setRootIsDecorated(true); @@ -41,7 +45,7 @@ QtMUCSearchWindow::QtMUCSearchWindow() { ui_.results_->setAlternatingRowColors(true); ui_.results_->setSortingEnabled(true); ui_.results_->sortByColumn(0, Qt::AscendingOrder); - connect(ui_.searchButton, SIGNAL(clicked()), this, SLOT(handleSearch())); + connect(ui_.searchButton_, SIGNAL(clicked()), this, SLOT(handleSearch())); connect(ui_.service_, SIGNAL(activated(const QString&)), this, SLOT(handleSearch(const QString&))); connect(ui_.results_->selectionModel(), SIGNAL(selectionChanged (const QItemSelection&, const QItemSelection&)), this, SLOT(handleSelectionChanged (const QItemSelection&, const QItemSelection&))); connect(ui_.results_, SIGNAL(activated(const QModelIndex&)), this, SLOT(handleActivated(const QModelIndex&))); @@ -50,6 +54,7 @@ QtMUCSearchWindow::QtMUCSearchWindow() { connect(ui_.okButton, SIGNAL(clicked()), this, SLOT(accept())); ui_.okButton->setEnabled(false); connect(ui_.cancelButton, SIGNAL(clicked()), this, SLOT(reject())); + connect(ui_.filter_, SIGNAL(textChanged(const QString&)), this, SLOT(handleFilterStringChanged(const QString&))); throbber_ = new QLabel(tr("Searching"), ui_.results_); throbber_->setMovie(new QMovie(":/icons/throbber.gif", QByteArray(), throbber_)); @@ -104,7 +109,7 @@ void QtMUCSearchWindow::handleActivated(const QModelIndex& index) { if (!index.isValid()) { return; } - if (dynamic_cast(static_cast(index.internalPointer()))) { + if (dynamic_cast(static_cast(sortFilterProxyModel_->mapToSource(index).internalPointer()))) { accept(); } } @@ -119,7 +124,12 @@ void QtMUCSearchWindow::handleSearch(const QString& service) { } } +void QtMUCSearchWindow::handleFilterStringChanged(const QString& filterString) { + sortFilterProxyModel_->setFilterRegExp(filterString); +} + void QtMUCSearchWindow::show() { + ui_.filter_->clear(); QWidget::show(); QWidget::activateWindow(); } @@ -197,7 +207,7 @@ MUCSearchRoomItem* QtMUCSearchWindow::getSelectedRoom() const { return nullptr; } else { - return dynamic_cast(static_cast(lstIndex.first().internalPointer())); + return dynamic_cast(static_cast(sortFilterProxyModel_->mapToSource(lstIndex.first()).internalPointer())); } } diff --git a/Swift/QtUI/MUCSearch/QtMUCSearchWindow.h b/Swift/QtUI/MUCSearch/QtMUCSearchWindow.h index b115e6f..6f38533 100644 --- a/Swift/QtUI/MUCSearch/QtMUCSearchWindow.h +++ b/Swift/QtUI/MUCSearch/QtMUCSearchWindow.h @@ -10,6 +10,8 @@ #include +class QSortFilterProxyModel; + namespace Swift { class MUCSearchModel; class MUCSearchDelegate; @@ -36,6 +38,7 @@ namespace Swift { private slots: void handleSearch(); void handleSearch(const QString&); + void handleFilterStringChanged(const QString&); void handleActivated(const QModelIndex& index); void updateThrobberPosition(); void handleSelectionChanged (const QItemSelection&, const QItemSelection&); @@ -47,5 +50,6 @@ namespace Swift { MUCSearchDelegate* delegate_; QLabel* throbber_; bool hasHadScrollBars_; + QSortFilterProxyModel* sortFilterProxyModel_ = nullptr; }; } diff --git a/Swift/QtUI/MUCSearch/QtMUCSearchWindow.ui b/Swift/QtUI/MUCSearch/QtMUCSearchWindow.ui index 49460ab..52714c4 100644 --- a/Swift/QtUI/MUCSearch/QtMUCSearchWindow.ui +++ b/Swift/QtUI/MUCSearch/QtMUCSearchWindow.ui @@ -6,21 +6,14 @@ 0 0 - 523 - 368 + 566 + 264 Search Room - - - - Service: - - - @@ -34,26 +27,14 @@ - - - - - 1 - 0 - - + + - - - - true + Service: - - - - + @@ -90,13 +71,42 @@ + + + + + 1 + 0 + + + + + + + true + + + + + + - + List rooms + + + + + + + Search for + + + diff --git a/Swift/QtUI/SConscript b/Swift/QtUI/SConscript index 1f15c15..2d01672 100644 --- a/Swift/QtUI/SConscript +++ b/Swift/QtUI/SConscript @@ -160,12 +160,13 @@ sources = [ "ChatList/ChatListMUCItem.cpp", "ChatList/ChatListRecentItem.cpp", "ChatList/ChatListWhiteboardItem.cpp", - "MUCSearch/QtMUCSearchWindow.cpp", + "MUCSearch/MUCSearchDelegate.cpp", + "MUCSearch/MUCSearchEmptyItem.cpp", "MUCSearch/MUCSearchModel.cpp", "MUCSearch/MUCSearchRoomItem.cpp", - "MUCSearch/MUCSearchEmptyItem.cpp", - "MUCSearch/MUCSearchDelegate.cpp", "MUCSearch/MUCSearchServiceItem.cpp", + "MUCSearch/QtLeafSortFilterProxyModel.cpp", + "MUCSearch/QtMUCSearchWindow.cpp", "UserSearch/ContactListDelegate.cpp", "UserSearch/ContactListModel.cpp", "UserSearch/QtContactListWidget.cpp", -- cgit v0.10.2-6-g49f6