[ui] NodeEditor: refactor ChunksList and add global stats

This commit is contained in:
Fabien Castan 2021-01-22 09:40:07 +01:00
parent bd5d447d12
commit 831443c29d
9 changed files with 415 additions and 307 deletions

View file

@ -1,6 +1,5 @@
import QtQuick 2.11
import QtQuick.Controls 2.3
import QtQuick.Controls 1.4 as Controls1 // SplitView
import QtQuick.Layouts 1.3
import MaterialIcons 2.2
import Controls 1.0
@ -16,169 +15,148 @@ import "common.js" as Common
FocusScope {
id: root
property variant node
property alias chunkCurrentIndex: chunksLV.currentIndex
signal changeCurrentChunk(int chunkIndex)
property variant currentChunkIndex
property variant currentChunk
SystemPalette { id: activePalette }
Controls1.SplitView {
Loader {
id: componentLoader
clip: true
anchors.fill: parent
// The list of chunks
ChunksListView {
id: chunksLV
Layout.fillHeight: true
model: node.chunks
onChangeCurrentChunk: root.changeCurrentChunk(chunkIndex)
}
property string currentFile: (root.currentChunkIndex >= 0) ? root.currentChunk["statusFile"] : ""
property url source: Filepath.stringToUrl(currentFile)
Loader {
id: componentLoader
clip: true
Layout.fillWidth: true
Layout.fillHeight: true
property url source
sourceComponent: statViewerComponent
}
property string currentFile: chunksLV.currentChunk ? chunksLV.currentChunk["statusFile"] : ""
onCurrentFileChanged: {
// only set text file viewer source when ListView is fully ready
// (either empty or fully populated with a valid currentChunk)
// to avoid going through an empty url when switching between two nodes
Component {
id: statViewerComponent
Item {
id: statusViewer
property url source: componentLoader.source
property var lastModified: undefined
if(!chunksLV.count || chunksLV.currentChunk)
componentLoader.source = Filepath.stringToUrl(currentFile);
onSourceChanged: {
statusListModel.readSourceFile()
}
sourceComponent: statViewerComponent
}
ListModel {
id: statusListModel
Component {
id: statViewerComponent
Item {
id: statusViewer
property url source: componentLoader.source
property var lastModified: undefined
function readSourceFile() {
// make sure we are trying to load a statistics file
if(!Filepath.urlToString(source).endsWith("status"))
return;
onSourceChanged: {
statusListModel.readSourceFile()
}
var xhr = new XMLHttpRequest;
xhr.open("GET", source);
ListModel {
id: statusListModel
xhr.onreadystatechange = function() {
if (xhr.readyState === XMLHttpRequest.DONE && xhr.status === 200) {
// console.warn("StatusListModel: read valid file")
if(lastModified === undefined || lastModified !== xhr.getResponseHeader('Last-Modified')) {
lastModified = xhr.getResponseHeader('Last-Modified')
try {
var jsonObject = JSON.parse(xhr.responseText);
function readSourceFile() {
// make sure we are trying to load a statistics file
if(!Filepath.urlToString(source).endsWith("status"))
return;
var xhr = new XMLHttpRequest;
xhr.open("GET", source);
xhr.onreadystatechange = function() {
if (xhr.readyState === XMLHttpRequest.DONE && xhr.status === 200) {
// console.warn("StatusListModel: read valid file")
if(lastModified === undefined || lastModified !== xhr.getResponseHeader('Last-Modified')) {
lastModified = xhr.getResponseHeader('Last-Modified')
try {
var jsonObject = JSON.parse(xhr.responseText);
var entries = [];
// prepare data to populate the ListModel from the input json object
for(var key in jsonObject)
{
var entry = {};
entry["key"] = key;
entry["value"] = String(jsonObject[key]);
entries.push(entry);
}
// reset the model with prepared data (limit to one update event)
statusListModel.clear();
statusListModel.append(entries);
}
catch(exc)
var entries = [];
// prepare data to populate the ListModel from the input json object
for(var key in jsonObject)
{
// console.warn("StatusListModel: failed to read file")
lastModified = undefined;
statusListModel.clear();
var entry = {};
entry["key"] = key;
entry["value"] = String(jsonObject[key]);
entries.push(entry);
}
// reset the model with prepared data (limit to one update event)
statusListModel.clear();
statusListModel.append(entries);
}
catch(exc)
{
// console.warn("StatusListModel: failed to read file")
lastModified = undefined;
statusListModel.clear();
}
}
else
{
// console.warn("StatusListModel: invalid file")
lastModified = undefined;
statusListModel.clear();
}
};
xhr.send();
}
}
else
{
// console.warn("StatusListModel: invalid file")
lastModified = undefined;
statusListModel.clear();
}
};
xhr.send();
}
}
ListView {
id: statusListView
anchors.fill: parent
spacing: 3
model: statusListModel
ListView {
id: statusListView
anchors.fill: parent
spacing: 3
model: statusListModel
delegate: Rectangle {
color: activePalette.window
delegate: Rectangle {
color: activePalette.window
width: parent.width
height: childrenRect.height
RowLayout {
width: parent.width
height: childrenRect.height
RowLayout {
width: parent.width
Rectangle {
id: statusKey
anchors.margins: 2
// height: statusValue.height
color: Qt.darker(activePalette.window, 1.1)
Layout.preferredWidth: sizeHandle.x
Layout.minimumWidth: 10.0 * Qt.application.font.pixelSize
Layout.maximumWidth: 15.0 * Qt.application.font.pixelSize
Layout.fillWidth: false
Layout.fillHeight: true
Label {
text: key
anchors.fill: parent
anchors.top: parent.top
topPadding: 4
leftPadding: 6
verticalAlignment: TextEdit.AlignTop
elide: Text.ElideRight
}
Rectangle {
id: statusKey
anchors.margins: 2
// height: statusValue.height
color: Qt.darker(activePalette.window, 1.1)
Layout.preferredWidth: sizeHandle.x
Layout.minimumWidth: 10.0 * Qt.application.font.pixelSize
Layout.maximumWidth: 15.0 * Qt.application.font.pixelSize
Layout.fillWidth: false
Layout.fillHeight: true
Label {
text: key
anchors.fill: parent
anchors.top: parent.top
topPadding: 4
leftPadding: 6
verticalAlignment: TextEdit.AlignTop
elide: Text.ElideRight
}
TextArea {
id: statusValue
text: value
anchors.margins: 2
Layout.fillWidth: true
wrapMode: Label.WrapAtWordBoundaryOrAnywhere
textFormat: TextEdit.PlainText
}
TextArea {
id: statusValue
text: value
anchors.margins: 2
Layout.fillWidth: true
wrapMode: Label.WrapAtWordBoundaryOrAnywhere
textFormat: TextEdit.PlainText
readOnly: true
selectByMouse: true
background: Rectangle { anchors.fill: parent; color: Qt.darker(activePalette.window, 1.05) }
}
readOnly: true
selectByMouse: true
background: Rectangle { anchors.fill: parent; color: Qt.darker(activePalette.window, 1.05) }
}
}
}
}
// Categories resize handle
Rectangle {
id: sizeHandle
height: parent.contentHeight
width: 1
x: parent.width * 0.2
MouseArea {
anchors.fill: parent
anchors.margins: -4
cursorShape: Qt.SizeHorCursor
drag {
target: parent
axis: Drag.XAxis
threshold: 0
minimumX: statusListView.width * 0.2
maximumX: statusListView.width * 0.8
}
// Categories resize handle
Rectangle {
id: sizeHandle
height: parent.contentHeight
width: 1
x: parent.width * 0.2
MouseArea {
anchors.fill: parent
anchors.margins: -4
cursorShape: Qt.SizeHorCursor
drag {
target: parent
axis: Drag.XAxis
threshold: 0
minimumX: statusListView.width * 0.2
maximumX: statusListView.width * 0.8
}
}
}