NewUaObjectDialog   A
last analyzed

Complexity

Total Complexity 3

Size/Duplication

Total Lines 14
Duplicated Lines 0 %

Importance

Changes 4
Bugs 1 Features 1
Metric Value
c 4
b 1
f 1
dl 0
loc 14
rs 10
wmc 3

2 Methods

Rating   Name   Duplication   Size   Complexity  
A __init__() 0 8 2
A get_args() 0 4 1
1
from PyQt5.QtCore import QSettings, Qt
2
from PyQt5.QtWidgets import QPushButton, QComboBox, QLabel, QLineEdit, QHBoxLayout, QDialog, QDialogButtonBox, QVBoxLayout, QCheckBox, QFrame
3
4
from opcua import ua, Node
5
from opcua.common.ua_utils import string_to_variant
6
from opcua.common.ua_utils import data_type_to_variant_type
7
8
from uawidgets.get_node_dialog import GetNodeButton
9
10
11
class NewNodeBaseDialog(QDialog):
12
    def __init__(self, parent, title, server):
13
        QDialog.__init__(self, parent)
14
        self.setWindowTitle(title)
15
        self.settings = QSettings()
16
        self.server = server
17
18
        self.vlayout = QVBoxLayout(self)
19
        self.layout = QHBoxLayout()
20
        self.vlayout.addLayout(self.layout)
21
22
        self.layout.addWidget(QLabel("ns:", self))
23
24
        self.nsComboBox = QComboBox(self)
25
        uries = server.get_namespace_array()
26
        for uri in uries:
27
            self.nsComboBox.addItem(uri)
28
        nsidx = int(self.settings.value("last_namespace", len(uries) - 1))
29
        if nsidx > len(uries) - 1:
30
            nsidx = len(uries) - 1
31
        self.nsComboBox.setCurrentIndex(nsidx)
32
        self.layout.addWidget(self.nsComboBox)
33
34
        self.layout.addWidget(QLabel("Name:", self))
35
        self.nameLabel = QLineEdit(self)
36
        self.nameLabel.setMinimumWidth(120)
37
        self.nameLabel.setText("NoName")
38
        self.layout.addWidget(self.nameLabel)
39
        self.nodeidCheckBox = QCheckBox("Auto NodeId", self)
40
        self.nodeidCheckBox.stateChanged.connect(self._show_nodeid)
41
        self.layout.addWidget(self.nodeidCheckBox)
42
        self.nodeidLineEdit = QLineEdit(self)
43
        self.nodeidLineEdit.setMinimumWidth(80)
44
        self.nodeidLineEdit.setText(self.settings.value("last_nodeid_prefix", "ns={};i=20000".format(nsidx)))
45
        self.layout.addWidget(self.nodeidLineEdit)
46
47
        # restore check box state from settings
48
        if self.settings.value("last_node_widget_vis", False) == "true":
49
            self.nodeidCheckBox.setChecked(False)
50
            self.nodeidLineEdit.show()
51
        else:
52
            self.nodeidCheckBox.setChecked(True)
53
            self.nodeidLineEdit.hide()
54
55
        self.buttons = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel, Qt.Horizontal, self)
56
        self.vlayout.addWidget(self.buttons)
57
58
        self.buttons.accepted.connect(self.accept)
59
        self.buttons.accepted.connect(self._store_state)
60
        self.buttons.rejected.connect(self.reject)
61
62
    def _store_state(self):
63
        self.settings.setValue("last_namespace", self.nsComboBox.currentIndex())
64
        self.settings.setValue("last_node_widget_vis", not self.nodeidCheckBox.isChecked())
65
        ns_nt = self.nodeidLineEdit.text().split(';')
66
        self.settings.setValue("last_nodeid_prefix", ns_nt[0] + ';' + ns_nt[1][0:2])
67
68
    def _show_nodeid(self, val):
69
        if val:
70
            self.nodeidLineEdit.hide()
71
        else:
72
            self.nodeidLineEdit.show()
73
        self.adjustSize()
74
75
    def get_nodeid_and_bname(self):
76
        ns = self.nsComboBox.currentIndex()
