Implement event model in C++
Filtering events in JS is too slow with >20,000 events. This moves the event data model into C++.
This commit is contained in:
parent
e9b70c585c
commit
cb76fedcbc
14 changed files with 375 additions and 342 deletions
135
Events.qml
135
Events.qml
|
@ -3,139 +3,35 @@
|
|||
import QtQuick 2.12
|
||||
import QtQuick.Controls 2.13
|
||||
import QtQuick.Layouts 1.6
|
||||
import QtQml.Models 2.1
|
||||
|
||||
import 'util.js' as Util
|
||||
|
||||
ListView {
|
||||
id: control
|
||||
|
||||
required property var tags // tag definitions
|
||||
property bool editing: false
|
||||
property var tags: []
|
||||
|
||||
signal changed
|
||||
|
||||
clip: true
|
||||
focus: true
|
||||
keyNavigationEnabled: true
|
||||
highlightMoveDuration: 0
|
||||
highlightResizeDuration: 0
|
||||
ScrollBar.vertical: ScrollBar { anchors.right: parent.right }
|
||||
|
||||
// Create a new blank event, insert it and start editing.
|
||||
function create(time, tag, fields) {
|
||||
const index = Util.find(list, 'time', time)
|
||||
list.insert(index, {
|
||||
'time': time,
|
||||
'tag': tag,
|
||||
'fields': fields,
|
||||
})
|
||||
currentIndex = index
|
||||
if (fields.length > 0)
|
||||
editing = true
|
||||
changed()
|
||||
}
|
||||
|
||||
function clear() {
|
||||
list.clear()
|
||||
}
|
||||
|
||||
function load(json) {
|
||||
// Return list of fields for the given tag.
|
||||
function getFields(name) {
|
||||
for (var i = 0; i < tags.length; i++)
|
||||
if (tags[i].tag === name)
|
||||
return tags[i].fields
|
||||
return []
|
||||
}
|
||||
|
||||
for (var i = 0; i < json.length; i++) {
|
||||
const event = json[i]
|
||||
var fields = getFields(event.tag)
|
||||
for (var j = 0; j < fields.length; j++)
|
||||
fields[j].value = event.fields[fields[j].name]
|
||||
list.append({ 'time': event.time, 'tag': event.tag, 'fields': fields })
|
||||
}
|
||||
forceActiveFocus()
|
||||
}
|
||||
|
||||
function save() {
|
||||
var data = []
|
||||
for (var i = 0; i < list.count; i++) {
|
||||
const event = list.get(i)
|
||||
var fields = {}
|
||||
for (var j = 0; j < event.fields.count; j++) {
|
||||
const field = event.fields.get(j)
|
||||
fields[field.name] = field.value
|
||||
}
|
||||
data.push({ 'time': event.time, 'tag': event.tag, 'fields': fields })
|
||||
}
|
||||
return data
|
||||
}
|
||||
|
||||
onCurrentIndexChanged: editing = false
|
||||
|
||||
Keys.onPressed: {
|
||||
switch (event.key) {
|
||||
case Qt.Key_Enter:
|
||||
case Qt.Key_Return:
|
||||
if (editing) {
|
||||
currentItem.store()
|
||||
changed()
|
||||
editing = false
|
||||
} else {
|
||||
if (currentItem.fields.count > 0)
|
||||
editing = true
|
||||
}
|
||||
break
|
||||
case Qt.Key_Escape:
|
||||
if (editing) {
|
||||
currentItem.reset()
|
||||
editing = false
|
||||
}
|
||||
break
|
||||
case Qt.Key_Delete:
|
||||
editing = false
|
||||
if (currentIndex >= 0 && currentIndex < list.count) {
|
||||
list.remove(currentIndex)
|
||||
changed()
|
||||
}
|
||||
break
|
||||
case Qt.Key_Tab:
|
||||
case Qt.Key_Backtab:
|
||||
// swallow tabs so we don’t lose focus when editing
|
||||
break
|
||||
default:
|
||||
return
|
||||
}
|
||||
event.accepted = true
|
||||
}
|
||||
|
||||
model: ListModel {
|
||||
id: list
|
||||
dynamicRoles: true
|
||||
}
|
||||
ScrollBar.vertical: ScrollBar { anchors.right: parent.right }
|
||||
|
||||
delegate: Event {
|
||||
id: item
|
||||
|
||||
time: model.time
|
||||
tag: model.tag
|
||||
fields: model.fields
|
||||
// If field definitions are missing for this event’s tag, use
|
||||
// Text for all field types unless where the value is bool.
|
||||
fields: tags[model.tag] ? tags[model.tag].fields :
|
||||
Object.entries(model.values).map(value => ({
|
||||
'name': value[0],
|
||||
'type': typeof(value[1]) === 'boolean' ? 'Bool' : 'Text',
|
||||
}))
|
||||
|
||||
width: control.width
|
||||
editing: control.editing && ListView.isCurrentItem
|
||||
|
||||
background: Rectangle {
|
||||
anchors.fill: parent
|
||||
color: border.width > 0 ? Util.alphize(border.color, 0.1) :
|
||||
(index % 2 === 0 ? palette.base : palette.alternateBase)
|
||||
border {
|
||||
color: editing ? palette.highlight : palette.dark
|
||||
width: item.ListView.isCurrentItem ? 1 : 0
|
||||
}
|
||||
radius: border.width
|
||||
}
|
||||
highlighted: ListView.isCurrentItem
|
||||
|
||||
Connections {
|
||||
enabled: ListView.currentIndex === index
|
||||
|
@ -143,13 +39,10 @@ ListView {
|
|||
control.positionViewAtIndex(index, ListView.Contain)
|
||||
}
|
||||
}
|
||||
onEditingChanged: {
|
||||
reset()
|
||||
if (editing)
|
||||
forceActiveFocus()
|
||||
}
|
||||
onRemove: {
|
||||
list.remove(ObjectModel.index)
|
||||
|
||||
onClicked: {
|
||||
control.currentIndex = index
|
||||
control.forceActiveFocus()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue