import QtQuick 2.15 import QtQuick.Controls 2.15 import QtQuick.Layouts 1.15 import Monitoring 1.0 import Qt.labs.settings 1.0 import AppLayouts.Wallet.stores 1.0 as WalletStores Component { ColumnLayout { spacing: 0 Settings { property alias tabIndex: tabBar.currentIndex property alias modelObjectName: objectNameTextFiled.text } TabBar { id: tabBar Layout.fillWidth: true Layout.bottomMargin: 10 TabButton { text: "Context properties inspection" } TabButton { text: "Models inspection" } currentIndex: swipeView.currentIndex } StackLayout { id: swipeView currentIndex: tabBar.currentIndex //anchors.fill: parent Layout.fillWidth: true Layout.fillHeight: true SplitView { id: root ColumnLayout { SplitView.fillHeight: true SplitView.preferredWidth: 450 spacing: 5 Label { Layout.fillWidth: true Layout.margins: 5 text: "Context properties:" font.bold: true } ListView { Layout.fillWidth: true Layout.fillHeight: true Layout.margins: 5 model: Monitor.contexPropertiesModel clip: true spacing: 5 delegate: Item { implicitWidth: delegateRow.implicitWidth implicitHeight: delegateRow.implicitHeight readonly property var contextPropertyValue: MonitorUtils.contextPropertyBindingHelper(name, this).value Row { id: delegateRow Label { text: name } Label { text: ` [${MonitorUtils.typeName(contextPropertyValue)}]` color: "darkgreen" } Label { text: ` (${MonitorUtils.valueToString(contextPropertyValue)})` color: "darkred" } } MouseArea { anchors.fill: parent onClicked: { inspectionStackView.clear() headerModel.clear() const props = { name: name, objectForInspection: contextPropertyValue } inspectionStackView.push(inspectionList, props) headerModel.append({ name }) } } } } } Component { id: modelInspectionComponent ModelInspectionPane {} } Component { id: inspectionList ListView { property var objectForInspection property string name ScrollBar.vertical: ScrollBar {} onObjectForInspectionChanged: { inspectionModel.clear() if (!objectForInspection) return const items = [] for (const property in objectForInspection) { const type = typeof objectForInspection[property] if (type === "function") { items.push({ name: property, category: "functions", isModel: false, type: type }) } else { const value = objectForInspection[property] const detailedType = MonitorUtils.typeName(value) const isModel = Monitor.isModel(value) items.push({ name: property, type: detailedType, category: isModel? "models" : "properties", isModel: isModel }) } } items.sort((a, b) => { const nameA = a.category const nameB = b.category if (nameA === nameB) return 0 if (nameA === "models") return -1 if (nameB === "models") return 1 if (nameA < nameB) return -1 if (nameA > nameB) return 1 }) inspectionModel.append(items) } anchors.fill: parent spacing: 5 clip: true model: ListModel { id: inspectionModel } delegate: Item { implicitWidth: delegateRow.implicitWidth implicitHeight: delegateRow.implicitHeight Row { id: delegateRow readonly property var object: objectForInspection[name] Label { text: name } Loader { active: type !== "function" sourceComponent: Label { text: ` [${type}]` color: "darkgreen" } } Loader { active: type !== "function" sourceComponent: Label { text: ` (${MonitorUtils.valueToString(delegateRow.object)})` color: "darkred" } } Loader { active: isModel sourceComponent: Label { text: `, ${delegateRow.object.rowCount()} items` color: "darkred" font.bold: true } } } MouseArea { anchors.fill: parent onClicked: { if (isModel) { const props = { name: name, model: objectForInspection[name] } inspectionStackView.push(modelInspectionComponent, props, StackView.Immediate) headerModel.append({ name }) } else if (type !== "function") { const props = { name: name, objectForInspection: objectForInspection[name] } inspectionStackView.push(inspectionList, props, StackView.Immediate) headerModel.append({ name }) } } } } section.property: "category" section.delegate: Pane { leftPadding: 0 Label { text: section font.bold: true } } } } Pane { SplitView.fillHeight: true SplitView.minimumWidth: 100 ColumnLayout { anchors.fill: parent RowLayout { Layout.fillWidth: true Layout.fillHeight: false RoundButton { text: "⬅️" visible: headerRepeater.count > 1 onClicked: { inspectionStackView.pop(StackView.Immediate) headerModel.remove(headerModel.count - 1) } } Repeater { id: headerRepeater model: ListModel { id: headerModel } delegate: TextInput { readonly property bool last: headerRepeater.count - 1 === index text: model.name + (last ? "" : " -> ") font.pixelSize: 20 font.bold: true selectByMouse: true readOnly: true } } } MenuSeparator { visible: headerRepeater.count Layout.fillWidth: true } StackView { id: inspectionStackView Layout.fillWidth: true Layout.fillHeight: true } } } } Pane { ColumnLayout { anchors.fill: parent RowLayout { Layout.fillHeight: false Layout.fillWidth: true Label { text: "Model's object name:" } TextField { id: objectNameTextFiled Layout.fillWidth: true selectByMouse: true onAccepted: searchButton.clicked() } Button { id: searchButton text: "Search" onClicked: { const roots = [ applicationWindow, WalletStores.RootStore ] let obj = null for (let root of roots) { obj = Monitor.findChild(root, objectNameTextFiled.text) if (obj) break } if (!obj) { objLabel.objStr = "Model not found" rolesModelContent.model = null return } if (!Monitor.isModel(obj)) { objLabel.objStr = "Found object is not a model" rolesModelContent.model = null return } objLabel.objStr = obj.toString() rolesModelContent.model = obj } } } Label { id: objLabel property string objStr Layout.fillWidth: true visible: objStr !== "" text: "Object: " + objStr } ModelInspectionPane { id: rolesModelContent showControls: false Layout.fillWidth: true Layout.fillHeight: true } } } } } }