77
        name = self.nameLabel.text()
78
        bname = ua.QualifiedName(name, ns)
79
        if self.nodeidCheckBox.isChecked():
80
            nodeid = ua.NodeId(namespaceidx=ns)
81
        else:
82
            nodeid = ua.NodeId.from_string(self.nodeidLineEdit.text())
83
        return nodeid, bname
84
85
    def get_args(self):
86
        nodeid, bname = self.get_nodeid_and_bname()
87
        return nodeid, bname
88
89
    @classmethod
90
    def getArgs(cls, parent, title, server, *args, **kwargs):
91
        dialog = cls(parent, title, server, *args, **kwargs)
92
        result = dialog.exec_()
93
        if result == QDialog.Accepted:
94
            return dialog.get_args(), True
95
        else:
96
            return [], False
97
98
99
class NewUaObjectDialog(NewNodeBaseDialog):
100
    def __init__(self, parent, title, server, base_node_type, current_node_type=None):
101
        NewNodeBaseDialog.__init__(self, parent, title, server)
102
103
        if current_node_type is None:
104
            current_node_type = base_node_type
105
106
        self.objectTypeButton = GetNodeButton(self, current_node_type, base_node_type)
107
        self.layout.addWidget(self.objectTypeButton)
108
109
    def get_args(self):
110
        nodeid, bname = self.get_nodeid_and_bname()
111
        otype = self.objectTypeButton.get_node()
112
        return nodeid, bname, otype
113
114
115
class NewUaVariableDialog(NewNodeBaseDialog):
116
    def __init__(self, parent, title, server, default_value, dtype):
117
        NewNodeBaseDialog.__init__(self, parent, title, server)
118
119
        self.valLineEdit = QLineEdit(self)
120
        self.valLineEdit.setText(str(default_value))
121
        self.valLineEdit.setMinimumWidth(100)
122
        self.layout.addWidget(self.valLineEdit)
123
124
        base_data_type = server.get_node(ua.ObjectIds.BaseDataType)
125
        if dtype is None:
126
            current_type = server.get_node(ua.ObjectIds.Float)
127
        else:
128
            current_type = server.get_node(dtype)
129
        self.dataTypeButton = GetNodeButton(self, current_type, base_data_type)
130
        self.dataTypeButton.value_changed.connect(self._data_type_changed)
131
        self.layout.addWidget(self.dataTypeButton)
132
        self._data_type_changed(self.dataTypeButton.get_node())
133
134
    def _data_type_changed(self, node):
135
        if node.nodeid in (
136
                ua.NodeId(ua.ObjectIds.Decimal),
137
                ua.NodeId(ua.ObjectIds.Float),
138
                ua.NodeId(ua.ObjectIds.Double)):
139
            self.valLineEdit.setText(str(0.0))
140
            self.valLineEdit.setEnabled(True)
141
        elif node.nodeid in (
142
                ua.NodeId(ua.ObjectIds.UInt16),
143
                ua.NodeId(ua.ObjectIds.UInt32),
144
                ua.NodeId(ua.ObjectIds.UInt64),
145
                ua.NodeId(ua.ObjectIds.Int16),
146
                ua.NodeId(ua.ObjectIds.Int32),
147
                ua.NodeId(ua.ObjectIds.Int64)):
148
            self.valLineEdit.setText(str(0))
149
            self.valLineEdit.setEnabled(True)
150
        elif node.nodeid in (
151
                ua.NodeId(ua.ObjectIds.Structure),
152
                ua.NodeId(ua.ObjectIds.Enumeration),
153
                ua.NodeId(ua.ObjectIds.DiagnosticInfo)):
154
            self.valLineEdit.setText("Null")
155
            self.valLineEdit.setEnabled(False)
156
        else:
157
            self.valLineEdit.setText("Null")
158
            self.valLineEdit.setEnabled(True)
159
160
    def get_args(self):
161
        nodeid, bname = self.get_nodeid_and_bname()
162
        dtype = self.dataTypeButton.get_node()
163
        vtype = data_type_to_variant_type(dtype)
