mirror of
https://github.com/overte-org/overte.git
synced 2025-04-25 14:54:29 +02:00
367 lines
12 KiB
QML
367 lines
12 KiB
QML
//
|
|
// ResourceCacheInspector.qml
|
|
//
|
|
// Created by Sam Gateau on 2019-09-17
|
|
// Copyright 2019 High Fidelity, Inc.
|
|
//
|
|
// Distributed under the Apache License, Version 2.0.
|
|
// See the accompanying file LICENSE or https://www.apache.org/licenses/LICENSE-2.0.html
|
|
//
|
|
import QtQuick 2.12
|
|
import QtQuick.Controls 2.5
|
|
import QtQuick.Layouts 1.3
|
|
import QtQml.Models 2.12
|
|
|
|
import "../../lib/skit/qml" as Skit
|
|
import "../../lib/prop" as Prop
|
|
|
|
Item {
|
|
id: root;
|
|
Prop.Global { id: global }
|
|
|
|
anchors.fill: parent.fill
|
|
property var cache: {}
|
|
property string cacheResourceName: ""
|
|
|
|
function fromScript(message) {
|
|
switch (message.method) {
|
|
case "resetItemList":
|
|
resetItemListFromCache()
|
|
break;
|
|
}
|
|
}
|
|
|
|
function requestResourceDetails(resourceURL) {
|
|
sendToScript({method: "inspectResource", params: {url: resourceURL, semantic: cacheResourceName}});
|
|
}
|
|
|
|
Component.onCompleted: {
|
|
resetItemListFromCache();
|
|
}
|
|
|
|
function fetchItemsList() {
|
|
var theList;
|
|
if (cache !== undefined) {
|
|
theList = cache.getResourceList();
|
|
} else {
|
|
theList = ["ResourceCacheInspector.cache is undefined"];
|
|
}
|
|
var theListString = new Array(theList.length)
|
|
for (var i in theList) {
|
|
theListString[i] = (theList[i].toString())
|
|
}
|
|
return theListString;
|
|
}
|
|
|
|
function resetItemListFromCache() {
|
|
resetItemList(fetchItemsList())
|
|
}
|
|
|
|
property var needFreshList : false
|
|
|
|
function updateItemListFromCache() {
|
|
needFreshList = true
|
|
}
|
|
|
|
|
|
Timer {
|
|
interval: 2000; running: true; repeat: true
|
|
onTriggered: pullFreshValues()
|
|
}
|
|
|
|
function pullFreshValues() {
|
|
if (needFreshList) {
|
|
updateItemList(fetchItemsList())
|
|
needFreshList = false
|
|
}
|
|
}
|
|
|
|
property alias resourceItemsModel: visualModel.model
|
|
property var currentItemsList: new Array();
|
|
|
|
function packItemEntry(item, identifier) {
|
|
var entry = { "identifier": identifier, "name": "", "scheme": "", "host": "", "pathDir": "", "url": item}
|
|
if (item.length > 0) {
|
|
// Detect scheme:
|
|
var schemePos = item.search(":")
|
|
entry.scheme = item.substring(0, schemePos)
|
|
if (schemePos < 0) schemePos = 0
|
|
else schemePos += 1
|
|
|
|
// path pos is probably after schemePos
|
|
var pathPos = schemePos
|
|
|
|
// try to detect //userinfo@host:port
|
|
var token = item.substr(schemePos, 2);
|
|
if (token.search("//") == 0) {
|
|
pathPos += 2
|
|
}
|
|
item = item.substring(pathPos, item.length)
|
|
// item is now everything after scheme:[//]
|
|
var splitted = item.split('/')
|
|
|
|
// odd ball, the rest of the url has no other'/' ?
|
|
// in theory this means it s just the host info ?
|
|
// we are assuming that path ALWAYS starts with a slash
|
|
entry.host = splitted[0]
|
|
|
|
if (splitted.length > 1) {
|
|
entry.name = splitted[splitted.length - 1]
|
|
|
|
// if splitted is longer than 2 then there should be a path dir
|
|
if (splitted.length > 2) {
|
|
for (var i = 1; i < splitted.length - 1; i++) {
|
|
entry.pathDir += '/' + splitted[i]
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return entry
|
|
}
|
|
|
|
|
|
function resetItemList(itemList) {
|
|
currentItemsList = []
|
|
resourceItemsModel.clear()
|
|
for (var i in itemList) {
|
|
var item = itemList[i]
|
|
currentItemsList.push(item)
|
|
resourceItemsModel.append(packItemEntry(item, currentItemsList.length -1))
|
|
}
|
|
// At the end of it, force an update
|
|
visualModel.forceUpdate()
|
|
}
|
|
|
|
function updateItemList(newItemList) {
|
|
resetItemList(newItemList)
|
|
}
|
|
|
|
property var itemFields: ['identifier', 'name', 'scheme', 'host', 'pathDir', 'url']
|
|
|
|
|
|
Column {
|
|
id: header
|
|
|
|
anchors.top: parent.top
|
|
anchors.left: parent.left
|
|
anchors.right: parent.right
|
|
|
|
Item {
|
|
anchors.left: parent.left
|
|
anchors.right: parent.right
|
|
height: totalCount.height
|
|
id: headerTop
|
|
|
|
Prop.PropButton {
|
|
id: refreshButton
|
|
anchors.left: parent.left
|
|
anchors.verticalCenter: parent.verticalCenter
|
|
text: "Refresh"
|
|
color: needFreshList ? global.colorOrangeAccent : global.fontColor
|
|
onPressed: { pullFreshValues() }
|
|
}
|
|
|
|
GridLayout {
|
|
anchors.left: refreshButton.right
|
|
anchors.right: parent.right
|
|
id: headerCountLane
|
|
columns: 3
|
|
|
|
Item {
|
|
Layout.fillWidth: true
|
|
Prop.PropScalar {
|
|
id: itemCount
|
|
label: "Count"
|
|
object: root.cache
|
|
property: "numTotal"
|
|
integral: true
|
|
readOnly: true
|
|
}
|
|
}
|
|
Item {
|
|
Layout.fillWidth: true
|
|
Prop.PropScalar {
|
|
id: totalCount
|
|
label: "Count"
|
|
object: root.cache
|
|
property: "numTotal"
|
|
integral: true
|
|
readOnly: true
|
|
onSourceValueVarChanged: { updateItemListFromCache() }
|
|
}
|
|
}
|
|
Item {
|
|
Layout.fillWidth: true
|
|
Prop.PropScalar {
|
|
id: cachedCount
|
|
label: "Cached"
|
|
object: root.cache
|
|
property: "numCached"
|
|
integral: true
|
|
readOnly: true
|
|
onSourceValueVarChanged: { updateItemListFromCache() }
|
|
}
|
|
}
|
|
}
|
|
}
|
|
Item {
|
|
anchors.left: parent.left
|
|
anchors.right: parent.right
|
|
height: orderSelector.height
|
|
|
|
Prop.PropText {
|
|
anchors.left: parent.left
|
|
anchors.verticalCenter: parent.verticalCenter
|
|
width: 50
|
|
id: orderSelectorLabel
|
|
text: "Sort by"
|
|
horizontalAlignment: Text.AlignHCenter
|
|
}
|
|
Prop.PropComboBox {
|
|
anchors.left: orderSelectorLabel.right
|
|
width: 80
|
|
id: orderSelector
|
|
model: itemFields
|
|
currentIndex: 1
|
|
|
|
property var isSchemeVisible: (currentIndex == 2 || filterFieldSelector.currentIndex == 2)
|
|
property var isHostVisible: (currentIndex == 3 || filterFieldSelector.currentIndex == 3)
|
|
property var isPathDirVisible: (currentIndex == 4 || filterFieldSelector.currentIndex == 4)
|
|
property var isURLVisible: (currentIndex == 5 || filterFieldSelector.currentIndex == 5)
|
|
}
|
|
|
|
Prop.PropTextField {
|
|
anchors.left: orderSelector.right
|
|
anchors.right: filterFieldSelector.left
|
|
id: nameFilter
|
|
placeholderText: qsTr("Filter by " + itemFields[filterFieldSelector.currentIndex] + "...")
|
|
Layout.fillWidth: true
|
|
}
|
|
Prop.PropComboBox {
|
|
anchors.right: parent.right
|
|
id: filterFieldSelector
|
|
model: itemFields
|
|
currentIndex: 1
|
|
width: 80
|
|
opacity: (nameFilter.text.length > 0) ? 1.0 : 0.5
|
|
}
|
|
}
|
|
}
|
|
|
|
Component {
|
|
id: resouceItemDelegate
|
|
MouseArea {
|
|
id: dragArea
|
|
property bool held: false
|
|
anchors { left: parent.left; right: parent.right }
|
|
height: item.height
|
|
onPressed: {held = true}
|
|
onReleased: {held = false}
|
|
onDoubleClicked: { requestResourceDetails(model.url) }
|
|
Rectangle {
|
|
id: item
|
|
width: parent.width
|
|
height: global.slimHeight
|
|
color: dragArea.held ? global.colorBackHighlight : (index % 2 ? global.colorBackShadow : global.colorBack)
|
|
Row {
|
|
id: itemRow
|
|
anchors.verticalCenter : parent.verticalCenter
|
|
Prop.PropText {
|
|
id: itemIdentifier
|
|
text: model.identifier
|
|
width: 30
|
|
}
|
|
Prop.PropSplitter {
|
|
visible: orderSelector.isSchemeVisible
|
|
size:8
|
|
}
|
|
Prop.PropLabel {
|
|
visible: orderSelector.isSchemeVisible
|
|
text: model.scheme
|
|
width: 30
|
|
}
|
|
Prop.PropSplitter {
|
|
visible: orderSelector.isHostVisible
|
|
size:8
|
|
}
|
|
Prop.PropLabel {
|
|
visible: orderSelector.isHostVisible
|
|
text: model.host
|
|
width: 150
|
|
}
|
|
Prop.PropSplitter {
|
|
visible: orderSelector.isPathDirVisible
|
|
size:8
|
|
}
|
|
Prop.PropLabel {
|
|
visible: orderSelector.isPathDirVisible
|
|
text: model.pathDir
|
|
}
|
|
Prop.PropSplitter {
|
|
size:8
|
|
}
|
|
Prop.PropLabel {
|
|
visible: !orderSelector.isURLVisible
|
|
text: model.name
|
|
}
|
|
Prop.PropLabel {
|
|
visible: orderSelector.isURLVisible
|
|
text: model.url
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
Skit.SortFilterModel {
|
|
id: visualModel
|
|
model: ListModel {}
|
|
|
|
property int sortOrder: orderSelector.currentIndex
|
|
|
|
property var lessThanArray: [
|
|
function(left, right) { return left.index < right.index },
|
|
function(left, right) { return left.name < right.name },
|
|
function(left, right) { return left.scheme < right.scheme },
|
|
function(left, right) { return left.host < right.host },
|
|
function(left, right) { return left.pathDir < right.pathDir },
|
|
function(left, right) { return left.url < right.url }
|
|
];
|
|
lessThan: lessThanArray[sortOrder]
|
|
|
|
property int filterField: filterFieldSelector.currentIndex
|
|
onFilterFieldChanged: { refreshFilter() }
|
|
property var textFilter: nameFilter.text
|
|
onTextFilterChanged: { refreshFilter() }
|
|
|
|
function filterToken(itemWord, token) { return (itemWord.search(token) > -1) }
|
|
property var acceptItemArray: [
|
|
function(item) { return true },
|
|
function(item) { return filterToken(item.identifier.toString(), textFilter) },
|
|
function(item) { return filterToken(item.name, textFilter) },
|
|
function(item) { return filterToken(item.scheme, textFilter) },
|
|
function(item) { return filterToken(item.host, textFilter) },
|
|
function(item) { return filterToken(item.pathDir, textFilter) },
|
|
function(item) { return filterToken(item.url, textFilter) }
|
|
]
|
|
|
|
function refreshFilter() {
|
|
//console.log("refreshFilter! token = " + textFilter + " field = " + filterField)
|
|
acceptItem = acceptItemArray[(textFilter.length != 0) * + (1 + filterField)]
|
|
}
|
|
|
|
delegate: resouceItemDelegate
|
|
}
|
|
|
|
ListView {
|
|
anchors.top: header.bottom
|
|
anchors.bottom: parent.bottom
|
|
anchors.left: parent.left
|
|
anchors.right: parent.right
|
|
clip: true
|
|
|
|
id: listView
|
|
model: visualModel
|
|
}
|
|
}
|