summaryrefslogtreecommitdiffstats
path: root/demo/NodePage.qml
diff options
context:
space:
mode:
Diffstat (limited to 'demo/NodePage.qml')
-rw-r--r--demo/NodePage.qml135
1 files changed, 124 insertions, 11 deletions
diff --git a/demo/NodePage.qml b/demo/NodePage.qml
index 1468817..e677232 100644
--- a/demo/NodePage.qml
+++ b/demo/NodePage.qml
@@ -14,7 +14,20 @@ Page {
readonly property var pages: [
{
+ title: "Server Info",
+ description: "Standard OPC UA server nodes (namespace 0)."
+ + " CurrentTime updates live via monitoring.",
+ nodes: [
+ "ns=0;i=2258", // CurrentTime
+ "ns=0;i=2257", // StartTime
+ "ns=0;i=2259", // State
+ "ns=0;i=2261", // ProductName
+ "ns=0;i=2264" // SoftwareVersion
+ ]
+ },
+ {
title: "Read-Write Scalars",
+ description: "Single-value nodes with read and write access.",
nodes: [
"ns=1;s=bool_rw_scalar",
"ns=1;s=int16_rw_scalar",
@@ -25,11 +38,17 @@ Page {
"ns=1;s=uint64_rw_scalar",
"ns=1;s=float_rw_scalar",
"ns=1;s=double_rw_scalar",
- "ns=1;s=string_rw_scalar"
+ "ns=1;s=string_rw_scalar",
+ "ns=1;s=sbyte_rw_scalar",
+ "ns=1;s=byte_rw_scalar",
+ "ns=1;s=datetime_rw_scalar",
+ "ns=1;s=guid_rw_scalar",
+ "ns=1;s=bytestring_rw_scalar"
]
},
{
title: "Read-Only Scalars",
+ description: "Single-value nodes with read-only access.",
nodes: [
"ns=1;s=bool_ro_scalar",
"ns=1;s=int16_ro_scalar",
@@ -40,11 +59,19 @@ Page {
"ns=1;s=uint64_ro_scalar",
"ns=1;s=float_ro_scalar",
"ns=1;s=double_ro_scalar",
- "ns=1;s=string_ro_scalar"
+ "ns=1;s=string_ro_scalar",
+ "ns=1;s=sbyte_ro_scalar",
+ "ns=1;s=byte_ro_scalar",
+ "ns=1;s=datetime_ro_scalar",
+ "ns=1;s=guid_ro_scalar",
+ "ns=1;s=bytestring_ro_scalar"
]
},
{
title: "Read-Write Arrays",
+ description: "Array nodes. Values are displayed comma-separated."
+ + " To write, enter comma-separated values (e.g. \"1, 2, 3\")."
+ + " Commas cannot appear inside individual values.",
nodes: [
"ns=1;s=bool_rw_array",
"ns=1;s=int16_rw_array",
@@ -55,13 +82,50 @@ Page {
"ns=1;s=uint64_rw_array",
"ns=1;s=float_rw_array",
"ns=1;s=double_rw_array",
- "ns=1;s=string_rw_array"
+ "ns=1;s=string_rw_array",
+ "ns=1;s=sbyte_rw_array",
+ "ns=1;s=byte_rw_array",
+ "ns=1;s=datetime_rw_array",
+ "ns=1;s=guid_rw_array",
+ "ns=1;s=bytestring_rw_array"
+ ]
+ },
+ {
+ title: "Non-Existent Nodes",
+ description: "These node IDs do not exist on the server."
+ + " The row should show no value and no metadata in the tooltip.",
+ nodes: [
+ "ns=1;s=does_not_exist",
+ "ns=99;i=12345",
+ "ns=1;s=also_missing"
]
+ },
+ {
+ title: "Empty (Monitoring Test)",
+ description: "No nodes on this page. All previous pages are inactive,"
+ + " so the server log should show zero active monitored items.",
+ nodes: []
}
]
readonly property var currentPage: pages[pageNumber - 1]
+ // OPC UA ServerState enum (Part 4, Table 120).
+ readonly property var serverStates: [
+ "Running", "Failed", "NoConfiguration", "Suspended",
+ "Shutdown", "Test", "CommunicationFault", "Unknown"
+ ]
+
+ function formatValue(node) {
+ var v = node.value;
+ if (v === undefined || String(v) === "")
+ return "—";
+ // Map ServerState enum to human-readable string.
+ if (node.nodeId === "ns=0;i=2259" && !isNaN(v))
+ return serverStates[v] || String(v);
+ return String(v);
+ }
+
Component.onCompleted: nodePage.logFunction(
currentPage.title + " page loaded (" + currentPage.nodes.length + " nodes)")
@@ -78,7 +142,7 @@ Page {
font.pointSize: 14
}
Label {
- text: "(" + nodePage.pageNumber + "/3)"
+ text: "(" + nodePage.pageNumber + "/" + nodePage.pages.length + ")"
color: "gray"
}
Item { Layout.fillWidth: true }
@@ -88,24 +152,41 @@ Page {
}
}
+ Label {
+ id: pageDescription
+ visible: currentPage.description !== undefined
+ text: currentPage.description || ""
+ wrapMode: Text.WordWrap
+ color: "gray"
+ font.italic: true
+ Layout.fillWidth: true
+ }
+
// Column headers
RowLayout {
Layout.fillWidth: true
- spacing: 0
+ Layout.leftMargin: 12
+ Layout.rightMargin: 12
+ spacing: 12
Label {
text: "Identifier"
font.bold: true
- Layout.preferredWidth: 200
- leftPadding: 12
+ Layout.preferredWidth: 160
}
Label {
text: "Value"
font.bold: true
+ Layout.preferredWidth: 300
+ }
+ Label {
+ text: "Write"
+ font.bold: true
Layout.fillWidth: true
}
}
Rectangle {
+ id: separator
Layout.fillWidth: true
height: 1
color: "#ccc"
@@ -128,6 +209,10 @@ Page {
id: node
nodeId: delegate.modelData
monitored: nodePage.StackView.status === StackView.Active
+ onWriteCompleted: (success, message) => {
+ var short_id = node.nodeId.substring(node.nodeId.indexOf(";s=") + 3);
+ nodePage.logFunction(short_id + ": " + message);
+ }
}
background: Rectangle {
@@ -137,18 +222,46 @@ Page {
contentItem: RowLayout {
spacing: 12
+
+ // Column 1: Display name if available, otherwise short ID.
Label {
text: {
+ if (node.info.displayName)
+ return node.info.displayName;
var idx = node.nodeId.indexOf(";s=");
return idx >= 0 ? node.nodeId.substring(idx + 3) : node.nodeId;
}
- Layout.preferredWidth: 188
+ Layout.preferredWidth: 160
+ elide: Text.ElideRight
+ }
+
+ // Column 2: Live value (always visible)
+ Label {
+ text: nodePage.formatValue(node)
+ Layout.preferredWidth: 300
elide: Text.ElideRight
}
+
+ // Column 3: Edit area (writable) or READ-ONLY label
+ TextField {
+ id: editField
+ visible: node.writable
+ Layout.fillWidth: true
+ placeholderText: "Enter value..."
+ onAccepted: node.writeValue(text)
+ }
+ Button {
+ id: writeButton
+ visible: node.writable
+ text: "Write"
+ onClicked: node.writeValue(editField.text)
+ }
Label {
- text: node.value !== undefined && String(node.value) !== "" ? String(node.value) : "—"
+ visible: !node.writable
+ text: "(READ-ONLY)"
+ color: "gray"
+ font.italic: true
Layout.fillWidth: true
- elide: Text.ElideRight
}
}
@@ -179,7 +292,7 @@ Page {
Item { Layout.fillWidth: true }
Button {
text: "Next →"
- visible: nodePage.pageNumber < 3
+ visible: nodePage.pageNumber < nodePage.pages.length
onClicked: nodePage.stackRef.push("NodePage.qml", {
stackRef: nodePage.stackRef,
pageNumber: nodePage.pageNumber + 1,