fuzbal/Sidebar.qml
Timotej Lazar 8d44150598
Implement filter
Add a proxy model class with filter logic, and use it as the model for
events ListView.
2021-09-16 20:33:33 +02:00

254 lines
8 KiB
QML
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// SPDX-License-Identifier: Unlicense
import QtQuick 2.12
import QtQuick.Controls 2.13
import QtQuick.Layouts 1.6
import Qt.labs.platform 1.1
import fuzbal 1
Page {
id: control
property bool modified: false
property Video video
EventList {
id: eventList
onDataChanged: modified = true
onRowsInserted: modified = true
onRowsRemoved: modified = true
}
EventFilter {
id: eventFilter
sourceModel: eventList
}
FileDialog {
id: videoDialog
title: qsTr('Open video')
onAccepted: {
video.source = currentFile
const json = JSON.parse(io.read(currentFile+'.events') || '{}')
eventList.load(json)
description.text = json['description'] || ''
modified = false
}
}
FileDialog {
id: tagsDialog
title: qsTr('Load tags')
nameFilters: [qsTr('JSON files (*.json)'), qsTr('All files (*)')]
onAccepted: eventList.load({ 'tags': JSON.parse(io.read(currentFile)) })
}
Keys.forwardTo: [tags, video]
header: ToolBar {
horizontalPadding: 0
RowLayout {
anchors.fill: parent
ToolButton {
action: Action {
icon.name: 'document-open'
shortcut: StandardKey.Open
onTriggered: videoDialog.open()
}
focusPolicy: Qt.NoFocus
}
Label {
text: video.loaded ? video.source : ''
elide: Text.ElideLeft
Layout.fillWidth: true
}
ToolButton {
action: Action {
onTriggered: {
var json = eventList.save()
json['description'] = description.text
json['video'] = video.source
json['version'] = Qt.application.version
io.write(video.source+'.events', JSON.stringify(json))
modified = false
}
shortcut: StandardKey.Save
icon.name: 'document-save'
enabled: video.loaded && control.modified
}
visible: video.loaded
opacity: enabled ? 1 : 0.25
focusPolicy: Qt.NoFocus
}
}
}
ColumnLayout {
anchors.fill: parent
// Description box.
ColumnLayout {
spacing: 0
RowLayout {
Label {
text: qsTr('Description')
Layout.fillWidth: true
}
Label { text: description.enabled ? qsTr('') : qsTr('+') }
TapHandler { onTapped: description.enabled = !description.enabled }
}
ScrollView {
Layout.fillWidth: true
Layout.preferredHeight: 100
contentWidth: parent.availableWidth
padding: 1
visible: description.enabled
background: Frame { }
ScrollBar.horizontal.policy: ScrollBar.AlwaysOff
TextArea {
id: description
background: Rectangle { color: palette.base }
leftPadding: padding
selectByMouse: true
wrapMode: Text.Wrap
onTextChanged: modified = true
KeyNavigation.priority: KeyNavigation.BeforeItem
KeyNavigation.tab: events
}
}
}
// Events list.
ColumnLayout {
spacing: 0
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
Layout.fillHeight: true
Events {
id: events
anchors.fill: parent
focus: true
model: eventFilter
tags: eventList.tags
onEditingChanged: video.pause(editing)
onCurrentItemChanged: {
if (currentItem)
video.seek(currentItem.time)
}
Keys.onPressed: {
switch (event.key) {
case Qt.Key_Home:
currentIndex = 0
break
case Qt.Key_End:
currentIndex = count-1
break
case Qt.Key_Enter:
case Qt.Key_Return:
if (editing) {
currentItem.store()
editing = false
} else {
if (currentItem.fields.length > 0)
editing = true
}
break
case Qt.Key_Escape:
if (editing) {
currentItem.reset()
editing = false
}
break
case Qt.Key_Delete:
editing = false
eventFilter.remove(currentIndex)
break
case Qt.Key_Tab:
case Qt.Key_Backtab:
// swallow tabs so we dont lose focus when editing
break
default:
return
}
event.accepted = true
}
}
}
}
// Tag list.
Frame {
Layout.fillWidth: true
Layout.fillHeight: false
padding: 5
ColumnLayout {
width: parent.width
spacing: 0
RowLayout {
Label {
text: qsTr('Tags')
Layout.fillWidth: true
Layout.alignment: Qt.AlignVCenter
}
ToolButton {
icon.name: 'document-open'
Layout.alignment: Qt.AlignVCenter
onClicked: tagsDialog.open()
focusPolicy:Qt.NoFocus
}
}
Tags {
id: tags
model: eventList.tagsOrder.map(tag => eventList.tags[tag])
enabled: video.loaded && !events.editing
onClicked: {
const index = eventList.insert(tag, video.time)
// Reset filter if new event doesnt 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
if (event.fields.length > 0)
events.editing = true
}
Layout.fillWidth: true
}
}
}
}
}