summaryrefslogtreecommitdiff
path: root/src/filterwidget.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/filterwidget.cpp')
-rw-r--r--src/filterwidget.cpp94
1 files changed, 84 insertions, 10 deletions
diff --git a/src/filterwidget.cpp b/src/filterwidget.cpp
index 16a46b0e..44cbb274 100644
--- a/src/filterwidget.cpp
+++ b/src/filterwidget.cpp
@@ -1,12 +1,41 @@
#include "filterwidget.h"
#include "eventfilter.h"
-FilterWidget::FilterWidget()
- : m_edit(nullptr), m_eventFilter(nullptr), m_clear(nullptr)
+FilterWidgetProxyModel::FilterWidgetProxyModel(FilterWidget& fw, QWidget* parent)
+ : QSortFilterProxyModel(parent), m_filter(fw)
{
+ connect(&fw, &FilterWidget::changed, [&]{ invalidateFilter(); });
}
-void FilterWidget::set(QLineEdit* edit)
+bool FilterWidgetProxyModel::filterAcceptsRow(
+ int sourceRow, const QModelIndex& sourceParent) const
+{
+ const auto cols = sourceModel()->columnCount();
+
+ const auto m = m_filter.matches([&](auto&& what) {
+ for (int c=0; c<cols; ++c) {
+ QModelIndex index = sourceModel()->index(sourceRow, c, sourceParent);
+ const auto text = sourceModel()->data(index, Qt::DisplayRole).toString();
+
+ if (text.contains(what, Qt::CaseInsensitive)) {
+ return true;
+ }
+ }
+
+ return false;
+ });
+
+ return m;
+}
+
+
+FilterWidget::FilterWidget() :
+ m_edit(nullptr), m_list(nullptr), m_proxy(nullptr),
+ m_eventFilter(nullptr), m_clear(nullptr)
+{
+}
+
+void FilterWidget::setEdit(QLineEdit* edit)
{
unhook();
@@ -16,11 +45,22 @@ void FilterWidget::set(QLineEdit* edit)
return;
}
+ m_edit->setPlaceholderText(QObject::tr("Filter"));
+
createClear();
hookEvents();
clear();
}
+void FilterWidget::setList(QAbstractItemView* list)
+{
+ m_list = list;
+
+ m_proxy = new FilterWidgetProxyModel(*this);
+ m_proxy->setSourceModel(m_list->model());
+ m_list->setModel(m_proxy);
+}
+
void FilterWidget::clear()
{
if (!m_edit) {
@@ -30,21 +70,44 @@ void FilterWidget::clear()
m_edit->clear();
}
-bool FilterWidget::matches(std::function<bool (const QString& what)> pred) const
+bool FilterWidget::empty() const
{
+ return m_text.isEmpty();
+}
+
+QModelIndex FilterWidget::map(const QModelIndex& index)
+{
+ if (m_proxy) {
+ return m_proxy->mapToSource(index);
+ } else {
+ qCritical() << "FilterWidget::map() called, but proxy isn't set up";
+ return index;
+ }
+}
+
+void FilterWidget::compile()
+{
+ m_compiled.clear();
+
const QStringList ORList = [&] {
QString filterCopy = QString(m_text);
filterCopy.replace("||", ";").replace("OR", ";").replace("|", ";");
return filterCopy.split(";", QString::SkipEmptyParts);
}();
- if (ORList.isEmpty() || !pred) {
+ // split in ORSegments that internally use AND logic
+ for (auto& ORSegment : ORList) {
+ m_compiled.push_back(ORSegment.split(" ", QString::SkipEmptyParts));
+ }
+}
+
+bool FilterWidget::matches(std::function<bool (const QString& what)> pred) const
+{
+ if (m_compiled.isEmpty() || !pred) {
return true;
}
- // split in ORSegments that internally use AND logic
- for (auto& ORSegment : ORList) {
- QStringList ANDKeywords = ORSegment.split(" ", QString::SkipEmptyParts);
+ for (auto& ANDKeywords : m_compiled) {
bool segmentGood = true;
// check each word in the segment for match, each word needs to be matched
@@ -75,6 +138,14 @@ void FilterWidget::unhook()
if (m_edit) {
m_edit->removeEventFilter(m_eventFilter);
}
+
+ if (m_proxy && m_list) {
+ auto* model = m_proxy->sourceModel();
+ m_proxy->setSourceModel(nullptr);
+ delete m_proxy;
+
+ m_list->setModel(model);
+ }
}
void FilterWidget::createClear()
@@ -115,10 +186,13 @@ void FilterWidget::onTextChanged()
if (text != m_text) {
m_text = text;
+ compile();
- if (changed) {
- changed();
+ if (m_proxy) {
+ m_proxy->invalidateFilter();
}
+
+ emit changed();
}
}