From b993b689b0828b852675a002c76ca0a53cd95483 Mon Sep 17 00:00:00 2001 From: Karsten Herrler Date: Fri, 19 Jan 2024 14:13:02 +0100 Subject: [PATCH 1/4] fixed qmllint warnings --- src/opcuamodel.cpp | 2 +- src/qml/ContentView.qml | 1 - src/qml/ContextMenu.qml | 36 ++++++++------ src/qml/Main.qml | 14 ++++-- src/qml/NodeAttributeList.qml | 63 ++++++------------------ src/qml/NodeDetailView.qml | 3 ++ src/qml/NodeReferenceList.qml | 32 +++++++----- src/qml/NodesView.qml | 43 ++++++++++------ src/qml/SettingsView.qml | 2 +- src/qml/controls/StyledButton.qml | 6 ++- src/qml/controls/StyledComboBox.qml | 4 +- src/qml/controls/StyledIconTabButton.qml | 4 +- src/qml/controls/StyledItemSelector.qml | 10 ++-- src/qml/controls/StyledMenuItem.qml | 2 +- src/qml/controls/StyledMenuSeparator.qml | 4 +- src/qml/controls/StyledScrollBar.qml | 4 +- src/qml/controls/StyledTabButton.qml | 14 +++--- 17 files changed, 126 insertions(+), 118 deletions(-) diff --git a/src/opcuamodel.cpp b/src/opcuamodel.cpp index c85a83c..d667adb 100644 --- a/src/opcuamodel.cpp +++ b/src/opcuamodel.cpp @@ -29,7 +29,7 @@ enum Roles : int { QHash OpcUaModel::roleNames() const { auto names = QAbstractItemModel::roleNames(); - names[ColorRole] = "color"; + names[ColorRole] = "indicatorColor"; names[ValueRole] = "value"; names[NodeIdRole] = "nodeId"; names[AttributesRole] = "attributes"; diff --git a/src/qml/ContentView.qml b/src/qml/ContentView.qml index 0d2fde4..de65c07 100644 --- a/src/qml/ContentView.qml +++ b/src/qml/ContentView.qml @@ -7,7 +7,6 @@ import QtQml import QtQuick -import QtQuick.Controls import QtQuick.Layouts import OPC_UA_Browser diff --git a/src/qml/ContextMenu.qml b/src/qml/ContextMenu.qml index 4c6644d..37c5b23 100644 --- a/src/qml/ContextMenu.qml +++ b/src/qml/ContextMenu.qml @@ -5,6 +5,8 @@ * SPDX-License-Identifier: GPL-3.0-or-later */ +pragma ComponentBehavior: Bound + import QtQuick import QtQuick.Controls import QtQuick.Layouts @@ -12,7 +14,7 @@ import QtQuick.Layouts import OPC_UA_Browser Popup { - id: contextMenu + id: menu property alias listModel: popupListView.model property ThemeContextMenu theme: Style.contextMenu @@ -28,10 +30,10 @@ Popup { background: Rectangle { id: transparentBorderRect - width: contextMenu.width - height: contextMenu.height + width: menu.width + height: menu.height radius: 3 - color: theme.background + color: menu.theme.background } contentItem: Item { @@ -46,25 +48,31 @@ Popup { clip: true delegate: Item { + id: delegateItem + height: 36 width: 200 + required property int index + required property url imageSource + required property string name + MouseArea { anchors.fill: parent hoverEnabled: true - onEntered: popupListView.currentIndex = index + onEntered: popupListView.currentIndex = delegateItem.index onClicked: { - listItemClicked(index) - contextMenu.close() + menu.listItemClicked(delegateItem.index) + menu.close() } } Rectangle { anchors.fill: parent radius: transparentBorderRect.radius - color: theme.backgroundSelected - opacity: popupListView.currentIndex === index ? 0.8 : 0 + color: menu.theme.backgroundSelected + opacity: popupListView.currentIndex === delegateItem.index ? 0.8 : 0 } RowLayout { @@ -76,17 +84,17 @@ Popup { Layout.alignment: Qt.AlignVCenter sourceSize.width: 24 sourceSize.height: 24 - source: model.imageSource - color: theme.textColor + source: delegateItem.imageSource + color: menu.theme.textColor } Text { Layout.fillHeight: true Layout.fillWidth: true verticalAlignment: Text.AlignVCenter - horizontalAlignment: Text.AlignHLeft - color: theme.textColor + horizontalAlignment: Text.AlignLeft + color: menu.theme.textColor font.pointSize: 12 - text: model.name + text: delegateItem.name } } } diff --git a/src/qml/Main.qml b/src/qml/Main.qml index 2516b97..7ffba9b 100644 --- a/src/qml/Main.qml +++ b/src/qml/Main.qml @@ -17,10 +17,6 @@ ApplicationWindow { property ThemeMainWindow theme: Style.mainWindow property int themeIndex: 0 - onThemeIndexChanged: { - Style.currentThemeIndex = themeIndex - UiSettings.setStatusAndNavigationBarColor(theme.background) - } Connections { target: Qt.application @@ -31,6 +27,16 @@ ApplicationWindow { } } + Connections { + target: Style + function onCurrentThemeIndexChanged() { + if (window.themeIndex !== Style.currentThemeIndex) { + window.themeIndex = Style.currentThemeIndex + UiSettings.setStatusAndNavigationBarColor(window.theme.background) + } + } + } + Settings { property alias themeIndex: window.themeIndex } diff --git a/src/qml/NodeAttributeList.qml b/src/qml/NodeAttributeList.qml index 6162663..a9ba365 100644 --- a/src/qml/NodeAttributeList.qml +++ b/src/qml/NodeAttributeList.qml @@ -5,6 +5,8 @@ * SPDX-License-Identifier: GPL-3.0-or-later */ +pragma ComponentBehavior: Bound + import QtQuick import QtQuick.Controls import QtQuick.Layouts @@ -49,7 +51,7 @@ Rectangle { property bool wasOvershooted: false height: flickable.height - width: maxDelegateWidth() + width: root.maxDelegateWidth() model: root.attributes //boundsBehavior: Flickable.StopAtBounds @@ -66,11 +68,15 @@ Rectangle { delegate: Rectangle { id: listViewDelegate + required property int index + required property string attribute + required property string value + readonly property real padding: 5 - width: maxDelegateWidth() + width: root.maxDelegateWidth() implicitHeight: childrenRect.height - color: ((index % 1) == 0) ? theme.color1 : theme.color2 + color: ((listViewDelegate.index % 1) == 0) ? root.theme.color1 : root.theme.color2 ColumnLayout { spacing: 0 @@ -78,20 +84,20 @@ Rectangle { Rectangle { Layout.preferredWidth: flickable.width Layout.preferredHeight: 1 - visible: model.index > 0 - color: theme.divider + visible: listViewDelegate.index > 0 + color: root.theme.divider } Text { - id: attribute + id: attributeText Layout.topMargin: 5 Layout.leftMargin: 5 Layout.fillWidth: true verticalAlignment: Qt.AlignVCenter - text: model.attribute + text: listViewDelegate.attribute elide: Qt.ElideRight - color: theme.textColor + color: root.theme.textColor font { pointSize: 11 bold: true @@ -105,47 +111,10 @@ Rectangle { Layout.bottomMargin: 5 Layout.fillWidth: true verticalAlignment: Qt.AlignVCenter - text: model.value - color: attribute.color + text: listViewDelegate.value + color: attributeText.color } } - - - /*RowLayout { - spacing: 0 - height: Math.max(30, valueLabel.implicitHeight) - - Text { - id: attribute - - Layout.margins: 5 - Layout.fillHeight: true - Layout.preferredWidth: root.width / 3 - verticalAlignment: Qt.AlignVCenter - text: model.attribute - elide: Qt.ElideRight - color: theme.textColor - } - - Rectangle { - id: divider - - Layout.fillHeight: true - width: 1 - color: attribute.color - } - - Text { - id: valueLabel - - Layout.margins: 5 - Layout.fillWidth: true - Layout.fillHeight: true - verticalAlignment: Qt.AlignVCenter - text: model.value - color: attribute.color - } - }*/ } } } diff --git a/src/qml/NodeDetailView.qml b/src/qml/NodeDetailView.qml index 0e1b3a6..bd70e0e 100644 --- a/src/qml/NodeDetailView.qml +++ b/src/qml/NodeDetailView.qml @@ -5,6 +5,8 @@ * SPDX-License-Identifier: GPL-3.0-or-later */ +pragma ComponentBehavior: Bound + import QtQuick import QtQuick.Controls import QtQuick.Layouts @@ -35,6 +37,7 @@ Item { model: [qsTr("Attributes"), qsTr("References")] StyledTabButton { + required property string modelData text: modelData width: Math.max(100, root.width / repeater.count) } diff --git a/src/qml/NodeReferenceList.qml b/src/qml/NodeReferenceList.qml index 7396ac4..bc0f01b 100644 --- a/src/qml/NodeReferenceList.qml +++ b/src/qml/NodeReferenceList.qml @@ -5,6 +5,8 @@ * SPDX-License-Identifier: GPL-3.0-or-later */ +pragma ComponentBehavior: Bound + import QtQuick import QtQuick.Controls import QtQuick.Layouts @@ -48,7 +50,7 @@ Rectangle { id: referenceList height: flickable.height - width: maxDelegateWidth() + width: root.maxDelegateWidth() //boundsBehavior: Flickable.StopAtBounds ScrollBar.vertical: StyledScrollBar {} @@ -62,7 +64,7 @@ Rectangle { implicitHeight: childrenRect.height z: 2 - color: theme.headerBackground + color: root.theme.headerBackground RowLayout { spacing: 0 @@ -81,7 +83,7 @@ Rectangle { Rectangle { Layout.fillHeight: true - width: 1 + Layout.preferredWidth: 1 color: root.textColor } @@ -101,11 +103,17 @@ Rectangle { delegate: Rectangle { id: listViewDelegate + required property int index + required property string type + required property string typeNodeId + required property string target + required property string targetNodeId + readonly property real padding: 5 - width: maxDelegateWidth() + width: root.maxDelegateWidth() implicitHeight: childrenRect.height - color: ((index % 2) == 0) ? theme.color1 : theme.color2 + color: ((listViewDelegate.index % 2) == 0) ? root.theme.color1 : root.theme.color2 RowLayout { spacing: 0 @@ -116,7 +124,7 @@ Rectangle { Layout.alignment: Qt.AlignVCenter sourceSize.width: 15 sourceSize.height: 15 - source: model.isForward ? "qrc:/icons/forward.svg" : "qrc:/icons/inverse.svg" + source: referenceList.model.isForward ? "qrc:/icons/forward.svg" : "qrc:/icons/inverse.svg" color: root.textColor } @@ -125,21 +133,20 @@ Rectangle { Layout.fillHeight: true Layout.preferredWidth: root.width / 3 verticalAlignment: Qt.AlignVCenter - text: model.type + text: listViewDelegate.type elide: Qt.ElideRight color: root.textColor MouseArea { anchors.fill: parent cursorShape: Qt.PointingHandCursor - onClicked: BackEnd.opcUaModel.setCurrentNodeId( - model.typeNodeId) + onClicked: BackEnd.opcUaModel.setCurrentNodeId(typeNodeId) // qmllint disable unresolved-type } } Rectangle { Layout.fillHeight: true - width: 1 + Layout.preferredWidth: 1 color: root.textColor } @@ -149,14 +156,13 @@ Rectangle { Layout.fillHeight: true Layout.minimumWidth: root.width - x verticalAlignment: Qt.AlignVCenter - text: model.target + text: listViewDelegate.target color: root.textColor MouseArea { anchors.fill: parent cursorShape: Qt.PointingHandCursor - onClicked: BackEnd.opcUaModel.setCurrentNodeId( - model.targetNodeId) + onClicked: BackEnd.opcUaModel.setCurrentNodeId(targetNodeId) // qmllint disable unresolved-type } } } diff --git a/src/qml/NodesView.qml b/src/qml/NodesView.qml index 31a9bcc..2a325be 100644 --- a/src/qml/NodesView.qml +++ b/src/qml/NodesView.qml @@ -5,6 +5,8 @@ * SPDX-License-Identifier: GPL-3.0-or-later */ +pragma ComponentBehavior: Bound + import QtQuick import QtQuick.Controls @@ -60,7 +62,6 @@ Item { delegate: Rectangle { id: treeDelegate - readonly property real isCurrentItem: model.isCurrentItem readonly property real indent: 25 readonly property real padding: 5 @@ -70,11 +71,25 @@ Item { required property bool expanded required property int hasChildren required property int depth + required property int row + required property int column + + // Assigned to by model: + required property bool isCurrentItem + required property bool isSelected + required property bool canMonitoring + required property bool hasEventNotifier + required property color indicatorColor + required property string display + required property string value + required property var attributes + required property var references + required property var model onIsCurrentItemChanged: { if (isCurrentItem) { - view.attributes = model.attributes - view.references = model.references + view.attributes = attributes + view.references = references } } @@ -89,14 +104,12 @@ Item { id: tapHandler onTapped: { - treeView.toggleExpanded(row) - BackEnd.opcUaModel.setCurrentIndex(treeView.index(row, - column)) + treeView.toggleExpanded(treeDelegate.row) + BackEnd.opcUaModel.setCurrentIndex(treeView.index(treeDelegate.row, treeDelegate.column)) } onLongPressed: { - BackEnd.opcUaModel.setCurrentIndex(treeView.index(row, - column)) + BackEnd.opcUaModel.setCurrentIndex(treeView.index(row, column)) var xPos = tapHandler.point.position.x + treeDelegate.x - treeView.contentX var yPos = tapHandler.point.position.y + treeDelegate.y - treeView.contentY @@ -137,7 +150,7 @@ Item { anchors.verticalCenter: label.verticalCenter width: height height: label.height / 2 - color: model.color + color: treeDelegate.indicatorColor border.width: 1 } @@ -148,9 +161,9 @@ Item { anchors.verticalCenter: parent.verticalCenter width: treeDelegate.width - treeDelegate.padding - x clip: true - text: model.display + text: treeDelegate.display font.pointSize: 12 - color: model.isCurrentItem ? view.theme.textColorSelected : view.theme.textColor + color: treeDelegate.isCurrentItem ? view.theme.textColorSelected : view.theme.textColor } StyledItemSelector { @@ -158,11 +171,11 @@ Item { anchors.verticalCenter: treeDelegate.verticalCenter height: treeDelegate.height - 10 width: height - checkState: model.isSelected ? Qt.Checked : Qt.Unchecked - visible: (view.canSelectVariables && model.canMonitoring) - || (view.canSelectEvents && model.hasEventNotifier) + checkState: treeDelegate.isSelected ? Qt.Checked : Qt.Unchecked + visible: (view.canSelectVariables && treeDelegate.canMonitoring) + || (view.canSelectEvents && treeDelegate.hasEventNotifier) - onToggled: model.isSelected = !model.isSelected + onToggled: treeDelegate.model.isSelected = !treeDelegate.isSelected } } } diff --git a/src/qml/SettingsView.qml b/src/qml/SettingsView.qml index 35d9463..3a13b04 100644 --- a/src/qml/SettingsView.qml +++ b/src/qml/SettingsView.qml @@ -15,7 +15,7 @@ Rectangle { property ThemeSettingsView theme: Style.settingsView function setTheme(index) { - window.themeIndex = index + Style.currentThemeIndex = index if (index === 0) { darkItemSelector.checkState = Qt.Checked brightItemSelector.checkState = Qt.Unchecked diff --git a/src/qml/controls/StyledButton.qml b/src/qml/controls/StyledButton.qml index 8399377..efbce9b 100644 --- a/src/qml/controls/StyledButton.qml +++ b/src/qml/controls/StyledButton.qml @@ -11,6 +11,8 @@ import QtQuick.Controls import OPC_UA_Browser Button { + id: button + highlighted: true height: 36 @@ -20,8 +22,8 @@ Button { palette.buttonText: theme.textColor background: Rectangle { - color: highlighted ? theme.highlightedBackground : theme.background - border.color: highlighted ? theme.highlightedBorderColor : theme.borderColor + color: button.highlighted ? button.theme.highlightedBackground : button.theme.background + border.color: button.highlighted ? button.theme.highlightedBorderColor : button.theme.borderColor border.width: 1 radius: 5 } diff --git a/src/qml/controls/StyledComboBox.qml b/src/qml/controls/StyledComboBox.qml index 0174027..b419fed 100644 --- a/src/qml/controls/StyledComboBox.qml +++ b/src/qml/controls/StyledComboBox.qml @@ -30,7 +30,7 @@ ColumnLayout { Layout.preferredHeight: layout.textColumnHeight verticalAlignment: Qt.AlignVCenter - color: theme.captionTextColor + color: layout.theme.captionTextColor font.bold: true } @@ -39,6 +39,6 @@ ColumnLayout { Layout.fillWidth: true Layout.preferredHeight: layout.comboBoxColumnHeight - palette.button: theme.background + palette.button: layout.theme.background } } diff --git a/src/qml/controls/StyledIconTabButton.qml b/src/qml/controls/StyledIconTabButton.qml index 123dcd3..34b5b5f 100644 --- a/src/qml/controls/StyledIconTabButton.qml +++ b/src/qml/controls/StyledIconTabButton.qml @@ -25,7 +25,7 @@ TabButton { width: 80 background: Rectangle { - color: isCurrentTab ? theme.backgroundSelected : theme.background + color: control.isCurrentTab ? control.theme.backgroundSelected : control.theme.background } contentItem: ColumnLayout { @@ -48,7 +48,7 @@ TabButton { horizontalAlignment: Text.AlignHCenter font.pointSize: 8 text: control.text - color: isCurrentTab ? theme.textColorSelected : theme.textColor + color: control.isCurrentTab ? control.theme.textColorSelected : control.theme.textColor elide: Text.ElideRight } } diff --git a/src/qml/controls/StyledItemSelector.qml b/src/qml/controls/StyledItemSelector.qml index db5fa5b..8583af3 100644 --- a/src/qml/controls/StyledItemSelector.qml +++ b/src/qml/controls/StyledItemSelector.qml @@ -21,15 +21,15 @@ CheckBox { width: control.width height: width radius: width / 2 - color: theme.background - opacity: theme.backgroundOpacity + color: control.theme.background + opacity: control.theme.backgroundOpacity } Rectangle { anchors.fill: parent radius: background.radius border.width: 1 - border.color: theme.borderColor + border.color: control.theme.borderColor color: "transparent" IconImage { @@ -39,8 +39,8 @@ CheckBox { source: "qrc:/icons/checkmark.svg" sourceSize.width: parent.height * 0.65 sourceSize.height: parent.width * 0.65 - color: theme.checkMarkColor - visible: (checkState === Qt.Checked) + color: control.theme.checkMarkColor + visible: (control.checkState === Qt.Checked) } } } diff --git a/src/qml/controls/StyledMenuItem.qml b/src/qml/controls/StyledMenuItem.qml index 7114229..8341598 100644 --- a/src/qml/controls/StyledMenuItem.qml +++ b/src/qml/controls/StyledMenuItem.qml @@ -28,6 +28,6 @@ MenuItem { } background: Rectangle { - color: theme.background + color: control.theme.background } } diff --git a/src/qml/controls/StyledMenuSeparator.qml b/src/qml/controls/StyledMenuSeparator.qml index dc20b88..3457de1 100644 --- a/src/qml/controls/StyledMenuSeparator.qml +++ b/src/qml/controls/StyledMenuSeparator.qml @@ -11,12 +11,14 @@ import QtQuick.Controls import OPC_UA_Browser MenuSeparator { + id: separator + property ThemeSideMenu theme: Style.sideMenu height: enabled ? implicitHeight : 0 contentItem: Rectangle { implicitHeight: 1 - color: theme.iconColor + color: separator.theme.iconColor } } diff --git a/src/qml/controls/StyledScrollBar.qml b/src/qml/controls/StyledScrollBar.qml index 45f9c49..6301dba 100644 --- a/src/qml/controls/StyledScrollBar.qml +++ b/src/qml/controls/StyledScrollBar.qml @@ -19,7 +19,7 @@ ScrollBar { implicitWidth: 10 implicitHeight: 10 radius: 5 - color: theme.selector + color: control.theme.selector opacity: (control.policy === ScrollBar.AlwaysOn) || (control.active && control.size < 1.0) ? 0.75 : 0 @@ -30,6 +30,6 @@ ScrollBar { } background: Rectangle { - color: theme.background + color: control.theme.background } } diff --git a/src/qml/controls/StyledTabButton.qml b/src/qml/controls/StyledTabButton.qml index d053b40..5d791c8 100644 --- a/src/qml/controls/StyledTabButton.qml +++ b/src/qml/controls/StyledTabButton.qml @@ -11,14 +11,14 @@ import QtQuick.Controls import OPC_UA_Browser TabButton { - id: root + id: button readonly property bool isCurrentTab: (TabBar.tabBar.currentIndex == TabBar.index) property ThemeTabButton theme: Style.tabButton background: Rectangle { - color: theme.background + color: button.theme.background Rectangle { id: divider @@ -26,26 +26,26 @@ TabButton { anchors.right: parent.right anchors.bottom: parent.bottom height: 4 - color: theme.dividerColor + color: button.theme.dividerColor } Rectangle { anchors.centerIn: divider width: divider.width / 2 height: 4 - visible: isCurrentTab - color: theme.dividerColorSelected + visible: button.isCurrentTab + color: button.theme.dividerColorSelected } } contentItem: Text { - text: root.text + text: button.text font { pointSize: 11 bold: true capitalization: Font.AllUppercase } - color: theme.textColor + color: button.theme.textColor horizontalAlignment: Text.AlignHCenter verticalAlignment: Text.AlignVCenter elide: Text.ElideRight From 4d094b587c1a7577f977fb1386cb9bcc64077575 Mon Sep 17 00:00:00 2001 From: Karsten Herrler Date: Mon, 22 Jan 2024 15:02:13 +0100 Subject: [PATCH 2/4] fixed qmllint warnings --- src/CMakeLists.txt | 8 +-- src/backend.cpp | 28 +++++----- src/backend.h | 50 ++++++++++++------ src/dashboarditem.cpp | 14 ++--- src/dashboarditem.h | 15 ++++-- src/dashboarditemmodel.cpp | 14 ++--- src/dashboarditemmodel.h | 9 +++- src/main.cpp | 4 -- src/opcuamodel.h | 2 + src/qml/DashboardConfigurationView.qml | 3 +- src/qml/DashboardView.qml | 57 ++++++++++++++------- src/qml/NodeReferenceList.qml | 4 +- src/qml/NodesView.qml | 7 +-- src/qml/controls/SideMenu.qml | 1 - src/qml/controls/StyledEndpointComboBox.qml | 23 +++++---- src/qml/controls/StyledIconTabButton.qml | 8 +-- src/qml/style/ThemeBright.qml | 2 - src/qml/style/ThemeButton.qml | 2 +- src/qml/style/ThemeComboBox.qml | 2 +- src/qml/style/ThemeDark.qml | 2 - src/qml/style/ThemeHeader.qml | 2 +- src/qml/style/ThemeIconTabButton.qml | 2 +- src/qml/style/ThemeItemSelector.qml | 2 +- src/qml/style/ThemeTextField.qml | 2 +- src/types.h | 23 --------- 25 files changed, 154 insertions(+), 132 deletions(-) delete mode 100644 src/types.h diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index d35a652..a7dfc72 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -4,7 +4,10 @@ SPDX-FileContributor: Karsten Herrler SPDX-License-Identifier: BSD-3-Clause ]] - cmake_minimum_required(VERSION 3.19) +cmake_minimum_required(VERSION 3.19) + +set(QT_QML_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/qml) +set(QML_IMPORT_PATH ${QT_QML_OUTPUT_DIRECTORY} CACHE STRING "Import paths for Qt Creator's code model" FORCE) qt_add_executable(appOPC_UA_Browser main.cpp @@ -16,7 +19,7 @@ set_source_files_properties(qml/style/Style.qml PROPERTIES qt_add_qml_module(appOPC_UA_Browser URI OPC_UA_Browser - VERSION 1.0.0 + VERSION 1.0 QML_FILES qml/Main.qml qml/BrowserView.qml qml/ConnectionView.qml @@ -77,7 +80,6 @@ qt_add_qml_module(appOPC_UA_Browser reference.h reference.cpp referencemodel.h referencemodel.cpp treeitem.h treeitem.cpp - types.h uisettings.h uisettings.cpp x509certificate.h x509certificate.cpp ) diff --git a/src/backend.cpp b/src/backend.cpp index 1117d13..1466cd6 100644 --- a/src/backend.cpp +++ b/src/backend.cpp @@ -14,9 +14,7 @@ #include #include "backend.h" -#include "dashboarditemmodel.h" #include "monitoreditemmodel.h" -#include "opcuamodel.h" #include "x509certificate.h" static QString defaultPkiPath() @@ -40,10 +38,10 @@ BackEnd::BackEnd(QObject *parent) mOpcUaModel(new OpcUaModel(this)), mOpcUaProvider(new QOpcUaProvider(this)), mDashboardItemModel(new DashboardItemModel(this)), - mDefaultVariableDashboardsModel(new QStringListModel(this)), - mDefaultEventDashboardsModel(new QStringListModel(this)), - mSavedVariableDashboardsModel(new QStringListModel(this)), - mSavedEventDashboardsModel(new QStringListModel(this)) + mDefaultVariableDashboardsModel(new QQmlStringListModel(this)), + mDefaultEventDashboardsModel(new QQmlStringListModel(this)), + mSavedVariableDashboardsModel(new QQmlStringListModel(this)), + mSavedEventDashboardsModel(new QQmlStringListModel(this)) { setupPkiConfiguration(); @@ -128,27 +126,27 @@ OpcUaModel *BackEnd::opcUaModel() const noexcept return mOpcUaModel; } -QAbstractItemModel *BackEnd::dashboardItemModel() const noexcept +DashboardItemModel *BackEnd::dashboardItemModel() const noexcept { return mDashboardItemModel; } -QStringListModel *BackEnd::defaultVariableDashboards() const noexcept +QQmlStringListModel *BackEnd::defaultVariableDashboards() const noexcept { return mDefaultVariableDashboardsModel; } -QStringListModel *BackEnd::defaultEventDashboards() const noexcept +QQmlStringListModel *BackEnd::defaultEventDashboards() const noexcept { return mDefaultEventDashboardsModel; } -QStringListModel *BackEnd::savedVariableDashboards() const noexcept +QQmlStringListModel *BackEnd::savedVariableDashboards() const noexcept { return mSavedVariableDashboardsModel; } -QStringListModel *BackEnd::savedEventDashboards() const noexcept +QQmlStringListModel *BackEnd::savedEventDashboards() const noexcept { return mSavedEventDashboardsModel; } @@ -281,11 +279,11 @@ void BackEnd::saveCurrentDashboard(const QString &name) QSettings settings; switch (mDashboardItemModel->getCurrentDashboardType()) { - case Types::DashboardType::Variables: + case DashboardItem::DashboardType::Variables: settings.setValue("dashboards/variables/" % name, nodeIds); addItemToStringListModel(mSavedVariableDashboardsModel, name); break; - case Types::DashboardType::Events: + case DashboardItem::DashboardType::Events: settings.setValue("dashboards/events/" % name, nodeIds); addItemToStringListModel(mSavedEventDashboardsModel, name); break; @@ -526,8 +524,8 @@ void BackEnd::loadLastDashboardsFromSettings() for (int i = 0; i < size; ++i) { settings.setArrayIndex(i); const QString name = settings.value("name").toString(); - const Types::DashboardType type = - static_cast(settings.value("type", 0).toInt()); + const DashboardItem::DashboardType type = + static_cast(settings.value("type", 0).toInt()); const int index = mDashboardItemModel->addItem(type, name); auto model = mDashboardItemModel->getMonitoredItemModel(index); diff --git a/src/backend.h b/src/backend.h index 027ac35..fffad03 100644 --- a/src/backend.h +++ b/src/backend.h @@ -16,11 +16,29 @@ #include #include +#include "dashboarditemmodel.h" #include "opcuamodel.h" -class DashboardItemModel; class MonitoredItemModel; +// Workaround, otherwise qmllint doesn't recognise the QStringListModel +class QQmlStringListModel : public QStringListModel +{ + Q_OBJECT + QML_ANONYMOUS + +public: + explicit QQmlStringListModel(QObject *parent = nullptr) + : QStringListModel(parent){ + + }; + + Q_INVOKABLE int rowCount(const QModelIndex &parent = QModelIndex()) const override + { + return QStringListModel::rowCount(parent); + }; +}; + class BackEnd : public QObject { Q_OBJECT @@ -35,16 +53,16 @@ class BackEnd : public QObject recentConnectionsChanged FINAL) Q_PROPERTY(QVector serverList READ serverList NOTIFY serverListChanged FINAL) Q_PROPERTY(QVector endpointList READ endpointList NOTIFY endpointListChanged FINAL) - Q_PROPERTY(QAbstractItemModel *opcUaModel READ opcUaModel NOTIFY opcUaModelChanged FINAL) - Q_PROPERTY(QAbstractItemModel *dashboardItemModel READ dashboardItemModel NOTIFY + Q_PROPERTY(OpcUaModel *opcUaModel READ opcUaModel NOTIFY opcUaModelChanged FINAL) + Q_PROPERTY(DashboardItemModel *dashboardItemModel READ dashboardItemModel NOTIFY opcUaModelChanged FINAL) - Q_PROPERTY(QStringListModel *defaultVariableDashboards READ defaultVariableDashboards NOTIFY + Q_PROPERTY(QQmlStringListModel *defaultVariableDashboards READ defaultVariableDashboards NOTIFY defaultVariableDashboardsChanged FINAL) - Q_PROPERTY(QStringListModel *defaultEventDashboards READ defaultEventDashboards NOTIFY + Q_PROPERTY(QQmlStringListModel *defaultEventDashboards READ defaultEventDashboards NOTIFY defaultEventDashboardsChanged FINAL) - Q_PROPERTY(QStringListModel *savedVariableDashboards READ savedVariableDashboards NOTIFY + Q_PROPERTY(QQmlStringListModel *savedVariableDashboards READ savedVariableDashboards NOTIFY savedVariableDashboardsChanged FINAL) - Q_PROPERTY(QStringListModel *savedEventDashboards READ savedEventDashboards NOTIFY + Q_PROPERTY(QQmlStringListModel *savedEventDashboards READ savedEventDashboards NOTIFY savedEventDashboardsChanged FINAL) Q_PROPERTY(bool hasLastDashboards READ hasLastDashboards CONSTANT FINAL) @@ -58,11 +76,11 @@ class BackEnd : public QObject QVector serverList() const noexcept; QVector endpointList() const; OpcUaModel *opcUaModel() const noexcept; - QAbstractItemModel *dashboardItemModel() const noexcept; - QStringListModel *defaultVariableDashboards() const noexcept; - QStringListModel *defaultEventDashboards() const noexcept; - QStringListModel *savedVariableDashboards() const noexcept; - QStringListModel *savedEventDashboards() const noexcept; + DashboardItemModel *dashboardItemModel() const noexcept; + QQmlStringListModel *defaultVariableDashboards() const noexcept; + QQmlStringListModel *defaultEventDashboards() const noexcept; + QQmlStringListModel *savedVariableDashboards() const noexcept; + QQmlStringListModel *savedEventDashboards() const noexcept; bool hasLastDashboards() const noexcept; Q_INVOKABLE void clearServerList(); @@ -135,10 +153,10 @@ private slots: DashboardItemModel *mDashboardItemModel = nullptr; QVector mLastServerHosts; - QStringListModel *mDefaultVariableDashboardsModel; - QStringListModel *mDefaultEventDashboardsModel; - QStringListModel *mSavedVariableDashboardsModel; - QStringListModel *mSavedEventDashboardsModel; + QQmlStringListModel *mDefaultVariableDashboardsModel; + QQmlStringListModel *mDefaultEventDashboardsModel; + QQmlStringListModel *mSavedVariableDashboardsModel; + QQmlStringListModel *mSavedEventDashboardsModel; bool mHasLastDashboards = false; }; diff --git a/src/dashboarditem.cpp b/src/dashboarditem.cpp index b8ecc86..cce77c2 100644 --- a/src/dashboarditem.cpp +++ b/src/dashboarditem.cpp @@ -10,14 +10,14 @@ #include "dashboarditem.h" #include "monitoreditemmodel.h" -QString getDefaultNameForType(Types::DashboardType type) +QString getDefaultNameForType(DashboardItem::DashboardType type) { switch (type) { - case Types::DashboardType::Variables: + case DashboardItem::DashboardType::Variables: return QCoreApplication::translate("OpcUaBrowser", "Dashboard"); - case Types::DashboardType::Events: + case DashboardItem::DashboardType::Events: return QCoreApplication::translate("OpcUaBrowser", "Event"); - case Types::DashboardType::Add: + case DashboardItem::DashboardType::Add: return QCoreApplication::translate("OpcUaBrowser", "Add"); default: break; @@ -27,14 +27,14 @@ QString getDefaultNameForType(Types::DashboardType type) return QString(); } -DashboardItem::DashboardItem(Types::DashboardType type, const QString &name) +DashboardItem::DashboardItem(DashboardItem::DashboardType type, const QString &name) : mName(name), mType(type) { if (mName.isEmpty()) { mName = getDefaultNameForType(type); } - if (type != Types::DashboardType::Add) { + if (type != DashboardItem::DashboardType::Add) { mMonitoredItemModel = new MonitoredItemModel(); } } @@ -58,7 +58,7 @@ void DashboardItem::setName(const QString &name) } } -Types::DashboardType DashboardItem::type() const noexcept +DashboardItem::DashboardType DashboardItem::type() const noexcept { return mType; } diff --git a/src/dashboarditem.h b/src/dashboarditem.h index 55d89e9..942a7a0 100644 --- a/src/dashboarditem.h +++ b/src/dashboarditem.h @@ -12,27 +12,32 @@ #include #include -#include "types.h" - class MonitoredItemModel; class QAbstractListModel; class DashboardItem : public QObject { + Q_OBJECT + QML_ELEMENT + QML_UNCREATABLE("DashboardItem is created by DashboardItemModel") + public: - explicit DashboardItem(Types::DashboardType type, const QString &name = QString()); + enum class DashboardType { Unknown = -1, Variables, Events, Add }; + Q_ENUM(DashboardType) + + explicit DashboardItem(DashboardItem::DashboardType type, const QString &name = QString()); ~DashboardItem(); const QString &name() const noexcept; void setName(const QString &name); - Types::DashboardType type() const noexcept; + DashboardItem::DashboardType type() const noexcept; QAbstractListModel *monitoredItemModel() const noexcept; QStringList getMonitoredNodeIds() const; private: QString mName; - Types::DashboardType mType; + DashboardItem::DashboardType mType; MonitoredItemModel *mMonitoredItemModel = nullptr; }; diff --git a/src/dashboarditemmodel.cpp b/src/dashboarditemmodel.cpp index 7b49d39..3e88aef 100644 --- a/src/dashboarditemmodel.cpp +++ b/src/dashboarditemmodel.cpp @@ -20,7 +20,7 @@ enum Roles : int { DashboardItemModel::DashboardItemModel(QObject *parent) : QAbstractListModel{ parent } { // Insert Add item - mItems.push_back(new DashboardItem(Types::DashboardType::Add)); + mItems.push_back(new DashboardItem(DashboardItem::DashboardType::Add)); } DashboardItemModel::~DashboardItemModel() @@ -59,7 +59,7 @@ QVariant DashboardItemModel::data(const QModelIndex &index, int role) const return QVariant(); } -int DashboardItemModel::addItem(Types::DashboardType type, const QString &name) +int DashboardItemModel::addItem(DashboardItem::DashboardType type, const QString &name) { const int pos = mItems.size() - 1; DashboardItem *item = new DashboardItem(type, name); @@ -90,7 +90,7 @@ void DashboardItemModel::clearItems() qDeleteAll(mItems); mItems.clear(); // Insert Add item - mItems.push_back(new DashboardItem(Types::DashboardType::Add)); + mItems.push_back(new DashboardItem(DashboardItem::DashboardType::Add)); endResetModel(); } @@ -107,10 +107,10 @@ MonitoredItemModel *DashboardItemModel::getCurrentMonitoredItemModel() const return getMonitoredItemModel(mCurrentIndex); } -Types::DashboardType DashboardItemModel::getCurrentDashboardType() const +DashboardItem::DashboardType DashboardItemModel::getCurrentDashboardType() const { if (mCurrentIndex >= mItems.size()) - return Types::DashboardType::Unknown; + return DashboardItem::DashboardType::Unknown; return mItems[mCurrentIndex]->type(); } @@ -131,7 +131,7 @@ bool DashboardItemModel::isAddItem(uint index) const if (index >= mItems.size()) return false; - return (mItems.at(index)->type() == Types::DashboardType::Add); + return (mItems.at(index)->type() == DashboardItem::DashboardType::Add); } void DashboardItemModel::setCurrentIndex(uint index) @@ -152,7 +152,7 @@ void DashboardItemModel::saveDashboardsToSettings() const settings.beginWriteArray("lastDashboards"); for (qsizetype i = 0; i < mItems.count(); ++i) { - if (mItems[i]->type() == Types::DashboardType::Add) + if (mItems[i]->type() == DashboardItem::DashboardType::Add) continue; settings.setArrayIndex(i); diff --git a/src/dashboarditemmodel.h b/src/dashboarditemmodel.h index df138e9..8f2c311 100644 --- a/src/dashboarditemmodel.h +++ b/src/dashboarditemmodel.h @@ -9,12 +9,17 @@ #define DASHBOARDITEMMODEL_H #include +#include #include "dashboarditem.h" +class MonitoredItemModel; + class DashboardItemModel : public QAbstractListModel { Q_OBJECT + QML_ANONYMOUS + public: explicit DashboardItemModel(QObject *parent = nullptr); ~DashboardItemModel(); @@ -24,13 +29,13 @@ class DashboardItemModel : public QAbstractListModel QVariant data(const QModelIndex &index, int role) const override; bool containsItem(const QString &name) const noexcept; - Q_INVOKABLE int addItem(Types::DashboardType type, const QString &name = QString()); + Q_INVOKABLE int addItem(DashboardItem::DashboardType type, const QString &name = QString()); Q_INVOKABLE void removeItem(int index); void clearItems(); MonitoredItemModel *getMonitoredItemModel(int index) const; MonitoredItemModel *getCurrentMonitoredItemModel() const; - Types::DashboardType getCurrentDashboardType() const; + DashboardItem::DashboardType getCurrentDashboardType() const; void setCurrentDashboardName(const QString &name); Q_INVOKABLE bool isAddItem(uint index) const; diff --git a/src/main.cpp b/src/main.cpp index dcb129b..b20d1a1 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -13,8 +13,6 @@ #include #include -#include "types.h" - static constexpr auto FontSwansea = "://font/Swansea.ttf"; static constexpr auto FontSwanseaBold = "://font/SwanseaBold.ttf"; @@ -49,8 +47,6 @@ int main(int argc, char *argv[]) &engine, &QQmlApplicationEngine::objectCreationFailed, &app, []() { QCoreApplication::exit(-1); }, Qt::QueuedConnection); - qmlRegisterUncreatableMetaObject(Types::staticMetaObject, "Types", 1, 0, "DashboardType", - "Error: only enums"); engine.loadFromModule("OPC_UA_Browser", "Main"); return app.exec(); diff --git a/src/opcuamodel.h b/src/opcuamodel.h index da58b14..53b061f 100644 --- a/src/opcuamodel.h +++ b/src/opcuamodel.h @@ -9,6 +9,7 @@ #define OPCUAMODEL_H #include +#include #include "treeitem.h" @@ -18,6 +19,7 @@ class QOpcUaNode; class OpcUaModel : public QAbstractItemModel { Q_OBJECT + QML_ANONYMOUS public: explicit OpcUaModel(QObject *parent = nullptr); diff --git a/src/qml/DashboardConfigurationView.qml b/src/qml/DashboardConfigurationView.qml index 0aee8f0..5278440 100644 --- a/src/qml/DashboardConfigurationView.qml +++ b/src/qml/DashboardConfigurationView.qml @@ -6,7 +6,6 @@ */ import QtQuick -import QtQuick.Controls import QtQuick.Layouts import OPC_UA_Browser @@ -57,7 +56,7 @@ Item { onClicked: { if ((BackEnd.defaultVariableDashboards.rowCount() === 0) && (BackEnd.savedVariableDashboards.rowCount() === 0)) { - addMonitoredItems() + view.addMonitoredItems() } else { view.type = DashboardConfigurationView.Type.SelectVariables } diff --git a/src/qml/DashboardView.qml b/src/qml/DashboardView.qml index 3681fbc..47ce69d 100644 --- a/src/qml/DashboardView.qml +++ b/src/qml/DashboardView.qml @@ -5,19 +5,19 @@ * SPDX-License-Identifier: GPL-3.0-or-later */ +pragma ComponentBehavior: Bound + import QtQuick import QtQuick.Controls import QtQuick.Layouts import OPC_UA_Browser -import Types Rectangle { id: view readonly property bool canSaveDashboard: repeater.count > 1 - readonly property string currentDashboardName: (tabBar.currentItem - === null) ? "" : tabBar.currentItem.text + readonly property string currentDashboardName: (tabBar.currentItem === null) ? "" : tabBar.currentText readonly property int itemWidth: { // Calculate content width of flow var contentWidth = flow.width - flow.leftPadding - flow.rightPadding @@ -37,12 +37,12 @@ Rectangle { signal addNewDashboard function addMonitoredItemsDashboard(name) { - tabRepeater.model.addItem(DashboardType.Variables, name) + tabRepeater.model.addItem(DashboardItem.DashboardType.Variables, name) tabBar.currentIndex = tabRepeater.count - 2 } function addEventsDashboard(name) { - tabRepeater.model.addItem(DashboardType.Events, name) + tabRepeater.model.addItem(DashboardItem.DashboardType.Events, name) tabBar.currentIndex = tabRepeater.count - 2 } @@ -97,7 +97,7 @@ Rectangle { onReleased: held = false onClicked: { if (dragArea.isAddItem) { - addMonitoredItems() + view.addMonitoredItems() } } @@ -112,7 +112,7 @@ Rectangle { width: view.itemWidth implicitHeight: Math.max(80, childrenRect.height) radius: 5 - color: dragArea.held ? theme.item.backgroundHeld : dragArea.hasError ? theme.item.backgroundError : theme.item.background + color: dragArea.held ? view.theme.item.backgroundHeld : dragArea.hasError ? view.theme.item.backgroundError : view.theme.item.background Behavior on color { ColorAnimation { @@ -126,7 +126,8 @@ Rectangle { ParentChange { target: content parent: view - width: view.itemWidth + // https://bugreports.qt.io/browse/QTBUG-101364 + width: view.itemWidth // qmllint disable incompatible-type } AnchorChanges { target: content @@ -148,7 +149,7 @@ Rectangle { Text { Layout.fillWidth: true - color: theme.item.textColor + color: view.theme.item.textColor text: dragArea.name font { pointSize: 12 @@ -162,7 +163,7 @@ Rectangle { sourceSize.width: 24 sourceSize.height: 24 source: "qrc:/icons/delete.svg" - color: theme.item.textColor + color: view.theme.item.textColor MouseArea { anchors.fill: parent @@ -176,7 +177,7 @@ Rectangle { Text { width: parent.width - 2 * parent.padding font.pointSize: 10 - color: theme.item.textColor + color: view.theme.item.textColor text: dragArea.value elide: Text.ElideRight clip: true @@ -186,7 +187,7 @@ Rectangle { visible: dragArea.hasError width: parent.width - 2 * parent.padding font.pointSize: 10 - color: theme.item.textColor + color: view.theme.item.textColor text: dragArea.status elide: Text.ElideRight clip: true @@ -199,7 +200,7 @@ Rectangle { sourceSize.height: 48 visible: dragArea.isAddItem source: "qrc:/icons/plus.svg" - color: theme.item.textColor + color: view.theme.item.textColor } } @@ -221,7 +222,7 @@ Rectangle { DelegateModel { id: visualModel - model: (tabBar.currentItem === null) ? null : tabBar.currentItem.monitoringModel + model: (tabBar.currentItem === null) ? null : tabBar.currentMonitoringModel delegate: dragDelegate } @@ -259,6 +260,8 @@ Rectangle { property int lastCurrentIndex: 0 property bool allowSelectingAddItem: false + property string currentText + property var currentMonitoringModel anchors.left: parent.left anchors.right: parent.right @@ -288,18 +291,34 @@ Rectangle { StyledIconTabButton { id: tabButton + required property var model + required property var monitoringModel + required property int index + type: model.type text: model.name - property var monitoringModel: model.monitoringModel onClicked: { - if (type === DashboardType.Add) { - addNewDashboard() + if (type === DashboardItem.DashboardType.Add) { + view.addNewDashboard() + } + } + + onIsCurrentTabChanged: { + if (isCurrentTab) { + tabBar.currentText = tabButton.text + tabBar.currentMonitoringModel = tabButton.monitoringModel + } + } + + onTextChanged: { + if (isCurrentTab) { + tabBar.currentText = tabButton.text } } onPressAndHold: { - if (type === DashboardType.Add) + if (type === DashboardItem.DashboardType.Add) return var pressedPoint = mapToItem(view, tabButton.pressX, @@ -310,7 +329,7 @@ Rectangle { view.width - contextMenu.width)) contextMenu.y = pressedPoint.y - contextMenu.height - contextMenu.selectedIndex = index + contextMenu.selectedIndex = tabButton.index contextMenu.open() } } diff --git a/src/qml/NodeReferenceList.qml b/src/qml/NodeReferenceList.qml index bc0f01b..54bd359 100644 --- a/src/qml/NodeReferenceList.qml +++ b/src/qml/NodeReferenceList.qml @@ -140,7 +140,7 @@ Rectangle { MouseArea { anchors.fill: parent cursorShape: Qt.PointingHandCursor - onClicked: BackEnd.opcUaModel.setCurrentNodeId(typeNodeId) // qmllint disable unresolved-type + onClicked: BackEnd.opcUaModel.setCurrentNodeId(listViewDelegate.typeNodeId) } } @@ -162,7 +162,7 @@ Rectangle { MouseArea { anchors.fill: parent cursorShape: Qt.PointingHandCursor - onClicked: BackEnd.opcUaModel.setCurrentNodeId(targetNodeId) // qmllint disable unresolved-type + onClicked: BackEnd.opcUaModel.setCurrentNodeId(listViewDelegate.targetNodeId) } } } diff --git a/src/qml/NodesView.qml b/src/qml/NodesView.qml index 2a325be..e6c2ab5 100644 --- a/src/qml/NodesView.qml +++ b/src/qml/NodesView.qml @@ -22,7 +22,7 @@ Item { property ThemeNodesView theme: Style.nodesView Connections { - target: BackEnd.opcUaModel + target: BackEnd.opcUaModel // qmllint disable incompatible-type function onCurrentIndexChanged(index) { treeView.expandToIndex(index) treeView.forceLayout() @@ -103,13 +103,14 @@ Item { TapHandler { id: tapHandler - onTapped: { + // ToDo: fix qmllint warning + onTapped: function(point, button) { // qmllint disable signal-handler-parameters treeView.toggleExpanded(treeDelegate.row) BackEnd.opcUaModel.setCurrentIndex(treeView.index(treeDelegate.row, treeDelegate.column)) } onLongPressed: { - BackEnd.opcUaModel.setCurrentIndex(treeView.index(row, column)) + BackEnd.opcUaModel.setCurrentIndex(treeView.index(treeDelegate.row, treeDelegate.column)) var xPos = tapHandler.point.position.x + treeDelegate.x - treeView.contentX var yPos = tapHandler.point.position.y + treeDelegate.y - treeView.contentY diff --git a/src/qml/controls/SideMenu.qml b/src/qml/controls/SideMenu.qml index fc8786d..10dbd16 100644 --- a/src/qml/controls/SideMenu.qml +++ b/src/qml/controls/SideMenu.qml @@ -7,7 +7,6 @@ import QtQuick import QtQuick.Controls -import QtQuick.Layouts import OPC_UA_Browser diff --git a/src/qml/controls/StyledEndpointComboBox.qml b/src/qml/controls/StyledEndpointComboBox.qml index 5eddcf8..43aec13 100644 --- a/src/qml/controls/StyledEndpointComboBox.qml +++ b/src/qml/controls/StyledEndpointComboBox.qml @@ -5,10 +5,14 @@ * SPDX-License-Identifier: GPL-3.0-or-later */ +pragma ComponentBehavior: Bound + import QtQuick import QtQuick.Controls StyledComboBox { + id: comboBox + comboBoxColumnHeight: _comboBox.contentItem.implicitHeight function getDisplayTextPart(str, part) { @@ -26,21 +30,21 @@ StyledComboBox { leftPadding: 12 Text { font.pointSize: 12 - text: getDisplayTextPart(_comboBox.displayText, 0) + text: comboBox.getDisplayTextPart(comboBox._comboBox.displayText, 0) verticalAlignment: Text.AlignVCenter } Text { leftPadding: 12 font.pointSize: 10 - text: getDisplayTextPart(_comboBox.displayText, 1) + text: comboBox.getDisplayTextPart(comboBox._comboBox.displayText, 1) verticalAlignment: Text.AlignVCenter } Text { leftPadding: 12 font.pointSize: 10 - text: getDisplayTextPart(_comboBox.displayText, 2) + text: comboBox.getDisplayTextPart(comboBox._comboBox.displayText, 2) verticalAlignment: Text.AlignVCenter } } @@ -52,29 +56,30 @@ StyledComboBox { required property var model required property int index - property string delegateText: model[_comboBox.textRole] - width: _comboBox.width - highlighted: _comboBox.highlightedIndex === index + property string delegateText: model[comboBox._comboBox.textRole] + + width: comboBox._comboBox.width + highlighted: comboBox._comboBox.highlightedIndex === delegate.index contentItem: Column { Text { font.pointSize: 12 - text: getDisplayTextPart(delegateText, 0) + text: comboBox.getDisplayTextPart(delegate.delegateText, 0) verticalAlignment: Text.AlignVCenter } Text { leftPadding: 12 font.pointSize: 10 - text: getDisplayTextPart(delegateText, 1) + text: comboBox.getDisplayTextPart(delegate.delegateText, 1) verticalAlignment: Text.AlignVCenter } Text { leftPadding: 12 font.pointSize: 10 - text: getDisplayTextPart(delegateText, 2) + text: comboBox.getDisplayTextPart(delegate.delegateText, 2) verticalAlignment: Text.AlignVCenter } } diff --git a/src/qml/controls/StyledIconTabButton.qml b/src/qml/controls/StyledIconTabButton.qml index 34b5b5f..d686e23 100644 --- a/src/qml/controls/StyledIconTabButton.qml +++ b/src/qml/controls/StyledIconTabButton.qml @@ -10,17 +10,16 @@ import QtQuick.Controls import QtQuick.Layouts import OPC_UA_Browser -import Types TabButton { id: control readonly property bool isCurrentTab: (TabBar.tabBar.currentIndex == TabBar.index) - && (type !== DashboardType.Add) + && (type !== DashboardItem.DashboardType.Add) property ThemeIconTabButton theme: Style.iconTabButton - property int type: DashboardType.Variables + property int type: DashboardItem.DashboardType.Variables width: 80 @@ -37,7 +36,8 @@ TabButton { Layout.alignment: Qt.AlignCenter sourceSize.width: 40 sourceSize.height: 40 - source: (DashboardType.Add === type) ? "qrc:/icons/plus.svg" : (DashboardType.Events === type) ? "qrc:/icons/event.svg" : "qrc:/icons/dashboard.svg" + source: (DashboardItem.DashboardType.Add === control.type) ? "qrc:/icons/plus.svg" : + (DashboardItem.DashboardType.Events === control.type) ? "qrc:/icons/event.svg" : "qrc:/icons/dashboard.svg" color: label.color } diff --git a/src/qml/style/ThemeBright.qml b/src/qml/style/ThemeBright.qml index 65ab3a7..a790c69 100644 --- a/src/qml/style/ThemeBright.qml +++ b/src/qml/style/ThemeBright.qml @@ -5,8 +5,6 @@ * SPDX-License-Identifier: GPL-3.0-or-later */ -import QtQuick - ThemeDefault { browserView.background: light diff --git a/src/qml/style/ThemeButton.qml b/src/qml/style/ThemeButton.qml index 7dbd350..d32540d 100644 --- a/src/qml/style/ThemeButton.qml +++ b/src/qml/style/ThemeButton.qml @@ -7,7 +7,7 @@ import QtQuick -Item { +StyleDefinitions { property color background: "transparent" property color borderColor: mediumLight property color textColor: mediumLight diff --git a/src/qml/style/ThemeComboBox.qml b/src/qml/style/ThemeComboBox.qml index ec2c309..4aac514 100644 --- a/src/qml/style/ThemeComboBox.qml +++ b/src/qml/style/ThemeComboBox.qml @@ -7,7 +7,7 @@ import QtQuick -Item { +StyleDefinitions { property color background: mediumLight property color captionTextColor: foreground } diff --git a/src/qml/style/ThemeDark.qml b/src/qml/style/ThemeDark.qml index c527b77..f18d898 100644 --- a/src/qml/style/ThemeDark.qml +++ b/src/qml/style/ThemeDark.qml @@ -5,6 +5,4 @@ * SPDX-License-Identifier: GPL-3.0-or-later */ -import QtQuick - ThemeDefault {} diff --git a/src/qml/style/ThemeHeader.qml b/src/qml/style/ThemeHeader.qml index 79997fc..5154cef 100644 --- a/src/qml/style/ThemeHeader.qml +++ b/src/qml/style/ThemeHeader.qml @@ -7,7 +7,7 @@ import QtQuick -Item { +StyleDefinitions { property color background: "transparent" property color iconColor: foreground property color dividerColor: dark diff --git a/src/qml/style/ThemeIconTabButton.qml b/src/qml/style/ThemeIconTabButton.qml index 00a881b..8e5ba27 100644 --- a/src/qml/style/ThemeIconTabButton.qml +++ b/src/qml/style/ThemeIconTabButton.qml @@ -7,7 +7,7 @@ import QtQuick -Item { +StyleDefinitions { property color background: "transparent" property color backgroundSelected: "transparent" property color textColor: foreground diff --git a/src/qml/style/ThemeItemSelector.qml b/src/qml/style/ThemeItemSelector.qml index 9a5f041..4bb0a1c 100644 --- a/src/qml/style/ThemeItemSelector.qml +++ b/src/qml/style/ThemeItemSelector.qml @@ -7,7 +7,7 @@ import QtQuick -Item { +StyleDefinitions { property color background: anthrazite property real backgroundOpacity: 0.8 property color borderColor: accent diff --git a/src/qml/style/ThemeTextField.qml b/src/qml/style/ThemeTextField.qml index 98b31f0..9348942 100644 --- a/src/qml/style/ThemeTextField.qml +++ b/src/qml/style/ThemeTextField.qml @@ -7,7 +7,7 @@ import QtQuick -Item { +StyleDefinitions { property color background: foreground property color captionTextColor: foreground } diff --git a/src/types.h b/src/types.h deleted file mode 100644 index 0a6ca28..0000000 --- a/src/types.h +++ /dev/null @@ -1,23 +0,0 @@ -/** - * SPDX-FileCopyrightText: 2024 basysKom GmbH - * SPDX-FileContributor: Karsten Herrler - * - * SPDX-License-Identifier: GPL-3.0-or-later - */ - -#ifndef TYPES_H -#define TYPES_H - -#include - -namespace Types { - -Q_NAMESPACE -enum class DashboardType { Unknown = -1, Variables, Events, Add }; -Q_ENUM_NS(DashboardType) - -} // namespace Types - -Q_DECLARE_METATYPE(Types::DashboardType) - -#endif // TYPES_H From 017e07f283fa5719896a9fafad7af997f991262b Mon Sep 17 00:00:00 2001 From: Karsten Herrler Date: Mon, 22 Jan 2024 15:28:38 +0100 Subject: [PATCH 3/4] find better workaround for qmllint warning --- src/CMakeLists.txt | 1 + src/backend.cpp | 16 ++++++++-------- src/backend.h | 40 +++++++++++++++------------------------- src/qml/NodesView.qml | 2 +- 4 files changed, 25 insertions(+), 34 deletions(-) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index a7dfc72..e34ce97 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -20,6 +20,7 @@ set_source_files_properties(qml/style/Style.qml PROPERTIES qt_add_qml_module(appOPC_UA_Browser URI OPC_UA_Browser VERSION 1.0 + DEPENDENCIES QtCore QtQuick QML_FILES qml/Main.qml qml/BrowserView.qml qml/ConnectionView.qml diff --git a/src/backend.cpp b/src/backend.cpp index 1466cd6..75299f5 100644 --- a/src/backend.cpp +++ b/src/backend.cpp @@ -38,10 +38,10 @@ BackEnd::BackEnd(QObject *parent) mOpcUaModel(new OpcUaModel(this)), mOpcUaProvider(new QOpcUaProvider(this)), mDashboardItemModel(new DashboardItemModel(this)), - mDefaultVariableDashboardsModel(new QQmlStringListModel(this)), - mDefaultEventDashboardsModel(new QQmlStringListModel(this)), - mSavedVariableDashboardsModel(new QQmlStringListModel(this)), - mSavedEventDashboardsModel(new QQmlStringListModel(this)) + mDefaultVariableDashboardsModel(new QStringListModel(this)), + mDefaultEventDashboardsModel(new QStringListModel(this)), + mSavedVariableDashboardsModel(new QStringListModel(this)), + mSavedEventDashboardsModel(new QStringListModel(this)) { setupPkiConfiguration(); @@ -131,22 +131,22 @@ DashboardItemModel *BackEnd::dashboardItemModel() const noexcept return mDashboardItemModel; } -QQmlStringListModel *BackEnd::defaultVariableDashboards() const noexcept +QStringListModel *BackEnd::defaultVariableDashboards() const noexcept { return mDefaultVariableDashboardsModel; } -QQmlStringListModel *BackEnd::defaultEventDashboards() const noexcept +QStringListModel *BackEnd::defaultEventDashboards() const noexcept { return mDefaultEventDashboardsModel; } -QQmlStringListModel *BackEnd::savedVariableDashboards() const noexcept +QStringListModel *BackEnd::savedVariableDashboards() const noexcept { return mSavedVariableDashboardsModel; } -QQmlStringListModel *BackEnd::savedEventDashboards() const noexcept +QStringListModel *BackEnd::savedEventDashboards() const noexcept { return mSavedEventDashboardsModel; } diff --git a/src/backend.h b/src/backend.h index fffad03..8319721 100644 --- a/src/backend.h +++ b/src/backend.h @@ -22,21 +22,11 @@ class MonitoredItemModel; // Workaround, otherwise qmllint doesn't recognise the QStringListModel -class QQmlStringListModel : public QStringListModel +struct ThisIsAnnoying { - Q_OBJECT + Q_GADGET + QML_FOREIGN(QStringListModel) QML_ANONYMOUS - -public: - explicit QQmlStringListModel(QObject *parent = nullptr) - : QStringListModel(parent){ - - }; - - Q_INVOKABLE int rowCount(const QModelIndex &parent = QModelIndex()) const override - { - return QStringListModel::rowCount(parent); - }; }; class BackEnd : public QObject @@ -56,13 +46,13 @@ class BackEnd : public QObject Q_PROPERTY(OpcUaModel *opcUaModel READ opcUaModel NOTIFY opcUaModelChanged FINAL) Q_PROPERTY(DashboardItemModel *dashboardItemModel READ dashboardItemModel NOTIFY opcUaModelChanged FINAL) - Q_PROPERTY(QQmlStringListModel *defaultVariableDashboards READ defaultVariableDashboards NOTIFY + Q_PROPERTY(QStringListModel *defaultVariableDashboards READ defaultVariableDashboards NOTIFY defaultVariableDashboardsChanged FINAL) - Q_PROPERTY(QQmlStringListModel *defaultEventDashboards READ defaultEventDashboards NOTIFY + Q_PROPERTY(QStringListModel *defaultEventDashboards READ defaultEventDashboards NOTIFY defaultEventDashboardsChanged FINAL) - Q_PROPERTY(QQmlStringListModel *savedVariableDashboards READ savedVariableDashboards NOTIFY + Q_PROPERTY(QStringListModel *savedVariableDashboards READ savedVariableDashboards NOTIFY savedVariableDashboardsChanged FINAL) - Q_PROPERTY(QQmlStringListModel *savedEventDashboards READ savedEventDashboards NOTIFY + Q_PROPERTY(QStringListModel *savedEventDashboards READ savedEventDashboards NOTIFY savedEventDashboardsChanged FINAL) Q_PROPERTY(bool hasLastDashboards READ hasLastDashboards CONSTANT FINAL) @@ -77,10 +67,10 @@ class BackEnd : public QObject QVector endpointList() const; OpcUaModel *opcUaModel() const noexcept; DashboardItemModel *dashboardItemModel() const noexcept; - QQmlStringListModel *defaultVariableDashboards() const noexcept; - QQmlStringListModel *defaultEventDashboards() const noexcept; - QQmlStringListModel *savedVariableDashboards() const noexcept; - QQmlStringListModel *savedEventDashboards() const noexcept; + QStringListModel *defaultVariableDashboards() const noexcept; + QStringListModel *defaultEventDashboards() const noexcept; + QStringListModel *savedVariableDashboards() const noexcept; + QStringListModel *savedEventDashboards() const noexcept; bool hasLastDashboards() const noexcept; Q_INVOKABLE void clearServerList(); @@ -153,10 +143,10 @@ private slots: DashboardItemModel *mDashboardItemModel = nullptr; QVector mLastServerHosts; - QQmlStringListModel *mDefaultVariableDashboardsModel; - QQmlStringListModel *mDefaultEventDashboardsModel; - QQmlStringListModel *mSavedVariableDashboardsModel; - QQmlStringListModel *mSavedEventDashboardsModel; + QStringListModel *mDefaultVariableDashboardsModel; + QStringListModel *mDefaultEventDashboardsModel; + QStringListModel *mSavedVariableDashboardsModel; + QStringListModel *mSavedEventDashboardsModel; bool mHasLastDashboards = false; }; diff --git a/src/qml/NodesView.qml b/src/qml/NodesView.qml index e6c2ab5..2a6b4e2 100644 --- a/src/qml/NodesView.qml +++ b/src/qml/NodesView.qml @@ -22,7 +22,7 @@ Item { property ThemeNodesView theme: Style.nodesView Connections { - target: BackEnd.opcUaModel // qmllint disable incompatible-type + target: BackEnd.opcUaModel function onCurrentIndexChanged(index) { treeView.expandToIndex(index) treeView.forceLayout() From d8b45cf629d9ff5301ea858362687841920ed43e Mon Sep 17 00:00:00 2001 From: Karsten Herrler Date: Mon, 22 Jan 2024 16:09:00 +0100 Subject: [PATCH 4/4] first version of readme --- README.md | 62 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 62 insertions(+) create mode 100644 README.md diff --git a/README.md b/README.md new file mode 100644 index 0000000..56ebc85 --- /dev/null +++ b/README.md @@ -0,0 +1,62 @@ + +# OPC UA Browser + +The OPC UA Browser from basysKom is an OPC UA client with a wide range of application options for OPC UA technology. + +The OPC UA Browser can be used to establish an unencrypted connection to an OPC UA server as well as a connection encrypted via certificates. User authentication via user name and password is also supported. + +The OPC UA Browser can be used to monitor selected nodes in order to obtain a quick overview of important components. Individual nodes can be easily added to and removed from the dashboard. It is possible to create several dashboards at the same time and quickly switch back and forth between them. The dashboards created can be easily saved so that they can be quickly reloaded in a new session. + +The information model of the OPC UA server is displayed as a tree structure using the expert mode. Selecting a node displays its attributes and references. By clicking on a reference, you can quickly jump to the selected reference in the tree structure. + +## Features + +- Connecting to OPC UA Browser (uncrypted and encrypted via certificates, user authentication) +- Monitoring nodes in several dashboards +- Saving dashboards for reuse +- Browser for information model +- Windows, Linux, Android, iOS + +## Getting OPC UA Browser + +### Android + +coming soon in Google Play store + +### iOS + +coming soon in App Store + +## Compatibility +The application has been tested on: + +- Windows using the MinGW 64-Bit compiler and Qt 6.5+ + +- Linux (Ubuntu 22.04 LTS) and Qt 6.5+ + +- Android using clang for arm64-v8a, armeabi-v7a, x86, x86_64 + +- iOS + +## Dependencies + +- Qt 6.5+ +- Qt OPC UA (available at [https://doc.qt.io/qt-6/qtopcua-index.html)) +- OpenSSL >= 3.0 + +## Building + +To be done + +## Contributing + +Contributions are welcome! If you encounter any issues or would like to request a feature, feel free to open an issue or submit a pull request. + +## License + +This project is released under the GPLv3.0-or-later License. \ No newline at end of file