summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTobias Markmann <tm@ayena.de>2013-12-08 16:48:18 (GMT)
committerSwift Review <review@swift.im>2014-05-26 14:40:44 (GMT)
commit168538129a69fa37a19e768149b32ca262bb85a3 (patch)
tree70881bbddc7561f2139f9d2ec32c7a5d357a8909
parent3a2c03a97576b2839eeba3015ccebde769263d09 (diff)
downloadswift-168538129a69fa37a19e768149b32ca262bb85a3.zip
swift-168538129a69fa37a19e768149b32ca262bb85a3.tar.bz2
Add QtFilterWidget, a general live-filtering composite widget for QtTreeWidgets.
Change-Id: I39d1ae718890d15ffacde6d482b5435cc05330ec License: This patch is BSD-licensed, see Documentation/Licenses/BSD-simplified.txt for details.
-rw-r--r--Swift/Controllers/Roster/FuzzyRosterFilter.h38
-rw-r--r--Swift/QtUI/QtMainWindow.cpp3
-rw-r--r--Swift/QtUI/Roster/QtFilterWidget.cpp132
-rw-r--r--Swift/QtUI/Roster/QtFilterWidget.h46
-rw-r--r--Swift/QtUI/SConscript1
5 files changed, 220 insertions, 0 deletions
diff --git a/Swift/Controllers/Roster/FuzzyRosterFilter.h b/Swift/Controllers/Roster/FuzzyRosterFilter.h
new file mode 100644
index 0000000..6710084
--- /dev/null
+++ b/Swift/Controllers/Roster/FuzzyRosterFilter.h
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2013 Tobias Markmann
+ * Licensed under the simplified BSD license.
+ * See Documentation/Licenses/BSD-simplified.txt for more information.
+ */
+
+#pragma once
+
+#include <string>
+
+#include <Swift/Controllers/ContactSuggester.h>
+#include <Swift/Controllers/Roster/ContactRosterItem.h>
+#include <Swift/Controllers/Roster/RosterItem.h>
+#include <Swift/Controllers/Roster/RosterFilter.h>
+
+namespace Swift {
+
+class FuzzyRosterFilter : public RosterFilter {
+ public:
+ FuzzyRosterFilter(const std::string& query) : query_(query) { }
+ virtual ~FuzzyRosterFilter() {}
+ virtual bool operator() (RosterItem* item) const {
+ ContactRosterItem *contactItem = dynamic_cast<ContactRosterItem*>(item);
+ if (contactItem) {
+ const bool itemMatched = ContactSuggester::fuzzyMatch(contactItem->getDisplayName(), query_) || ContactSuggester::fuzzyMatch(contactItem->getDisplayJID(), query_);
+ return !itemMatched;
+ } else {
+ return false;
+ }
+ }
+
+ private:
+ std::string query_;
+};
+
+}
+
+
diff --git a/Swift/QtUI/QtMainWindow.cpp b/Swift/QtUI/QtMainWindow.cpp
index 4716780..7af9728 100644
--- a/Swift/QtUI/QtMainWindow.cpp
+++ b/Swift/QtUI/QtMainWindow.cpp
@@ -33,6 +33,7 @@
#include <Swift/Controllers/UIEvents/RequestBlockListDialogUIEvent.h>
#include <Swift/Controllers/SettingConstants.h>
+#include <Swift/QtUI/Roster/QtFilterWidget.h>
#include <Swift/QtUI/QtSwiftUtil.h>
#include <Swift/QtUI/QtTabWidget.h>
#include <Swift/QtUI/QtSettingsProvider.h>
@@ -76,7 +77,9 @@ QtMainWindow::QtMainWindow(SettingsProvider* settings, UIEventStream* uiEventStr
contactTabLayout->setContentsMargins(0, 0, 0, 0);
treeWidget_ = new QtRosterWidget(uiEventStream_, settings_, this);
+
contactTabLayout->addWidget(treeWidget_);
+ new QtFilterWidget(this, treeWidget_, contactTabLayout);
tabs_->addTab(contactsTabWidget_, tr("&Contacts"));
diff --git a/Swift/QtUI/Roster/QtFilterWidget.cpp b/Swift/QtUI/Roster/QtFilterWidget.cpp
new file mode 100644
index 0000000..5bd4669
--- /dev/null
+++ b/Swift/QtUI/Roster/QtFilterWidget.cpp
@@ -0,0 +1,132 @@
+/*
+ * Copyright (c) 2013 Tobias Markmann
+ * Licensed under the simplified BSD license.
+ * See Documentation/Licenses/BSD-simplified.txt for more information.
+ */
+
+#include <Swift/QtUI/Roster/QtFilterWidget.h>
+
+#include <QLayout>
+#include <QVBoxLayout>
+#include <QKeyEvent>
+#include <QEvent>
+#include <QString>
+#include <QEvent>
+
+#include <Swift/QtUI/QtSwiftUtil.h>
+
+namespace Swift {
+
+QtFilterWidget::QtFilterWidget(QWidget* parent, QtTreeWidget* treeView, QBoxLayout* layout) : QWidget(parent), treeView_(treeView), fuzzyRosterFilter_(0), isModifierSinglePressed_(false) {
+ int targetIndex = layout->indexOf(treeView);
+
+ QVBoxLayout* vboxLayout = new QVBoxLayout(this);
+ vboxLayout->setSpacing(0);
+ vboxLayout->setContentsMargins(0,0,0,0);
+
+ filterLineEdit_ = new QLineEdit(this);
+ filterLineEdit_->hide();
+ vboxLayout->addWidget(filterLineEdit_);
+
+ vboxLayout->addWidget(treeView);
+ setLayout(vboxLayout);
+ layout->insertWidget(targetIndex, this);
+
+ filterLineEdit_->installEventFilter(this);
+ treeView->installEventFilter(this);
+
+ sourceModel_ = treeView_->model();
+}
+
+QtFilterWidget::~QtFilterWidget() {
+
+}
+
+bool QtFilterWidget::eventFilter(QObject*, QEvent* event) {
+ if (event->type() == QEvent::KeyPress ||
+ event->type() == QEvent::KeyRelease ||
+ // InputMethodQuery got introduced in Qt 5.
+#if QT_VERSION >= 0x050000
+ event->type() == QEvent::InputMethodQuery ||
+#endif
+ event->type() == QEvent::InputMethod) {
+ event->ignore();
+ QKeyEvent* keyEvent = dynamic_cast<QKeyEvent*>(event);
+ if (keyEvent) {
+ if (keyEvent->key() == Qt::Key_Up || keyEvent->key() == Qt::Key_Down) {
+ return false;
+ } else if ((keyEvent->key() == Qt::Key_Left || keyEvent->key() == Qt::Key_Right) && filterLineEdit_->text().isEmpty()) {
+ return false;
+ } else if (keyEvent->key() == Qt::Key_Alt && event->type() == QEvent::KeyPress) {
+ isModifierSinglePressed_ = true;
+ } else if (keyEvent->key() == Qt::Key_Alt && event->type() == QEvent::KeyRelease && isModifierSinglePressed_) {
+ QPoint itemOffset(2,2);
+ QPoint contextMenuPosition = treeView_->visualRect(treeView_->currentIndex()).topLeft() + itemOffset;;
+ QApplication::postEvent(treeView_, new QContextMenuEvent(QContextMenuEvent::Keyboard, contextMenuPosition, treeView_->mapToGlobal(contextMenuPosition)));
+ return true;
+ } else if (keyEvent->key() == Qt::Key_Return) {
+ filterLineEdit_->setText("");
+ return false;
+ } else if (keyEvent->key() == Qt::Key_Escape) {
+ filterLineEdit_->setText("");
+ } else {
+ isModifierSinglePressed_ = false;
+ }
+ }
+
+ filterLineEdit_->event(event);
+ filterLineEdit_->setVisible(!filterLineEdit_->text().isEmpty());
+
+ // update roster filters
+ if (event->type() == QEvent::KeyRelease) {
+ if (fuzzyRosterFilter_) {
+ if (filterLineEdit_->text().isEmpty()) {
+ // remove currently installed search filter and put old filters back
+ treeView_->getRoster()->removeFilter(fuzzyRosterFilter_);
+ delete fuzzyRosterFilter_;
+ fuzzyRosterFilter_ = NULL;
+ pushAllFilters();
+ } else {
+ // remove currently intsalled search filter and put new search filter in place
+ updateSearchFilter();
+ }
+ } else {
+ if (!filterLineEdit_->text().isEmpty()) {
+ // remove currently installed filters and put a search filter in place
+ popAllFilters();
+ updateSearchFilter();
+ }
+ }
+ }
+ return true;
+ }
+ return false;
+}
+
+void QtFilterWidget::popAllFilters() {
+ std::vector<RosterFilter*> filters = treeView_->getRoster()->getFilters();
+ foreach(RosterFilter* filter, filters) {
+ filters_.push_back(filter);
+ treeView_->getRoster()->removeFilter(filter);
+ }
+}
+
+void QtFilterWidget::pushAllFilters() {
+ foreach(RosterFilter* filter, filters_) {
+ treeView_->getRoster()->addFilter(filter);
+ }
+ filters_.clear();
+}
+
+void QtFilterWidget::updateSearchFilter() {
+ if (fuzzyRosterFilter_) {
+ treeView_->getRoster()->removeFilter(fuzzyRosterFilter_);
+ delete fuzzyRosterFilter_;
+ fuzzyRosterFilter_ = NULL;
+ }
+ fuzzyRosterFilter_ = new FuzzyRosterFilter(Q2PSTRING(filterLineEdit_->text()));
+ treeView_->getRoster()->addFilter(fuzzyRosterFilter_);
+ treeView_->setCurrentIndex(sourceModel_->index(0, 0, sourceModel_->index(0,0)));
+}
+
+}
diff --git a/Swift/QtUI/Roster/QtFilterWidget.h b/Swift/QtUI/Roster/QtFilterWidget.h
new file mode 100644
index 0000000..e33616b
--- /dev/null
+++ b/Swift/QtUI/Roster/QtFilterWidget.h
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2013 Tobias Markmann
+ * Licensed under the simplified BSD license.
+ * See Documentation/Licenses/BSD-simplified.txt for more information.
+ */
+
+#pragma once
+
+#include <vector>
+
+#include <QBoxLayout>
+#include <QLineEdit>
+#include <QWidget>
+
+#include <Swift/Controllers/Roster/RosterFilter.h>
+#include <Swift/Controllers/Roster/FuzzyRosterFilter.h>
+
+#include <Swift/QtUI/Roster/QtTreeWidget.h>
+
+namespace Swift {
+
+class QtFilterWidget : public QWidget {
+ Q_OBJECT
+ public:
+ QtFilterWidget(QWidget* parent, QtTreeWidget* treeView, QBoxLayout* layout = 0);
+ virtual ~QtFilterWidget();
+
+ protected:
+ bool eventFilter(QObject*, QEvent* event);
+
+ private:
+ void popAllFilters();
+ void pushAllFilters();
+
+ void updateSearchFilter();
+
+ private:
+ QLineEdit* filterLineEdit_;
+ QtTreeWidget* treeView_;
+ std::vector<RosterFilter*> filters_;
+ QAbstractItemModel* sourceModel_;
+ FuzzyRosterFilter* fuzzyRosterFilter_;
+ bool isModifierSinglePressed_;
+};
+
+}
diff --git a/Swift/QtUI/SConscript b/Swift/QtUI/SConscript
index 56d2d1b..06b04fa 100644
--- a/Swift/QtUI/SConscript
+++ b/Swift/QtUI/SConscript
@@ -145,6 +145,7 @@ sources = [
"Roster/RosterDelegate.cpp",
"Roster/GroupItemDelegate.cpp",
"Roster/DelegateCommons.cpp",
+ "Roster/QtFilterWidget.cpp",
"Roster/QtRosterWidget.cpp",
"Roster/QtOccupantListWidget.cpp",
"Roster/RosterTooltip.cpp",