164
        if vtype == ua.VariantType.ExtensionObject:
165
            # we currently cannot construct a complex object from a string
166
            var = ua.Variant()
167
        else:
168
            var = string_to_variant(self.valLineEdit.text(), vtype)
169
        return nodeid, bname, var, vtype, dtype.nodeid
170
171
172
class NewUaMethodDialog(NewNodeBaseDialog):
173
    def __init__(self, parent, title, server):
174
        NewNodeBaseDialog.__init__(self, parent, title, server)
175
        # FIXME current temporary UI is fixed; should be changed to listview or treeview object
176
177
        self.widgets = []
178
179
        self.inplayout = QVBoxLayout(self)
180
        self.vlayout.addLayout(self.inplayout)
181
        self.inplayout.addLayout(self.add_input_header())
182
183
        self.ouplayout = QVBoxLayout(self)
184
        self.vlayout.addLayout(self.ouplayout)
185
        self.ouplayout.addLayout(self.add_output_header())
186
187
    def get_args(self):
188
        nodeid, bname = self.get_nodeid_and_bname()
189
190
        input_args = []
191
        output_args = []
192
193
        for row in self.widgets:
194
            dtype = row[3].get_node()
195
            name = row[1].text()
196
            description = row[2].text()
197
198
            if name != "":
199
                # FIXME arguments need to be created from dynamaic UA
200
                method_arg = ua.Argument()
201
                method_arg.Name = name
202
                method_arg.DataType = dtype.nodeid
203
                method_arg.ValueRank = -1
204
                method_arg.ArrayDimensions = []
205
                method_arg.Description = ua.LocalizedText(description)
206
207
                if row[0] == 'input':
208
                    input_args.append(method_arg)
209
                else:
210
                    output_args.append(method_arg)
211
212
        # callback is None, this cannot be set from modeler
213
        return nodeid, bname, None, input_args, output_args
214
215
    def add_row(self, mode):
216
        rowlayout = QHBoxLayout(self)
217
218
        rowlayout.addWidget(QLabel("Arg Name:", self))
219
        argNameLabel = QLineEdit(self)
220
        argNameLabel.setText("")
221
        rowlayout.addWidget(argNameLabel)
222
223
        rowlayout.addWidget(QLabel("Description:", self))
224
        argDescLabel = QLineEdit(self)
225
        argDescLabel.setText("")
226
        rowlayout.addWidget(argDescLabel)
227
228
        base_data_type = self.server.get_node(ua.ObjectIds.BaseDataType)
229
        dtype_str = self.settings.value("last_datatype", None)
230
        if dtype_str is None:
231
            current_type = self.server.get_node(ua.ObjectIds.Float)
232
        else:
233
            current_type = self.server.get_node(dtype_str)
234
        dataTypeButton = GetNodeButton(self, current_type, base_data_type)
235
        rowlayout.addWidget(dataTypeButton)
236
237
        self.widgets.append([mode, argNameLabel, argDescLabel, dataTypeButton])
238
        return rowlayout
239
240
    def _add_input_row(self):
241
        self.inplayout.addLayout(self.add_row("input"))
242
243
    def _add_output_row(self):
244
        self.ouplayout.addLayout(self.add_row("output"))
245
246
    def add_input_header(self):
247
        header_row = QHBoxLayout(self)
248
        header_row.addWidget(QLabel("Input", self))
249
        #header_row.addWidget(self.add_h_line())
250
        button = QPushButton("Add input argument")
251
        button.clicked.connect(self._add_input_row)
252
        header_row.addWidget(button)
253
        return header_row
254
255
    def add_output_header(self):
256
        header_row = QHBoxLayout(self)
257
        header_row.addWidget(QLabel("Output", self))
258
        #header_row.addWidget(self.add_h_line())
259
        button = QPushButton("Add output argument")
260
        header_row.addWidget(button)
261
        button.clicked.connect(self._add_output_row)
262
        return header_row
263
264
265
    def add_h_line(self):
266
        line = QFrame()
267
        line.setFrameShape(QFrame.HLine)
268
        line.setFrameShadow(QFrame.Sunken)
269
        return line
270