summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Sidebar.qml38
-rw-r--r--event_filter.cpp79
-rw-r--r--event_filter.h25
-rw-r--r--event_list.cpp4
-rw-r--r--event_list.h6
-rw-r--r--fuzbal.pro4
6 files changed, 144 insertions, 12 deletions
diff --git a/Sidebar.qml b/Sidebar.qml
index f66e5a6..059079c 100644
--- a/Sidebar.qml
+++ b/Sidebar.qml
@@ -20,6 +20,11 @@ Page {
onRowsRemoved: modified = true
}
+ EventFilter {
+ id: eventFilter
+ sourceModel: eventList
+ }
+
FileDialog {
id: videoDialog
title: qsTr('Open video')
@@ -122,7 +127,24 @@ Page {
// Events list.
ColumnLayout {
spacing: 0
- Label { text: qsTr('Events') }
+
+ RowLayout {
+ Label {
+ text: qsTr('Events')
+ Layout.fillWidth: true
+ }
+ Label { text: qsTr('🔍') }
+ TapHandler { onTapped: filter.visible = !filter.visible }
+ }
+
+ TextField {
+ id: filter
+ Layout.fillWidth: true
+ placeholderText: qsTr('Filter…')
+ visible: false
+ onTextChanged: eventFilter.setFilter(text)
+ }
+
Frame {
padding: 1
Layout.fillWidth: true
@@ -133,7 +155,7 @@ Page {
anchors.fill: parent
focus: true
- model: eventList
+ model: eventFilter
tags: eventList.tags
onEditingChanged: video.pause(editing)
@@ -168,7 +190,7 @@ Page {
break
case Qt.Key_Delete:
editing = false
- eventList.removeRows(currentIndex)
+ eventFilter.remove(currentIndex)
break
case Qt.Key_Tab:
case Qt.Key_Backtab:
@@ -212,9 +234,15 @@ Page {
model: eventList.tagsOrder.map(tag => eventList.tags[tag])
enabled: video.loaded && !events.editing
onClicked: {
- events.currentIndex = eventList.insert(video.time)
+ const index = eventList.insert(tag, video.time)
+ // Reset filter if new event doesn’t match.
+ var row = eventFilter.mapFromSource(eventList.index(index, 0)).row
+ if (eventFilter.mapFromSource(eventList.index(index, 0)).row === -1) {
+ filter.text = ''
+ row = index
+ }
+ events.currentIndex = row
const event = events.currentItem
- event.model.tag = tag
if (event.fields.length > 0)
events.editing = true
}
diff --git a/event_filter.cpp b/event_filter.cpp
new file mode 100644
index 0000000..d3f5e17
--- /dev/null
+++ b/event_filter.cpp
@@ -0,0 +1,79 @@
+#include "event_filter.h"
+
+#include <QAbstractItemModel>
+#include <QMetaType>
+#include <QRegularExpression>
+
+void EventFilter::setFilter(const QString& text)
+{
+ filters.clear();
+ if (!text.isEmpty()) {
+ for (const auto &s : text.split(QRegularExpression{"\\s+"})) {
+ if (const int split = s.indexOf(":"); split == -1)
+ filters.append({"", s.trimmed()});
+ else
+ filters.append({s.left(split).trimmed(), s.mid(split+1).trimmed()});
+ }
+ }
+ invalidateFilter();
+}
+
+bool EventFilter::remove(int row)
+{
+ return removeRows(row, 1);
+}
+
+// Check if any of the given values match name: value.
+static bool matches(const QVariantMap& values, const QString& name, const QString& value)
+{
+ for (auto kv = values.constKeyValueBegin(); kv != values.constKeyValueEnd(); kv++) {
+ const auto& [fieldName, fieldValue] = *kv;
+ if (!name.isEmpty() && !fieldName.startsWith(name))
+ continue;
+
+ switch (fieldValue.type()) {
+ case QMetaType::QString:
+ // Prepend = to value for exact match.
+ if (value.startsWith("=")) {
+ if (fieldValue.toString() == value.mid(1))
+ return true;
+ } else {
+ if (fieldValue.toString().contains(value))
+ return true;
+ }
+ break;
+ case QMetaType::Bool:
+ // Prepend ! to value for inverted match.
+ if (value.startsWith("!")) {
+ if (fieldName.startsWith(value.mid(1)) && !fieldValue.toBool())
+ return true;
+ } else {
+ if (fieldName.startsWith(value) && fieldValue.toBool())
+ return true;
+ }
+ break;
+ default:
+ break;
+ }
+ }
+ return false;
+}
+
+bool EventFilter::filterAcceptsRow(int sourceRow, const QModelIndex& sourceParent) const
+{
+ const auto& model = sourceModel();
+ const auto& index = model->index(sourceRow, 0, sourceParent);
+
+ const auto& roles = model->roleNames();
+ const auto& tag = model->data(index, roles.key("tag")).toString();
+ const auto& values = model->data(index, roles.key("values")).toMap();
+
+ for (const auto& filter : filters) {
+ if (filter.first.isEmpty() && tag.startsWith(filter.second))
+ continue;
+ if (matches(values, filter.first, filter.second))
+ continue;
+ return false;
+ }
+ return true;
+}
diff --git a/event_filter.h b/event_filter.h
new file mode 100644
index 0000000..aca6ed9
--- /dev/null
+++ b/event_filter.h
@@ -0,0 +1,25 @@
+#ifndef EVENT_FILTER_H
+#define EVENT_FILTER_H
+
+#include <QList>
+#include <QPair>
+#include <QSortFilterProxyModel>
+#include <QString>
+#include <qqml.h>
+
+class EventFilter : public QSortFilterProxyModel
+{
+ Q_OBJECT
+ QML_ELEMENT
+public slots:
+ void setFilter(const QString& filter = "");
+ bool remove(int row);
+
+protected:
+ bool filterAcceptsRow(int sourceRow, const QModelIndex& sourceParent) const override;
+
+private:
+ QList<QPair<QString, QString>> filters;
+};
+
+#endif
diff --git a/event_list.cpp b/event_list.cpp
index 2654bef..a1e88a5 100644
--- a/event_list.cpp
+++ b/event_list.cpp
@@ -58,11 +58,11 @@ bool EventList::setData(const QModelIndex& index, const QVariant& value, int rol
return true;
}
-int EventList::insert(const int time)
+int EventList::insert(const QString& tag, const int time)
{
int row = time == -1 ? rowCount() : find(time);
beginInsertRows(QModelIndex{}, row, row);
- events.insert(row, {time});
+ events.insert(row, {time, tag});
endInsertRows();
return row;
}
diff --git a/event_list.h b/event_list.h
index 1c50c59..21932ad 100644
--- a/event_list.h
+++ b/event_list.h
@@ -20,8 +20,8 @@ public:
bool setData(const QModelIndex& index, const QVariant& value, int role);
public slots:
- int insert(const int time = -1);
- bool removeRows(int row, int count = 1, const QModelIndex &parent = {});
+ int insert(const QString& tag = {}, const int time = -1);
+ bool removeRows(int row, int count = 1, const QModelIndex& parent = {});
void load(const QJsonObject& json);
QJsonObject save() const;
@@ -36,8 +36,8 @@ private:
};
enum Role { Time = Qt::UserRole + 1, Tag, Values };
- QStringList tagsOrder;
QJsonObject tags;
+ QStringList tagsOrder;
QList<Event> events;
int find(long long time) const;
diff --git a/fuzbal.pro b/fuzbal.pro
index 59be94b..ecd6f0d 100644
--- a/fuzbal.pro
+++ b/fuzbal.pro
@@ -7,8 +7,8 @@ DEFINES += GIT_VERSION=\\\"$$system(git -C "$$_PRO_FILE_PWD_" describe --always
QML_IMPORT_NAME = fuzbal
QML_IMPORT_MAJOR_VERSION = 1
-SOURCES += event_list.cpp main.cpp
-HEADERS += event_list.h io.h
+SOURCES += event_filter.cpp event_list.cpp main.cpp
+HEADERS += event_filter.h event_list.h io.h
RESOURCES += main.qrc icons.qrc
TRANSLATIONS += translations/fuzbal_sl.ts