ChimeraTK-ControlSystemAdapter-OPCUAAdapter 04.00.05
Loading...
Searching...
No Matches
generatorForm.py
Go to the documentation of this file.
1from PyQt5.QtWidgets import QFileDialog, QDialog, QMainWindow, QTreeWidgetItem, QCheckBox, QMessageBox, QDialogButtonBox, QComboBox, QHeaderView
2from PyQt5.QtCore import Qt
3from PyQt5.QtGui import QBrush, QColor
4import os
5from ctk_opcua_generator_tools.generatorUI import Ui_MainWindow
6from ctk_opcua_generator_tools.encryptionUI import Ui_EncryptionDialog
7from ctk_opcua_generator_tools.historyUI import Ui_HistoryDialog
8from ctk_opcua_generator_tools.generatorClass import MapGenerator, XMLDirectory, XMLVar, EncryptionSettings, HistorySetting
9import logging
10from typing import Optional, List
11
13 def _getFileDialog(self):
14 dlg = QFileDialog(self)
15 dlg.setFileMode(QFileDialog.ExistingFile)
16 dlg.setViewMode( QFileDialog.Detail )
17 dlg.setNameFilters( [self.tr('Certificate file (*.der)'), self.tr('All Files (*)')] )
18 dlg.setDefaultSuffix('der')
19 return dlg
20
21 def openUserCert(self):
22 dlg = self._getFileDialog()
23 dlg.setWindowTitle('Set application certificate file')
24 # show dialog, save only if user did not cancel
25 if dlg.exec_() :
26 self.settings.certificate = str(dlg.selectedFiles()[0])
27 self.userCert.setText(self.settings.certificate)
28
29 def openPrivateKey(self):
30 dlg = self._getFileDialog()
31 dlg.setWindowTitle('Set appliction private key file')
32 # show dialog, save only if user did not cancel
33 if dlg.exec_() :
34 self.settings.key = str(dlg.selectedFiles()[0])
35 self.privateKey.setText(self.settings.key)
36
37 def _openDirectory(self) -> Optional[str]:
38 dlg = QFileDialog(self)
39 dlg.setFileMode(QFileDialog.Directory)
40 dlg.setOption(QFileDialog.ShowDirsOnly)
41 if dlg.exec() :
42 return str(dlg.selectedFiles()[0])
43 else:
44 return None
45
46 def openTrustList(self):
47 directory = self._openDirectory()
48 if directory:
49 self.settings.trustList = directory
50 self.trustList.setText(directory)
51
52 def openBlockList(self):
53 directory = self._openDirectory()
54 if directory:
55 self.settings.blockList = directory
56 self.blockList.setText(directory)
57
58 def openIssuerList(self):
59 directory = self._openDirectory()
60 if directory:
61 self.settings.issuerList = directory
62 self.issuerList.setText(directory)
63
64
65 def __init__(self, data:EncryptionSettings, parent=None):
66 super(EncryptionDialog, self).__init__(parent)
67 self.setupUi(self)
68
69 self.settings = data
70 if data.certificate:
71 self.userCert.setText(data.certificate)
72 if data.key:
73 self.privateKey.setText(data.key)
74 if data.trustList:
75 self.trustList.setText(data.trustList)
76 if data.blockList:
77 self.blockList.setText(data.blockList)
78 if data.issuerList:
79 self.issuerList.setText(data.issuerList)
80
81 self.setUserCert.clicked.connect(self.openUserCertopenUserCert)
83 self.setBlockList.clicked.connect(self.openBlockListopenBlockList)
84 self.setTrustList.clicked.connect(self.openTrustListopenTrustList)
86
88 def __init__(self, data:QComboBox, histories: List[HistorySetting], edit:bool, parent=None):
89 '''
90 @param data: The setting to be added.
91 @param histories: The list of all settings. Is used to ensure that names are unique!
92 '''
93 super(HistorySettingsDialog,self).__init__(parent)
94 self.setupUi(self)
95 self.data = data.currentData()
96 self.historyName.setText(self.data.name)
97 self.entriesPerResponse.setValue(self.data.entriesPerResponse)
98 self.bufferLength.setValue(self.data.bufferLength)
99 self.samplingInterval.setValue(self.data.interval)
100 self.histories = histories
101 self.edit = edit
102 # Save current text -> if edit is true and the name is changed we need to check again if it already exists
103 self.combo = data
104
105 self.historyName.editingFinished.connect(self.checkNameExistscheckNameExists)
106 self.samplingInterval.valueChanged.connect(self.updateDataupdateData)
107 self.entriesPerResponse.valueChanged.connect(self.updateDataupdateData)
108 self.bufferLength.valueChanged.connect(self.updateDataupdateData)
109
111 # check if is new or name was changed
112 if self.edit == False or self.combo.currentText() != self.historyName.text():
113 found = next((x for x in self.histories if x.name == self.historyName.text()),None)
114 if found != None:
115 self.buttonBox.button( QDialogButtonBox.Ok ).setEnabled( False );
116 else:
117 self.buttonBox.button( QDialogButtonBox.Ok ).setEnabled( True );
118 self.data.name = self.historyName.text()
119 self.combo.setItemText(self.combo.currentIndex(),self.historyName.text())
120
121 def updateData(self):
122 self.data.entriesPerResponse = self.entriesPerResponse.value()
123 self.data.interval = self.samplingInterval.value()
124 self.data.bufferLength = self.bufferLength.value()
125
126class MapGeneratorForm(QMainWindow, Ui_MainWindow):
127 def _createMapGenerator(self, fileName: str|None):
128 try:
129 self.MapGenerator: MapGenerator|None = MapGenerator(fileName)
130 if (fileName):
131 self.statusbar.showMessage(fileName)
132 self._fillTree()
133 except RuntimeError as error:
134 QMessageBox.critical(self, "Map file generator",
135 "Could not parse xml file. Is that a file generated by the XML generator of your application?\n Error: {}".format(error) )
136 self.treeWidgettreeWidget.clear()
137 self.MapGenerator = None
138 except:
139 QMessageBox.critical(self, "Map file generator",
140 "Could not parse xml file. Is that a file generated by the XML generator of your application?" )
141 self.treeWidgettreeWidget.clear()
142 self.MapGenerator = None
143
144 def openFile(self, fromMenu:bool = True):
145 '''
146 Read all information from the given XML file.
147 Data is stored in the MapGenerator object.
148
149 @param fromMenu: If true no user interaction box is shown, because we know the user wants to open a file.
150 '''
151 buttonReply = None
152 if not fromMenu:
153 buttonReply = QMessageBox.question(self, 'PyQt5 message', "You did not specify an input xml file (created with the XMLGenerator of your application).\nIf not you will only be able to set general OPC UA server properties without mapping features.\n Do you want to specify it now?", QMessageBox.Yes | QMessageBox.No, QMessageBox.No)
154 if buttonReply == QMessageBox.Yes or fromMenu:
155 name = QFileDialog.getOpenFileName(self, caption='Set input file', filter="XML files (*.xml)", options=QFileDialog.DontResolveSymlinks)
156 if name[0]:
157 self._createMapGenerator(name[0])
158 else:
159 self._createMapGenerator(None)
160 logging.warning("No xml input file given.")
161
162 def _fillConfig(self):
163 '''
164 Fill config information to the GUI fields.
165 '''
169 self.configureEncryptionButton.setEnabled(self.MapGenerator.encryptionEnabled)
170 self.addUnsecureEndpointaddUnsecureEndpoint.setEnabled(self.MapGenerator.encryptionEnabled)
171 self.userNameuserName.setEnabled(self.MapGenerator.enableLogin)
172 self.passwordpassword.setEnabled(self.MapGenerator.enableLogin)
175 # Attention the following fields are set in the GUI but not set in the mapping file as long as they
176 # are not changed by the user!
177 # Simply show what will be used, because root folder and application name default to the
178 # application name if not set in the mapping file!
182 if self.rootFolderrootFolder == None:
184 else:
185 self._blockAndSetTextBox(self.MapGenerator.rootFolder, self.rootFolderrootFolder)
186 self.logLevelComboBox.blockSignals(True)
187 self.logLevelComboBox.setCurrentText(self.MapGenerator.logLevel)
188 self.logLevelComboBox.blockSignals(False)
189
190 def _fillTree(self):
191 '''
192 Fill the tree by passing the root node read from the XML file.
193 Filling is done recursively.
194 '''
195 self.treeWidgettreeWidget.clear()
196 # block widget while filling in order to avoid calling _updateItem
197 self.treeWidgettreeWidget.blockSignals(True)
199 self.treeWidgettreeWidget.blockSignals(False)
200
201 # resize columns
202 header = self.treeWidgettreeWidget.header()
203 #header.setSectionResizeMode(QHeaderView.ResizeToContents)
204 #header.setStretchLastSection(False)
205 header.setSectionResizeMode(0, QHeaderView.ResizeToContents)
206 header.setSectionResizeMode(1, QHeaderView.ResizeToContents)
207 header.setSectionResizeMode(2, QHeaderView.ResizeToContents)
208 header.setSectionResizeMode(3, QHeaderView.ResizeToContents)
209 header.setSectionResizeMode(4, QHeaderView.Interactive)
210
211 def _getCheckBox(self, item:XMLDirectory | XMLVar, text:str, node:QTreeWidgetItem):
212 '''
213 Create a checkbox.
214
215 @param item: The XML items that corresponds to the checkbox.
216 @param text: The check box label.
217 @param node: The widget item where the checkbox will be added. It is assumed it is a QTreeWidgetItem with multiple columns.
218 '''
219 checkbox = QCheckBox(parent=self.treeWidgettreeWidget, text=text)
220 if item.exclude == True:
221 checkbox.setChecked(True)
222 if isinstance(item, XMLDirectory) == True:
223 checkbox.stateChanged.connect(lambda state: self._mapDirectory(state,item, node))
224 else:
225 checkbox.stateChanged.connect(lambda state: self._mapItem(state,item, node))
226 return checkbox
227
228 def _getComboBox(self, item:XMLDirectory | XMLVar, node:QTreeWidgetItem):
229 '''
230 Create a combo box.
231
232 @param item: The XML items that corresponds to the checkbox.
233 @param node: The widget item where the checkbox will be added. It is assumed it is a QTreeWidgetItem with multiple columns.
234 '''
235 combobox = QComboBox(parent=self.treeWidgettreeWidget)
236 combobox.addItem('No history', None)
237 combobox.currentIndexChanged.connect(lambda histIndex: self._setHistoryItem(histIndex, item, combobox, node))
238 combobox.setSizeAdjustPolicy(QComboBox.AdjustToContents)
239 return combobox
240
241 def _updateItem(self, item:QTreeWidgetItem, index:int):
242 self.treeWidgettreeWidget.blockSignals(True)
243 data = item.data(0, Qt.UserRole)
244 if index == 0:
245 # Name
246 if item.text(index) == data.name:
247 data.newName = None
248 item.setForeground(index,QBrush(QColor("#000000")))
249 else:
250 data.newName = item.text(index)
251 item.setText(index, item.text(index) + " (Orig.: " + data.name + ")")
252 item.setForeground(index,QBrush(QColor("#FF0000")))
253 elif index == 3:
254 # Unit
255 if isinstance(data,XMLVar):
256 if item.text(index) == data.unit:
257 data.newUnit = None
258 item.setForeground(index,QBrush(QColor("#000000")))
259 else:
260 data.newUnit = item.text(index)
261 item.setText(index, item.text(index) + " (Orig.: " + str(data.unit or '') + ")")
262 item.setForeground(index,QBrush(QColor("#FF0000")))
263 else:
264 item.setText(index, '')
265 msg = "Adding unit to a directory does not make sense!"
266 QMessageBox.warning(self, "Map file generator", msg )
267 elif index == 4:
268 # Description
269 if item.text(index) == "":
270 data.newDescription = None
271 item.setForeground(index,QBrush(QColor("#000000")))
272 else:
273 data.newDescription = item.text(index)
274 item.setText(index, item.text(index) + " (Added descr.)")
275 item.setForeground(index,QBrush(QColor("#FF0000")))
276 elif index == 5:
277 # additional Location
278 if item.text(index) == "":
279 data.newDestination = None
280 item.setForeground(index,QBrush(QColor("#000000")))
281 else:
282 data.newDestination = item.text(index)
283 item.setText(5,data.newDestination)
284 item.setForeground(5,QBrush(QColor("#FF0000")))
285 self.treeWidgettreeWidget.blockSignals(False)
286
287 def _setupRow(self, item:QTreeWidgetItem, data: XMLDirectory|XMLVar):
288 item.setData(0, Qt.UserRole, data)
289 self.treeWidgettreeWidget.setItemWidget(item, 1, self._getCheckBox(data, "exclude", item))
290 self.treeWidgettreeWidget.setItemWidget(item, 2, self._getComboBox(data, item))
291 if isinstance(data, XMLDirectory):
292 item.setFlags(Qt.ItemIsEditable | Qt.ItemIsEnabled | Qt.ItemIsDragEnabled | Qt.ItemIsSelectable | Qt.ItemIsDropEnabled)
293 else:
294 item.setFlags(Qt.ItemIsEditable | Qt.ItemIsEnabled | Qt.ItemIsDragEnabled | Qt.ItemIsSelectable)
295
296 def _setState(self, state:int, item: XMLDirectory|XMLVar):
297 '''
298 Set data in XMLDirectory or XMLVar.
299 This is used to enable mapping.
300 '''
301 if state == Qt.Checked:
302 item.exclude = True
303 logging.debug("Excluding item {}.".format(item.name))
304 else:
305 item.exclude = False
306 logging.debug("Including item {}.".format(item.name))
307
308 def _createVariableNode(self, parent:QTreeWidgetItem, v:XMLVar) -> QTreeWidgetItem:
309 '''
310 Create variable entry in the tree.
311 Reads description and unit.
312 Add CheckBox to enable/disable mapping of that variable.
313 '''
314 name = v.name
315 if v.newName != None:
316 name = "{} (Orig.: {})".format(v.newName, v.name)
317 description = v.description
318 if v.newDescription != None:
319 description = "{} (Orig.: {})".format(v.newDescription, v.description)
320 unit = v.unit
321 if v.newUnit != None:
322 unit = "{} (Orig.: {})".format(v.newUnit, v.unit)
323 node = QTreeWidgetItem(parent, [name]+[""]*2 + [unit] + [description]+[v.newDestination])
324
325 if 'control_system_to_application' in v.direction:
326 node.setBackground(0,QBrush(QColor("#fee8c8")))
327 else:
328 node.setBackground(0,QBrush(QColor("#e5f5e0")))
329
330 if v.newName != None:
331 node.setForeground(0,QBrush(QColor("#FF0000")))
332 if v.newUnit != None:
333 node.setForeground(3,QBrush(QColor("#FF0000")))
334 if v.newDescription != None:
335 node.setForeground(4,QBrush(QColor("#FF0000")))
336 if v.newDestination != None:
337 node.setForeground(5,QBrush(QColor("#FF0000")))
338 self._setupRow(node, v)
339 return node
340
341 def _createDirectoryNode(self, parent:QTreeWidgetItem, directory:XMLDirectory, isRootNode:bool = False) -> QTreeWidgetItem:
342 '''
343 Create a directory entry in the Tree.
344 This will recursively add sub directories and variables in the directories.
345 '''
346 name = directory.name
347 if directory.newName != None:
348 name = "{} (Orig.: {})".format(directory.newName, directory.name)
349 description = ''
350 if directory.newDescription != None:
351 description = "{} (Added descr.)".format(directory.newDescription)
352 mainNode = QTreeWidgetItem(parent, [name] + [""]*3 + [description] + [directory.newDestination or ''])
353 if directory.newName != None:
354 mainNode.setForeground(0,QBrush(QColor("#FF0000")))
355 if directory.newDescription != None:
356 mainNode.setForeground(4,QBrush(QColor("#FF0000")))
357 if directory.newDestination != None:
358 mainNode.setForeground(5,QBrush(QColor("#FF0000")))
359
360 self._setupRow(mainNode, directory)
361 if isRootNode == True:
362 mainNode.setExpanded(True)
363 for d in directory.dirs:
364 self._createDirectoryNode(mainNode, d)
365 for v in directory.vars:
366 self._createVariableNode(mainNode, v)
367 return mainNode
368
369 def _mapItem(self, state:int, var:XMLVar, node:QTreeWidgetItem):
370 '''
371 Called when a variable is to be mapped.
372 The corresponding check box is edited.
373 '''
374 self._setState(state, var)
375 logging.debug("Childs: {}".format(node.childCount()))
376
377 def _mapDirectory(self, state:int, directory:XMLDirectory, node:QTreeWidgetItem):
378 '''
379 Called when a directory is to be mapped.
380 The corresponding check box is edited.
381 This will change the map status of all variables in the directory.
382 '''
383 logging.debug("Mapping directory.")
384 for chId in range(node.childCount()):
385 ch = node.child(chId)
386 self.treeWidgettreeWidget.itemWidget(ch, 1).setCheckState(state)
387 self._setState(state, directory)
388
389 def _setHistoryItem(self, histIndex:int, var:XMLVar|XMLDirectory, combo:QComboBox, node:QTreeWidgetItem):
390 '''
391 Called when historizing setting is choosen.
392 @param histIndex: The index of the history setting.
393 '''
394 if combo.itemText(histIndex) != 'No history':
395 var.historizing = combo.itemText(histIndex)
396 else:
397 var.historizing = None
398
399 if isinstance(var, XMLDirectory):
400 for chId in range(node.childCount()):
401 ch = node.child(chId)
402 self.treeWidgettreeWidget.itemWidget(ch, 2).setCurrentText(combo.itemText(histIndex))
403 if var.historizing:
404 self.treeWidgettreeWidget.itemWidget(ch, 2).setEnabled(False)
405 else:
406 self.treeWidgettreeWidget.itemWidget(ch, 2).setEnabled(True)
407
408 def closeEvent(self, event):
409 msg = "Are you sure you want to close the editor?"
410 reply = QMessageBox.question(self, 'ChimeraTK Logical Name Mapping editor', msg, QMessageBox.Yes, QMessageBox.No)
411 if reply != QMessageBox.Yes:
412 event.ignore()
413 else:
414 event.accept()
415
416 def saveFile(self):
417 '''
418 Save file. If file not yet set open dialog with saveFileAs()
419 '''
420 try:
421 if self.MapGenerator.outputFile == None:
423 else:
424 self.MapGenerator.save()
425 except RuntimeError as error:
426 msg = "The following error was reported: " + str(error)
427 QMessageBox.critical(self, "Map file generator", msg )
428
429 def saveFileAs(self):
430 # create file-save dialog
431 dlg = QFileDialog(self, directory=self.MapGenerator.applicationName + "_mapping.xml")
432 dlg.setAcceptMode(QFileDialog.AcceptSave)
433 dlg.setWindowTitle('Save XML mapping file')
434 dlg.setViewMode( QFileDialog.Detail )
435 dlg.setNameFilters( [self.tr('XML Mapping Files (*.xml)'), self.tr('All Files (*)')] )
436 dlg.setDefaultSuffix('xml')
437 if self.MapGenerator.outputFile != None:
438 dlg.setDirectory( os.path.dirname(self.MapGenerator.outputFile) )
439
440 # show dialog, save only if user did not cancel
441 if dlg.exec_() :
442 # file name must be converted into standard python string
443 self.MapGenerator.outputFile = str(dlg.selectedFiles()[0])
444 # save the file
445 self.saveFilesaveFile()
446 self.actionSave.setEnabled(True)
447
448 def enableLogin(self, state):
449 if state == Qt.Checked:
450 self.userNameuserName.setEnabled(True)
451 self.passwordpassword.setEnabled(True)
452 self.MapGenerator.enableLogin = True
453 else:
454 self.userNameuserName.setEnabled(False)
455 self.passwordpassword.setEnabled(False)
456 self.MapGenerator.enableLogin = False
457
458 def updateConfig(self):
459 self.MapGenerator.username = self.userNameuserName.text()
460 self.MapGenerator.password = self.passwordpassword.text()
461 self.MapGenerator.applicationName = self.applicationNameapplicationName.text()
462 self.MapGenerator.rootFolder = self.rootFolderrootFolder.text()
463 self.MapGenerator.applicationDescription = self.applicationDescriptionapplicationDescription.text()
464 self.MapGenerator.port = self.portport.value()
465 self.MapGenerator.logLevel = self.logLevelComboBox.currentText()
466
467
468 def dropEvent(self, event):
469 # get item where to drop
470 item = self.treeWidgettreeWidget.itemAt(event.pos())
471 if isinstance(item.data(0,Qt.UserRole), XMLVar):
472 msg = "Variables or directories can only be moved to other directories."
473 QMessageBox.critical(self, "Map file generator", msg )
474 return
475 # get item that is dropped
476 current = self.treeWidgettreeWidget.currentItem()
477 # get data that is dropped
478 currentData = current.data(0,Qt.UserRole)
479 currentData.newDestination = item.data(0,Qt.UserRole).path
480 current.setText(5,currentData.newDestination)
481 current.setForeground(5,QBrush(QColor("#FF0000")))
482 # create new item in the dropped place
483 # self._createVariableNode(item, currentData)
484 # remove original item -> leave original PV/directory
485 # parent = current.parent()
486 # parent.removeChild(current)
487
488 def dragEnterEvent(self, e)->None:
489 e.accept()
490
492 dlg = EncryptionDialog(parent=self, data=self.MapGenerator)
493 dlg.exec()
494
496 states = [self.enableEncryptionButtonenableEncryptionButton.isChecked(),
498 self.addUnsecureEndpointaddUnsecureEndpoint.setEnabled(states[0])
499 self.configureEncryptionButton.setEnabled(states[0])
500 self.MapGenerator.encryptionEnabled = states[0]
501 self.MapGenerator.addUnsecureEndpoint = states[1]
502
504 histName = 'historySetting'
505 if self.histories.findText(histName) != -1:
506 i = 0
507 histName = 'historySetting_{}'.format(i)
508 while(self.histories.findText(histName) != -1):
509 histName = 'historySetting_{}'.format(i)
510 i = i+1
511 setting = HistorySetting(name=histName)
512 # add item to the historizing combo box
513 self.histories.addItem(setting.name, setting)
514 self.histories.setCurrentText(setting.name)
515 dlg = HistorySettingsDialog(parent=self, data=self.histories, histories=self.MapGenerator.historySettings, edit=False)
516 dlg.exec()
517 self.addHistorySetting(setting)
518
519 def addHistorySetting(self, setting: HistorySetting, updateMapGenerator: bool = True):
520 '''
521 @param setting: The Setting to add.
522 @param updateMapGenerator: If False the setting is not added to the mapGenerator list.
523 This option is used when an existing map file was read and here
524 only the combo box should be updated.
525 '''
526 logging.info("Adding historizing setting with name: {}".format(setting.name))
527 # add HistorySetting to the settings of the MapGenerator
528 if updateMapGenerator:
529 self.MapGenerator.historySettings.append(setting)
530 # add history settings to the combo boxes in the TreeWidget (recursively)
531 self.addComboEntry(self.treeWidgettreeWidget.itemAt(0,0), setting)
532 header = self.treeWidgettreeWidget.header()
533 # resize the history column accoding to the new historizing setting name, size of 200 is ignored size
534 # the size is set to the combobox size using ResizeToContents-> see fillTree()
535 header.resizeSection(2,200)
536 self.editHistorySettingButton.setEnabled(True)
537 self.setHistoryForInputsButton.setEnabled(True)
538
539 def addComboEntry(self, item:QTreeWidgetItem, setting:HistorySetting):
540 self.treeWidgettreeWidget.itemWidget(item, 2).addItem(setting.name, setting)
541 for chId in range(item.childCount()):
542 self.addComboEntry(item.child(chId), setting)
543
545 dlg = HistorySettingsDialog(parent=self, data=self.histories,histories=self.MapGenerator.historySettings, edit=True)
546 dlg.exec()
547
548 def updateHistories(self, item:QTreeWidgetItem):
549 '''
550 After reading an existing map file the tree needs to be updated.
551 The information which history to use is already in the Item data.
552 '''
553 data = item.data(0, Qt.UserRole)
554 if isinstance(data, XMLVar):
555 if data.historizing != None:
556 self.treeWidgettreeWidget.itemWidget(item, 2).setCurrentText(data.historizing)
557 elif isinstance(data, XMLDirectory):
558 if data.historizing != None:
559 # if the directory has history set the history -> child will be set automatically by _setHistoryItem
560 self.treeWidgettreeWidget.itemWidget(item, 2).setCurrentText(data.historizing)
561 else:
562 # Check childs for history settings
563 for chId in range(item.childCount()):
564 self.updateHistories(item.child(chId))
565
566 def addHistoryForInputs(self, isChecked:bool, node:QTreeWidgetItem):
567 data = node.data(0, Qt.UserRole)
568 if isinstance(data, XMLVar) and ('control_system_to_application' in data.direction):
569 if isChecked:
570 self.treeWidgettreeWidget.itemWidget(node, 2).setCurrentText(self.histories.currentText())
571 else:
572 self.treeWidgettreeWidget.itemWidget(node, 2).setCurrentText('No history')
573
574 else:
575 for chId in range(node.childCount()):
576 self.addHistoryForInputs(isChecked,node.child(chId))
577
578 def _blockAndSetTextBox(self, value: str, control):
579 '''
580 Set a text box without updating the configuration,
581 which would override parameters of the MapGenerator.
582 '''
583 control.blockSignals(True)
584 if value != None:
585 control.setText(value)
586 control.blockSignals(False)
587
588 def _bockAndSetValue(self, value: int, control):
589 '''
590 Set value of spinbox.
591 '''
592 control.blockSignals(True)
593 if value != None:
594 control.setValue(value)
595 control.blockSignals(False)
596
597 def _blockAndSetCheckbox(self, value: bool, control):
598 '''
599 Set a check box without updating the configuration,
600 which would override parameters of the MapGenerator.
601 '''
602 control.blockSignals(True)
603 if value == True:
604 control.setChecked(True)
605 else:
606 control.setChecked(False)
607 control.blockSignals(False)
608
609 def loadMapFile(self):
610 if self.MapGenerator == None:
611 msg = "You have to open a xml file first."
612 QMessageBox.critical(self, "Map file generator", msg )
613 else:
614 name = QFileDialog.getOpenFileName(self, caption='Load existing mapping file', filter="XML files (*.xml)", options=QFileDialog.DontResolveSymlinks)
615 if name[0]:
616 try:
617 missed = self.MapGenerator.parseMapFile(name[0])
618 if missed[0] != 0 or missed[1] != 0 or missed[2] != 0:
619 QMessageBox.warning(self, "Map file generator",
620 "{} directories, {} PV and {} exclude paths could not be found by their source name in the original variable tree.\n Probably"
621 " the mapping file does not correspong to the application XML file or the application was changed in the mean time.".format(missed[0], missed[1], missed[2]))
622 self._fillConfig()
623 if self.MapGenerator.dir == None:
624 return
625 # update the tree
626 self._fillTree()
627 # update historizing settings
628 for setting in self.MapGenerator.historySettings:
629 if self.histories.findText(setting.name) == -1:
630 self.histories.addItem(setting.name,setting)
631 self.addHistorySetting(setting=setting, updateMapGenerator=False)
632 else:
633 logging.warning("Setting with name {} already exist. Not loading parameters from mapping file.".format(setting.name))
634 # loop over tree and apply history settings
635 self.updateHistories(self.treeWidgettreeWidget.itemAt(0,0))
636
637 except RuntimeError as error:
638 QMessageBox.critical(self, "Map file generator",
639 "Failed to load map file: {}\n Error: {}".format(name[0], error) )
640
641 def __init__(self, args, parent=None):
642 super(MapGeneratorForm, self).__init__(parent)
643 self.setupUi(self)
644
645
646 self.MapGenerator = None
647 if args.input:
648 self._createMapGenerator(args.input)
649 elif args.noinput:
650 self.MapGenerator: MapGenerator|None = MapGenerator(None)
651 else:
652 self.openFile(fromMenu=False)
653
654 self.histories.setSizeAdjustPolicy(QComboBox.AdjustToContents)
655
656 self.treeWidgettreeWidget.itemChanged.connect(self._updateItem_updateItem)
657
658 self.actionOpen_File.triggered.connect(lambda: self.openFile(fromMenu=True))
659 self.actionSave_as.triggered.connect(self.saveFileAssaveFileAs)
660 self.actionSave.triggered.connect(self.saveFilesaveFile)
662 self.actionQuit.triggered.connect(self.close)
663
665 self.passwordpassword.textChanged.connect(self.updateConfigupdateConfig)
666 self.userNameuserName.textChanged.connect(self.updateConfigupdateConfig)
667 self.applicationNameapplicationName.textChanged.connect(self.updateConfigupdateConfig)
668 self.rootFolderrootFolder.textChanged.connect(self.updateConfigupdateConfig)
669 self.portport.valueChanged.connect(self.updateConfigupdateConfig)
671 self.logLevelComboBox.currentTextChanged.connect(self.updateConfigupdateConfig)
677 self.setHistoryForInputsButton.clicked.connect(lambda isChecked: self.addHistoryForInputs(isChecked, self.treeWidgettreeWidget.itemAt(0,0)))
678
679
680 # Allow to move items
681 self.treeWidgettreeWidget.dropEvent = self.dropEvent
682 self.treeWidgettreeWidget.dragEnterEvent = self.dragEnterEvent
__init__(self, EncryptionSettings data, parent=None)
__init__(self, QComboBox data, List[HistorySetting] histories, bool edit, parent=None)
addComboEntry(self, QTreeWidgetItem item, HistorySetting setting)
QTreeWidgetItem _createVariableNode(self, QTreeWidgetItem parent, XMLVar v)
_mapItem(self, int state, XMLVar var, QTreeWidgetItem node)
_updateItem(self, QTreeWidgetItem item, int index)
addHistorySetting(self, HistorySetting setting, bool updateMapGenerator=True)
_getComboBox(self, XMLDirectory|XMLVar item, QTreeWidgetItem node)
addHistoryForInputs(self, bool isChecked, QTreeWidgetItem node)
_getCheckBox(self, XMLDirectory|XMLVar item, str text, QTreeWidgetItem node)
_setState(self, int state, XMLDirectory|XMLVar item)
_setHistoryItem(self, int histIndex, XMLVar|XMLDirectory var, QComboBox combo, QTreeWidgetItem node)
QTreeWidgetItem _createDirectoryNode(self, QTreeWidgetItem parent, XMLDirectory directory, bool isRootNode=False)
_setupRow(self, QTreeWidgetItem item, XMLDirectory|XMLVar data)
_mapDirectory(self, int state, XMLDirectory directory, QTreeWidgetItem node)
#define str(a)