MqttMonitor/MqttConnectionProfilesDialog.py

branch
eric7
changeset 103
5fe4f179975f
parent 97
21f9c010dc42
child 104
9a4c9b7f078c
equal deleted inserted replaced
102:70b8858199f5 103:5fe4f179975f
6 """ 6 """
7 Module implementing a dialog to edit the MQTT connection profiles. 7 Module implementing a dialog to edit the MQTT connection profiles.
8 """ 8 """
9 9
10 import collections 10 import collections
11 import copy
11 12
12 from PyQt6.QtCore import pyqtSlot, Qt, QUuid 13 from PyQt6.QtCore import pyqtSlot, Qt, QUuid
13 from PyQt6.QtWidgets import ( 14 from PyQt6.QtWidgets import (
14 QDialog, QDialogButtonBox, QAbstractButton, QListWidgetItem, QInputDialog, 15 QDialog, QDialogButtonBox, QAbstractButton, QListWidgetItem, QInputDialog,
15 QLineEdit 16 QLineEdit
37 @param profiles dictionary containing dictionaries containing the 38 @param profiles dictionary containing dictionaries containing the
38 connection parameters. Each entry must have the keys 39 connection parameters. Each entry must have the keys
39 "BrokerAddress", "BrokerPort", "ClientId", "Protocol", 40 "BrokerAddress", "BrokerPort", "ClientId", "Protocol",
40 "ConnectionTimeout", "Keepalive", "CleanSession", "Username", 41 "ConnectionTimeout", "Keepalive", "CleanSession", "Username",
41 "Password", "WillTopic", "WillMessage", "WillQos", "WillRetain", 42 "Password", "WillTopic", "WillMessage", "WillQos", "WillRetain",
42 "TlsEnable", "TlsCaCert", "TlsClientCert", "TlsClientKey". 43 "TlsEnable", "TlsCaCert", "TlsClientCert", "TlsClientKey",
44 "UserProperties".
43 @type dict 45 @type dict
44 @param parent reference to the parent widget 46 @param parent reference to the parent widget
45 @type QWidget 47 @type QWidget
46 """ 48 """
47 super().__init__(parent) 49 super().__init__(parent)
71 EricPathPickerModes.OPEN_FILE_MODE) 73 EricPathPickerModes.OPEN_FILE_MODE)
72 self.tlsSelfSignedClientKeyFilePicker.setFilters( 74 self.tlsSelfSignedClientKeyFilePicker.setFilters(
73 self.tr("Key Files (*.key *.pem);;All Files (*)")) 75 self.tr("Key Files (*.key *.pem);;All Files (*)"))
74 76
75 self.profileTabWidget.setCurrentIndex(0) 77 self.profileTabWidget.setCurrentIndex(0)
78
79 self.connectPropertiesButton.clicked[bool].connect(
80 self.__propertiesTypeSelected)
81 self.disconnectPropertiesButton.clicked[bool].connect(
82 self.__propertiesTypeSelected)
76 83
77 if len(self.__profiles) == 0: 84 if len(self.__profiles) == 0:
78 self.minusButton.setEnabled(False) 85 self.minusButton.setEnabled(False)
79 self.copyButton.setEnabled(False) 86 self.copyButton.setEnabled(False)
80 87
234 def getProfiles(self): 241 def getProfiles(self):
235 """ 242 """
236 Public method to return a dictionary of profiles. 243 Public method to return a dictionary of profiles.
237 244
238 @return dictionary containing dictionaries containing the defined 245 @return dictionary containing dictionaries containing the defined
239 connection profiles. Each entry have the keys "BrokerAddress", 246 connection profiles. Each entry has the keys "BrokerAddress",
240 "BrokerPort", "ClientId", "Protocol", "ConnectionTimeout", 247 "BrokerPort", "ClientId", "Protocol", "ConnectionTimeout",
241 "Keepalive", "CleanSession", "Username", "Password", "WillTopic", 248 "Keepalive", "CleanSession", "Username", "Password", "WillTopic",
242 "WillMessage", "WillQos", "WillRetain", "TlsEnable", "TlsCaCert", 249 "WillMessage", "WillQos", "WillRetain", "TlsEnable", "TlsCaCert",
243 "TlsClientCert", "TlsClientKey". 250 "TlsClientCert", "TlsClientKey", "UserProperties".
244 @rtype dict 251 @rtype dict
245 """ 252 """
246 profilesDict = {} 253 profilesDict = {}
247 profilesDict.update(self.__profiles) 254 profilesDict.update(self.__profiles)
248 return profilesDict 255 return profilesDict
260 protocol = MqttProtocols.MQTTv311 267 protocol = MqttProtocols.MQTTv311
261 elif self.mqttv5Button.isChecked(): 268 elif self.mqttv5Button.isChecked():
262 protocol = MqttProtocols.MQTTv5 269 protocol = MqttProtocols.MQTTv5
263 else: 270 else:
264 protocol = MqttProtocols.MQTTv311 271 protocol = MqttProtocols.MQTTv311
272
273 if protocol == MqttProtocols.MQTTv5:
274 if self.connectPropertiesButton.isChecked():
275 self.__userProperties["connect"] = (
276 self.propertiesWidget.getProperties())
277 else:
278 self.__userProperties["disconnect"] = (
279 self.propertiesWidget.getProperties())
280 self.__userProperties["use_connect"] = (
281 self.samePropertiesCheckBox.isChecked())
282 else:
283 self.__userProperties = {}
265 284
266 profileName = self.profileEdit.text() 285 profileName = self.profileEdit.text()
267 connectionProfile = { 286 connectionProfile = {
268 "BrokerAddress": self.brokerAddressEdit.text(), 287 "BrokerAddress": self.brokerAddressEdit.text(),
269 "BrokerPort": self.brokerPortSpinBox.value(), 288 "BrokerPort": self.brokerPortSpinBox.value(),
280 "WillRetain": self.willRetainCheckBox.isChecked(), 299 "WillRetain": self.willRetainCheckBox.isChecked(),
281 "TlsEnable": self.tlsGroupBox.isChecked(), 300 "TlsEnable": self.tlsGroupBox.isChecked(),
282 "TlsCaCert": "", 301 "TlsCaCert": "",
283 "TlsClientCert": "", 302 "TlsClientCert": "",
284 "TlsClientKey": "", 303 "TlsClientKey": "",
304 "UserProperties": copy.deepcopy(self.__userProperties),
285 } 305 }
286 if connectionProfile["TlsEnable"]: 306 if connectionProfile["TlsEnable"]:
287 if self.tlsCertsFileButton.isChecked(): 307 if self.tlsCertsFileButton.isChecked():
288 connectionProfile["TlsCaCert"] = self.tlsCertsFilePicker.text() 308 connectionProfile["TlsCaCert"] = self.tlsCertsFilePicker.text()
289 elif self.tlsSelfSignedCertsButton.isChecked(): 309 elif self.tlsSelfSignedCertsButton.isChecked():
354 if profileName is not None: 374 if profileName is not None:
355 self.profileEdit.setText(profileName) 375 self.profileEdit.setText(profileName)
356 self.brokerAddressEdit.setText(connectionProfile["BrokerAddress"]) 376 self.brokerAddressEdit.setText(connectionProfile["BrokerAddress"])
357 self.brokerPortSpinBox.setValue(connectionProfile["BrokerPort"]) 377 self.brokerPortSpinBox.setValue(connectionProfile["BrokerPort"])
358 self.clientIdEdit.setText(connectionProfile["ClientId"]) 378 self.clientIdEdit.setText(connectionProfile["ClientId"])
379
380 # general tab
359 self.mqttv31Button.setChecked( 381 self.mqttv31Button.setChecked(
360 connectionProfile["Protocol"] == MqttProtocols.MQTTv31) 382 connectionProfile["Protocol"] == MqttProtocols.MQTTv31)
361 self.mqttv311Button.setChecked( 383 self.mqttv311Button.setChecked(
362 connectionProfile["Protocol"] == MqttProtocols.MQTTv311) 384 connectionProfile["Protocol"] == MqttProtocols.MQTTv311)
363 self.mqttv5Button.setChecked( 385 self.mqttv5Button.setChecked(
364 connectionProfile["Protocol"] == MqttProtocols.MQTTv5) 386 connectionProfile["Protocol"] == MqttProtocols.MQTTv5)
387 self.on_mqttv5Button_toggled(self.mqttv5Button.isChecked())
365 self.connectionTimeoutSpinBox.setValue( 388 self.connectionTimeoutSpinBox.setValue(
366 connectionProfile["ConnectionTimeout"]) 389 connectionProfile["ConnectionTimeout"])
367 self.keepaliveSpinBox.setValue(connectionProfile["Keepalive"]) 390 self.keepaliveSpinBox.setValue(connectionProfile["Keepalive"])
368 self.cleanSessionCheckBox.setChecked(connectionProfile["CleanSession"]) 391 self.cleanSessionCheckBox.setChecked(connectionProfile["CleanSession"])
392
393 # user credentials tab
369 self.usernameEdit.setText(connectionProfile["Username"]) 394 self.usernameEdit.setText(connectionProfile["Username"])
370 self.passwordEdit.setText( 395 self.passwordEdit.setText(
371 pwConvert(connectionProfile["Password"], encode=False)) 396 pwConvert(connectionProfile["Password"], encode=False))
397
398 # will tab
372 self.willTopicEdit.setText(connectionProfile["WillTopic"]) 399 self.willTopicEdit.setText(connectionProfile["WillTopic"])
373 self.willMessageEdit.setPlainText(connectionProfile["WillMessage"]) 400 self.willMessageEdit.setPlainText(connectionProfile["WillMessage"])
374 self.willQosSpinBox.setValue(connectionProfile["WillQos"]) 401 self.willQosSpinBox.setValue(connectionProfile["WillQos"])
375 self.willRetainCheckBox.setChecked(connectionProfile["WillRetain"]) 402 self.willRetainCheckBox.setChecked(connectionProfile["WillRetain"])
403
404 # SSL/TLS tab
376 self.tlsGroupBox.setChecked(connectionProfile["TlsEnable"]) 405 self.tlsGroupBox.setChecked(connectionProfile["TlsEnable"])
377 if ( 406 if (
378 connectionProfile["TlsCaCert"] and 407 connectionProfile["TlsCaCert"] and
379 connectionProfile["TlsClientCert"] 408 connectionProfile["TlsClientCert"]
380 ): 409 ):
388 elif connectionProfile["TlsCaCert"]: 417 elif connectionProfile["TlsCaCert"]:
389 self.tlsCertsFileButton.setChecked(True) 418 self.tlsCertsFileButton.setChecked(True)
390 self.tlsCertsFilePicker.setText(connectionProfile["TlsCaCert"]) 419 self.tlsCertsFilePicker.setText(connectionProfile["TlsCaCert"])
391 else: 420 else:
392 self.tlsDefaultCertsButton.setChecked(True) 421 self.tlsDefaultCertsButton.setChecked(True)
422
423 # user properties tab
424 self.__userProperties = copy.deepcopy(
425 connectionProfile.get("UserProperties", {}))
426 if not self.__userProperties:
427 self.__userProperties = {
428 "connect": [],
429 "disconnect": [],
430 "use_connect": True,
431 }
432
433 if connectionProfile["Protocol"] == MqttProtocols.MQTTv5:
434 self.connectPropertiesButton.setChecked(True)
435 self.propertiesWidget.setProperties(
436 self.__userProperties["connect"])
437 self.samePropertiesCheckBox.setChecked(
438 self.__userProperties["use_connect"])
439 self.disconnectPropertiesButton.setEnabled(
440 not self.__userProperties["use_connect"])
441 else:
442 self.propertiesWidget.clear()
443
393 self.__populatingProfile = False 444 self.__populatingProfile = False
394 445
395 self.showPasswordButton.setChecked(False) 446 self.showPasswordButton.setChecked(False)
396 self.profileFrame.setEnabled(True) 447 self.profileFrame.setEnabled(True)
397 self.__updateApplyButton() 448 self.__updateApplyButton()
449
450 self.profileTabWidget.setCurrentIndex(0)
398 451
399 def __clearProfile(self): 452 def __clearProfile(self):
400 """ 453 """
401 Private method to clear the profile data entry fields. 454 Private method to clear the profile data entry fields.
402 """ 455 """
420 self.tlsCertsFilePicker.setText("") 473 self.tlsCertsFilePicker.setText("")
421 self.tlsSelfSignedCertsButton.setChecked(False) 474 self.tlsSelfSignedCertsButton.setChecked(False)
422 self.tlsSelfSignedCertsFilePicker.setText("") 475 self.tlsSelfSignedCertsFilePicker.setText("")
423 self.tlsSelfSignedClientCertFilePicker.setText("") 476 self.tlsSelfSignedClientCertFilePicker.setText("")
424 self.tlsSelfSignedClientKeyFilePicker.setText("") 477 self.tlsSelfSignedClientKeyFilePicker.setText("")
478
479 self.__userProperties = {
480 "connect": [],
481 "disconnect": [],
482 "use_connect": True,
483 }
484 self.propertiesWidget.clear()
485 self.samePropertiesCheckBox.setChecked(True)
486 self.connectPropertiesButton.setChecked(True)
487 self.disconnectPropertiesButton.setEnabled(False)
488
425 self.__populatingProfile = False 489 self.__populatingProfile = False
426 490
427 self.showPasswordButton.setChecked(False) 491 self.showPasswordButton.setChecked(False)
428 self.profileFrame.setEnabled(False) 492 self.profileFrame.setEnabled(False)
429 self.__updateApplyButton() 493 self.__updateApplyButton()
506 self.tlsSelfSignedClientCertFilePicker.text() != 570 self.tlsSelfSignedClientCertFilePicker.text() !=
507 connectionProfile["TlsClientCert"] or 571 connectionProfile["TlsClientCert"] or
508 self.tlsSelfSignedClientKeyFilePicker.text() != 572 self.tlsSelfSignedClientKeyFilePicker.text() !=
509 connectionProfile["TlsClientKey"] 573 connectionProfile["TlsClientKey"]
510 ) 574 )
575 # check user properties only, if not yet changed
576 if not changed and protocol == MqttProtocols.MQTTv5:
577 properties = {
578 "connect": self.propertiesWidget.getProperties(),
579 "disconnect": self.__userProperties["disconnect"],
580 } if self.connectPropertiesButton.isChecked() else {
581 "connect": self.__userProperties["connect"],
582 "disconnect": self.propertiesWidget.getProperties(),
583 }
584 changed |= (
585 self.samePropertiesCheckBox.isChecked() !=
586 connectionProfile["UserProperties"]["use_connect"] or
587 sorted(properties["connect"]) !=
588 sorted(connectionProfile["UserProperties"]["connect"]) or
589 sorted(properties["disconnect"]) !=
590 sorted(connectionProfile["UserProperties"]["disconnect"])
591 )
592
511 return changed 593 return changed
512 594
513 else: 595 else:
514 return True 596 return True
515 597
586 668
587 @param checked current state of the clean session selection 669 @param checked current state of the clean session selection
588 @type bool 670 @type bool
589 """ 671 """
590 self.__updateApplyButton() 672 self.__updateApplyButton()
673
674 @pyqtSlot(bool)
675 def on_mqttv5Button_toggled(self, checked):
676 """
677 Private slot to handle the selection of the MQTT protocol.
678
679 @param checked state of the button
680 @type bool
681 """
682 self.profileTabWidget.setTabEnabled(
683 self.profileTabWidget.indexOf(self.propertiesTab),
684 checked
685 )
686 # TODO: add code to enable the WILL properties button
591 687
592 @pyqtSlot(bool) 688 @pyqtSlot(bool)
593 def on_showPasswordButton_toggled(self, checked): 689 def on_showPasswordButton_toggled(self, checked):
594 """ 690 """
595 Private slot to show or hide the password. 691 Private slot to show or hide the password.
713 @param checked state of the selection 809 @param checked state of the selection
714 @type bool 810 @type bool
715 """ 811 """
716 self.__updateApplyButton() 812 self.__updateApplyButton()
717 813
814 @pyqtSlot(bool)
815 def on_samePropertiesCheckBox_toggled(self, checked):
816 """
817 Private slot to handle a change of the properties usage.
818
819 @param checked flag indicating to use the same user properties for
820 CONNECT and DISCONNECT
821 @type bool
822 """
823 if checked and not self.connectPropertiesButton.isChecked():
824 self.connectPropertiesButton.click()
825 self.disconnectPropertiesButton.setEnabled(not checked)
826
827 @pyqtSlot(bool)
828 def __propertiesTypeSelected(self, checked):
829 """
830 Private slot to handle the switching of the user properties type.
831
832 @param checked state of the buttons
833 @type bool
834 """
835 if checked:
836 # handle the selection only
837 if self.connectPropertiesButton.isChecked():
838 self.__userProperties["disconnect"] = (
839 self.propertiesWidget.getProperties())
840 self.propertiesWidget.setProperties(
841 self.__userProperties["connect"])
842 else:
843 self.__userProperties["connect"] = (
844 self.propertiesWidget.getProperties())
845 self.propertiesWidget.setProperties(
846 self.__userProperties["disconnect"])
847
718 @pyqtSlot() 848 @pyqtSlot()
719 def reject(self): 849 def reject(self):
720 """ 850 """
721 Public slot to reject the dialog changes. 851 Public slot to reject the dialog changes.
722 """ 852 """

eric ide

mercurial