summaryrefslogtreecommitdiffstats
path: root/demo
diff options
context:
space:
mode:
authorThomas Vanbesien <tvanbesi@proton.me>2026-02-19 05:13:42 +0100
committerThomas Vanbesien <tvanbesi@proton.me>2026-02-19 05:38:24 +0100
commita0c7f2a7ef04dbe2e7491eabf828e26423d1bd10 (patch)
tree50491c80f28ad5f2789a3777bec74489327c4d7f /demo
parent23916cbb98e952aab752a647ac96020aab709bb6 (diff)
downloadBobinkQtOpcUa-a0c7f2a7ef04dbe2e7491eabf828e26423d1bd10.tar.gz
BobinkQtOpcUa-a0c7f2a7ef04dbe2e7491eabf828e26423d1bd10.zip
Rename targets, route messages to debug console, clean up
- Rename CMake project and library target to BobinkQtOpcUa (URI stays Bobink) - Rename demo target to BobinkDemo, output binary to build/bin/ - Route all QML status/error messages to the in-app debug console - Remove discoveryInterval QML property, default to 30s internally - Add errorChanged handler, PKI file validation in applyPki()
Diffstat (limited to 'demo')
-rw-r--r--demo/CMakeLists.txt30
-rw-r--r--demo/Main.qml243
2 files changed, 173 insertions, 100 deletions
diff --git a/demo/CMakeLists.txt b/demo/CMakeLists.txt
index a12e090..9fb3093 100644
--- a/demo/CMakeLists.txt
+++ b/demo/CMakeLists.txt
@@ -1,18 +1,20 @@
-qt_add_executable(bobink-demo main.cpp)
+qt_add_executable(BobinkDemo main.cpp)
-qt_add_qml_module(bobink-demo
- URI BobinkDemo
- VERSION 1.0
- QML_FILES
- Main.qml
- # LoginPage.qml
- # NodePage.qml
- NO_RESOURCE_TARGET_PATH
-)
+qt_add_qml_module(
+ BobinkDemo
+ URI
+ BobinkDemo
+ VERSION
+ 1.0
+ QML_FILES
+ Main.qml)
-target_link_libraries(bobink-demo PRIVATE Qt6::Quick bobink)
+# Executable goes to bin/ to avoid clashing with the QML module directory
+set_target_properties(BobinkDemo PROPERTIES RUNTIME_OUTPUT_DIRECTORY
+ "${CMAKE_BINARY_DIR}/bin")
+
+target_link_libraries(BobinkDemo PRIVATE Qt6::Quick BobinkQtOpcUa)
# Tell the demo where to find the locally-built OpcUa plugin at runtime
-target_compile_definitions(bobink-demo PRIVATE
- QTOPCUA_PLUGIN_PATH="${QTOPCUA_BUILD_DIR}/plugins"
-)
+target_compile_definitions(
+ BobinkDemo PRIVATE QTOPCUA_PLUGIN_PATH="${QTOPCUA_BUILD_DIR}/plugins")
diff --git a/demo/Main.qml b/demo/Main.qml
index fe4f369..5bdf369 100644
--- a/demo/Main.qml
+++ b/demo/Main.qml
@@ -7,8 +7,9 @@ import QtQuick.Dialogs
import Bobink
ApplicationWindow {
- width: 600
- height: 800
+ id: root
+ width: 800
+ height: 900
visible: true
title: "Bobink Demo"
@@ -16,30 +17,33 @@ ApplicationWindow {
property bool showPkiSettings: false
Component.onCompleted: {
- BobinkClient.discoveryUrl = discoveryUrlField.text
- BobinkClient.startDiscovery()
+ BobinkClient.discoveryUrl = discoveryUrlField.text;
+ BobinkClient.startDiscovery();
}
Connections {
target: BobinkClient
function onServersChanged() {
- console.log("Discovered server list updated")
+ debugConsole.appendLog("Discovered server list updated");
}
function onConnectedChanged() {
- console.log("Connected:", BobinkClient.connected)
+ debugConsole.appendLog("Connected: " + BobinkClient.connected);
if (BobinkClient.connected)
- autoConnectFailed = false
+ root.autoConnectFailed = false;
}
function onConnectionError(message) {
- console.log("Connection error:", message)
- autoConnectFailed = true
+ debugConsole.appendLog("ERROR: " + message);
+ root.autoConnectFailed = true;
+ }
+ function onStatusMessage(message) {
+ debugConsole.appendLog(message);
}
function onDiscoveringChanged() {
- console.log("Discovering:", BobinkClient.discovering)
+ debugConsole.appendLog("Discovering: " + BobinkClient.discovering);
}
function onCertificateTrustRequested(certInfo) {
- certTrustDialog.certInfo = certInfo
- certTrustDialog.open()
+ certTrustDialog.certInfo = certInfo;
+ certTrustDialog.open();
}
}
@@ -50,7 +54,9 @@ ApplicationWindow {
title: "Certificate Trust"
modal: true
standardButtons: Dialog.Yes | Dialog.No
- Label { text: certTrustDialog.certInfo }
+ Label {
+ text: certTrustDialog.certInfo
+ }
onAccepted: BobinkClient.acceptCertificate()
onRejected: BobinkClient.rejectCertificate()
}
@@ -60,7 +66,10 @@ ApplicationWindow {
anchors.margins: 20
spacing: 12
- Label { text: "Discovery URL"; font.bold: true }
+ Label {
+ text: "Discovery URL"
+ font.bold: true
+ }
RowLayout {
TextField {
@@ -72,19 +81,17 @@ ApplicationWindow {
text: BobinkClient.discovering ? "Stop" : "Discover"
onClicked: {
if (BobinkClient.discovering) {
- BobinkClient.stopDiscovery()
+ BobinkClient.stopDiscovery();
} else {
- BobinkClient.discoveryUrl = discoveryUrlField.text
- BobinkClient.startDiscovery()
+ BobinkClient.discoveryUrl = discoveryUrlField.text;
+ BobinkClient.startDiscovery();
}
}
}
}
Label {
- text: BobinkClient.discovering
- ? "Discovering... (" + BobinkClient.servers.length + " found)"
- : BobinkClient.servers.length + " server(s)"
+ text: BobinkClient.discovering ? "Discovering... (" + BobinkClient.servers.length + " found)" : BobinkClient.servers.length + " server(s)"
font.italic: true
}
@@ -94,30 +101,34 @@ ApplicationWindow {
clip: true
model: BobinkClient.servers
delegate: ItemDelegate {
+ required property var modelData
width: ListView.view.width
text: modelData.serverName + " — " + modelData.applicationUri
onClicked: {
if (modelData.discoveryUrls.length > 0)
- serverUrlField.text = modelData.discoveryUrls[0]
+ serverUrlField.text = modelData.discoveryUrls[0];
}
}
ScrollBar.vertical: ScrollBar {}
}
RowLayout {
- Label { text: "PKI"; font.bold: true }
Label {
- text: BobinkClient.certFile
- ? " (" + BobinkClient.certFile.split("/").pop() + ")"
- : " (no certificate found)"
+ text: "PKI"
+ font.bold: true
+ }
+ Label {
+ text: BobinkClient.certFile ? " (" + BobinkClient.certFile.split("/").pop() + ")" : " (no certificate found)"
font.italic: true
color: BobinkClient.certFile ? "green" : "gray"
}
- Item { Layout.fillWidth: true }
+ Item {
+ Layout.fillWidth: true
+ }
Button {
- text: showPkiSettings ? "Hide" : "Configure..."
+ text: root.showPkiSettings ? "Hide" : "Configure..."
flat: true
- onClicked: showPkiSettings = !showPkiSettings
+ onClicked: root.showPkiSettings = !root.showPkiSettings
}
}
@@ -147,9 +158,11 @@ ApplicationWindow {
GridLayout {
columns: 3
Layout.fillWidth: true
- visible: showPkiSettings
+ visible: root.showPkiSettings
- Label { text: "Certificate:" }
+ Label {
+ text: "Certificate:"
+ }
TextField {
id: certFileField
Layout.fillWidth: true
@@ -161,7 +174,9 @@ ApplicationWindow {
onClicked: certFileDialog.open()
}
- Label { text: "Private key:" }
+ Label {
+ text: "Private key:"
+ }
TextField {
id: keyFileField
Layout.fillWidth: true
@@ -173,7 +188,9 @@ ApplicationWindow {
onClicked: keyFileDialog.open()
}
- Label { text: "Trust folder:" }
+ Label {
+ text: "Trust folder:"
+ }
TextField {
id: trustFolderField
Layout.fillWidth: true
@@ -188,16 +205,19 @@ ApplicationWindow {
Button {
text: "Apply PKI"
Layout.fillWidth: true
- visible: showPkiSettings
+ visible: root.showPkiSettings
onClicked: {
- BobinkClient.pkiDir = trustFolderField.text
- BobinkClient.certFile = certFileField.text
- BobinkClient.keyFile = keyFileField.text
- BobinkClient.applyPki()
+ BobinkClient.pkiDir = trustFolderField.text;
+ BobinkClient.certFile = certFileField.text;
+ BobinkClient.keyFile = keyFileField.text;
+ BobinkClient.applyPki();
}
}
- Label { text: "Server URL"; font.bold: true }
+ Label {
+ text: "Server URL"
+ font.bold: true
+ }
TextField {
id: serverUrlField
@@ -205,15 +225,18 @@ ApplicationWindow {
placeholderText: "opc.tcp://..."
}
- Label { text: "Authentication"; font.bold: true }
+ Label {
+ text: "Authentication"
+ font.bold: true
+ }
BobinkAuth {
id: auth
mode: authModeCombo.currentValue
username: usernameField.text
password: passwordField.text
- certPath: certPathField.text
- keyPath: keyPathField.text
+ certPath: BobinkClient.certFile
+ keyPath: BobinkClient.keyFile
}
ComboBox {
@@ -222,9 +245,18 @@ ApplicationWindow {
textRole: "text"
valueRole: "mode"
model: [
- { text: "Anonymous", mode: BobinkAuth.Anonymous },
- { text: "Username / Password", mode: BobinkAuth.UserPass },
- { text: "Certificate", mode: BobinkAuth.Certificate }
+ {
+ text: "Anonymous",
+ mode: BobinkAuth.Anonymous
+ },
+ {
+ text: "Username / Password",
+ mode: BobinkAuth.UserPass
+ },
+ {
+ text: "Certificate",
+ mode: BobinkAuth.Certificate
+ }
]
}
@@ -233,12 +265,16 @@ ApplicationWindow {
visible: authModeCombo.currentValue === BobinkAuth.UserPass
Layout.fillWidth: true
- Label { text: "Username:" }
+ Label {
+ text: "Username:"
+ }
TextField {
id: usernameField
Layout.fillWidth: true
}
- Label { text: "Password:" }
+ Label {
+ text: "Password:"
+ }
TextField {
id: passwordField
Layout.fillWidth: true
@@ -246,36 +282,17 @@ ApplicationWindow {
}
}
- GridLayout {
- columns: 2
- visible: authModeCombo.currentValue === BobinkAuth.Certificate
- Layout.fillWidth: true
-
- Label { text: "Certificate:" }
- TextField {
- id: certPathField
- Layout.fillWidth: true
- placeholderText: "/path/to/cert.pem"
- }
- Label { text: "Private key:" }
- TextField {
- id: keyPathField
- Layout.fillWidth: true
- placeholderText: "/path/to/key.pem"
- }
- }
-
Button {
text: BobinkClient.connected ? "Disconnect" : "Connect"
Layout.fillWidth: true
onClicked: {
if (BobinkClient.connected) {
- BobinkClient.disconnectFromServer()
+ BobinkClient.disconnectFromServer();
} else {
- autoConnectFailed = false
- BobinkClient.auth = auth
- BobinkClient.serverUrl = serverUrlField.text
- BobinkClient.connectToServer()
+ root.autoConnectFailed = false;
+ BobinkClient.auth = auth;
+ BobinkClient.serverUrl = serverUrlField.text;
+ BobinkClient.connectToServer();
}
}
}
@@ -283,37 +300,59 @@ ApplicationWindow {
Label {
text: "Direct Connect"
font.bold: true
- visible: autoConnectFailed && !BobinkClient.connected
+ visible: root.autoConnectFailed && !BobinkClient.connected
}
GridLayout {
columns: 2
Layout.fillWidth: true
- visible: autoConnectFailed && !BobinkClient.connected
+ visible: root.autoConnectFailed && !BobinkClient.connected
- Label { text: "Security policy:" }
+ Label {
+ text: "Security policy:"
+ }
ComboBox {
id: securityPolicyCombo
Layout.fillWidth: true
textRole: "text"
valueRole: "policy"
model: [
- { text: "Basic256Sha256", policy: BobinkClient.Basic256Sha256 },
- { text: "Aes128-Sha256-RsaOaep", policy: BobinkClient.Aes128_Sha256_RsaOaep },
- { text: "Aes256-Sha256-RsaPss", policy: BobinkClient.Aes256_Sha256_RsaPss }
+ {
+ text: "Basic256Sha256",
+ policy: BobinkClient.Basic256Sha256
+ },
+ {
+ text: "Aes128-Sha256-RsaOaep",
+ policy: BobinkClient.Aes128_Sha256_RsaOaep
+ },
+ {
+ text: "Aes256-Sha256-RsaPss",
+ policy: BobinkClient.Aes256_Sha256_RsaPss
+ }
]
}
- Label { text: "Security mode:" }
+ Label {
+ text: "Security mode:"
+ }
ComboBox {
id: securityModeCombo
Layout.fillWidth: true
textRole: "text"
valueRole: "mode"
model: [
- { text: "Sign & Encrypt", mode: BobinkClient.SignAndEncrypt },
- { text: "Sign", mode: BobinkClient.Sign },
- { text: "None", mode: BobinkClient.None }
+ {
+ text: "Sign & Encrypt",
+ mode: BobinkClient.SignAndEncrypt
+ },
+ {
+ text: "Sign",
+ mode: BobinkClient.Sign
+ },
+ {
+ text: "None",
+ mode: BobinkClient.None
+ }
]
}
}
@@ -321,12 +360,11 @@ ApplicationWindow {
Button {
text: "Direct Connect"
Layout.fillWidth: true
- visible: autoConnectFailed && !BobinkClient.connected
+ visible: root.autoConnectFailed && !BobinkClient.connected
onClicked: {
- BobinkClient.auth = auth
- BobinkClient.serverUrl = serverUrlField.text
- BobinkClient.connectDirect(securityPolicyCombo.currentValue,
- securityModeCombo.currentValue)
+ BobinkClient.auth = auth;
+ BobinkClient.serverUrl = serverUrlField.text;
+ BobinkClient.connectDirect(securityPolicyCombo.currentValue, securityModeCombo.currentValue);
}
}
@@ -335,6 +373,39 @@ ApplicationWindow {
color: BobinkClient.connected ? "green" : "red"
}
- Item { Layout.fillHeight: true }
+ Item {
+ Layout.fillHeight: true
+ }
+
+ Rectangle {
+ id: debugConsole
+ Layout.fillWidth: true
+ Layout.preferredHeight: 100
+ color: "#1e1e1e"
+ border.color: "#444"
+ radius: 4
+
+ function appendLog(msg) {
+ let ts = new Date().toLocaleTimeString(Qt.locale(), "HH:mm:ss");
+ statusLog.text += "[" + ts + "] " + msg + "\n";
+ statusLog.cursorPosition = statusLog.text.length;
+ }
+
+ ScrollView {
+ anchors.fill: parent
+ anchors.margins: 4
+
+ TextArea {
+ id: statusLog
+ readOnly: true
+ color: "#cccccc"
+ font.family: "monospace"
+ font.pointSize: 9
+ wrapMode: TextEdit.Wrap
+ background: null
+ }
+ }
+ }
}
+
}