Sun, 09 Sep 2018 17:32:54 +0200
Added a connect timeout function with a settable timeout value.
diff -r 17ef10819773 -r 40582e448c4b MqttMonitor/MqttClient.py --- a/MqttMonitor/MqttClient.py Sun Sep 09 12:21:19 2018 +0200 +++ b/MqttMonitor/MqttClient.py Sun Sep 09 17:32:54 2018 +0200 @@ -9,7 +9,8 @@ from __future__ import unicode_literals -from PyQt5.QtCore import pyqtSignal, QObject, QCoreApplication +from PyQt5.QtCore import pyqtSignal, pyqtSlot, QObject, QCoreApplication, \ + QTimer import paho.mqtt.client as mqtt @@ -24,6 +25,7 @@ broker @signal onDisconnected(rc) emitted after the client has disconnected from the broker + @signal onLog(level, message) emitted to send client log data @signal onMessage(topic, payload, qos, retain) emitted after a message has been received by the client @signal onPublish(mid) emitted after a message has been published @@ -34,11 +36,29 @@ """ onConnect = pyqtSignal(dict, int) onDisconnected = pyqtSignal(int) + onLog = pyqtSignal(int, str) onMessage = pyqtSignal(str, bytes, int, bool) onPublish = pyqtSignal(int) onSubscribe = pyqtSignal(int, tuple) onUnsubscribe = pyqtSignal(int) + connectTimeout = pyqtSignal() + + DefaultConnectTimeout = 15 # connect timeout in seconds + + LogDebug = 0x01 + LogInfo = 0x02 + LogNotice = 0x04 + LogWarning = 0x08 + LogError = 0x10 + LogLevelMap = { + mqtt.MQTT_LOG_DEBUG: LogDebug, + mqtt.MQTT_LOG_INFO: LogInfo, + mqtt.MQTT_LOG_NOTICE: LogNotice, + mqtt.MQTT_LOG_WARNING: LogWarning, # __NO-TASK__ + mqtt.MQTT_LOG_ERR: LogError, + } + def __init__(self, clientId="", cleanSession=True, userdata=None, protocol=mqtt.MQTTv311, transport="tcp", parent=None): """ @@ -61,6 +81,14 @@ self.__loopStarted = False + self.__connectTimeoutTimer = QTimer(self) + self.__connectTimeoutTimer.setSingleShot(True) + self.__connectTimeoutTimer.setInterval( + MqttClient.DefaultConnectTimeout * 1000) + self.__connectTimeoutTimer.timeout.connect(self.__connectTimeout) + + self.onConnect.connect(self.__connectTimeoutTimer.stop) + self.__mqttClient = mqtt.Client( client_id=clientId, clean_session=cleanSession, userdata=None, protocol=mqtt.MQTTv311, transport="tcp") @@ -76,6 +104,8 @@ flags, rc) self.__mqttClient.on_disconnect = \ lambda client, userdata, rc: self.onDisconnected.emit(rc) + self.__mqttClient.on_log = \ + lambda client, userdata, level, buf: self.onLog.emit(level, buf) self.__mqttClient.on_message = \ lambda client, userdata, message: self.onMessage.emit( message.topic, message.payload, message.qos, message.retain) @@ -87,6 +117,14 @@ self.__mqttClient.on_unsubscribe = \ lambda client, userdata, mid: self.onUnsubscribe.emit(mid) + @pyqtSlot() + def __connectTimeout(self): + """ + Privat slot handling a failed connection attempt. + """ + self.stopLoop() + self.connectTimeout.emit() + def reinitialise(self, clientId="", cleanSession=True, userdata=None): """ Public method to reinitialize the client with given data. @@ -103,6 +141,15 @@ self.__initCallbacks() + def setConnectionTimeout(self, timeout): + """ + Public method to set the connection timeout value. + + @param timeout timeout value to be set in seconds + @type int + """ + self.__connectTimeoutTimer.setInterval(timeout * 1000) + def setMaxInflightMessages(self, inflight=20): """ Public method to set the maximum number of messages with QoS > 0 that @@ -202,7 +249,8 @@ self.__mqttClient.loop_stop() self.__loopStarted = False - def connectToServer(self, host, port=1883, keepalive=60, bindAddress=""): + def connectToServer(self, host, port=1883, keepalive=60, bindAddress="", + reinit=True): """ Public method to connect to a remote MQTT broker. @@ -218,11 +266,13 @@ this client to @type str """ - # TODO: get this fixed or allow to interrupt - self.__mqttClient.reconnect_delay_set(max_delay=16) + if reinit: + self.reinitialise() self.__mqttClient.connect_async( host, port=port, keepalive=keepalive, bind_address=bindAddress) + self.__connectTimeoutTimer.start() + if not self.__loopStarted: self.startLoop() @@ -243,7 +293,7 @@ dictionary should contain the keys "ClientId", "Keepalive", "CleanSession", "Username", "Password", "WillTopic", "WillMessage", "WillQos", "WillRetain", "TlsEnable", "TlsCaCert", "TlsClientCert", - "TlsClientKey" + "TlsClientKey", "ConnectionTimeout" @type dict """ if options: @@ -255,6 +305,7 @@ clientId=parametersDict["ClientId"], cleanSession=parametersDict["CleanSession"] ) + self.setConnectionTimeout(parametersDict["ConnectionTimeout"]) # step 2: set username and password if parametersDict["Username"]: @@ -294,7 +345,8 @@ # step 5: connect to server self.connectToServer(host, port=port, - keepalive=parametersDict["Keepalive"]) + keepalive=parametersDict["Keepalive"], + reinit=False) else: keepalive = self.defaultConnectionOptions["Keepalive"] self.connectToServer(host, port=port, keepalive=keepalive, @@ -308,11 +360,13 @@ @return dictionary containing the default connection options. It has the keys "ClientId", "Keepalive", "CleanSession", "Username", "Password", "WillTopic", "WillMessage", "WillQos", "WillRetain", - "TlsEnable", "TlsCaCert", "TlsClientCert", "TlsClientKey". + "TlsEnable", "TlsCaCert", "TlsClientCert", "TlsClientKey", + "ConnectionTimeout". @rtype dict """ return { "ClientId": "ERIC6_MQTT_MONITOR_CLIENT", + "ConnectionTimeout": MqttClient.DefaultConnectTimeout, "Keepalive": 60, "CleanSession": True, "Username": "", @@ -331,6 +385,8 @@ """ Public method to reconnect the client with the same parameters. """ + self.__connectTimeoutTimer.start() + self.__mqttClient.reconnect() if not self.__loopStarted: @@ -340,6 +396,8 @@ """ Public method to disconnect the client from the remote broker. """ + self.__connectTimeoutTimer.stop() + self.__mqttClient.disconnect() def subscribe(self, topic, qos=0): @@ -389,7 +447,7 @@ def mqttConnackMessage(connackCode): """ - Public method to get the string associated with a CONNACK result. + Module function to get the string associated with a CONNACK result. @param connackCode result code of the connection request @type int @@ -428,7 +486,7 @@ def mqttErrorMessage(mqttErrno): """ - Public method to get the error string associated with an MQTT error + Module function to get the error string associated with an MQTT error number. @param mqttErrno result code of a MQTT request @@ -501,3 +559,37 @@ return QCoreApplication.translate( "MqttErrorMessage", "Unknown error.") + + +def mqttLogLevelString(mqttLogLevel, isMqttLogLevel=True): + """ + Module function to get the log level string associated with a log level. + + @param mqttLogLevel log level of the paho-mqtt client + @type int + @param isMqttLogLevel flag indicating a MQTT log level is given (if + False it is the MqttClient variant, i.e. Debug being lowest) + @type bool + @return textual representation of the log level + @rtype str + """ + if isMqttLogLevel: + try: + logLevel = MqttClient.LogLevelMap[mqttLogLevel] + except KeyError: + return QCoreApplication.translate("MqttLogLevelString", "Unknown") + else: + logLevel = mqttLogLevel + + if logLevel == MqttClient.LogInfo: + return QCoreApplication.translate("MqttLogLevelString", "Info") + elif logLevel == MqttClient.LogNotice: + return QCoreApplication.translate("MqttLogLevelString", "Notice") + elif logLevel == MqttClient.LogWarning: + return QCoreApplication.translate("MqttLogLevelString", "Warning") + elif logLevel == MqttClient.LogError: + return QCoreApplication.translate("MqttLogLevelString", "Error") + elif logLevel == MqttClient.LogDebug: + return QCoreApplication.translate("MqttLogLevelString", "Debug") + else: + return QCoreApplication.translate("MqttLogLevelString", "Unknown")
diff -r 17ef10819773 -r 40582e448c4b MqttMonitor/MqttConnectionOptionsDialog.py --- a/MqttMonitor/MqttConnectionOptionsDialog.py Sun Sep 09 12:21:19 2018 +0200 +++ b/MqttMonitor/MqttConnectionOptionsDialog.py Sun Sep 09 17:32:54 2018 +0200 @@ -34,7 +34,8 @@ @param options dictionary containing the connection options to populate the dialog with. It must have the keys "ClientId", "Keepalive", "CleanSession", "Username", "Password", "WillTopic", - "WillMessage", "WillQos", "WillRetain", "TlsEnable", "TlsCaCert". + "WillMessage", "WillQos", "WillRetain", "TlsEnable", "TlsCaCert", + "ConnectionTimeout". @type dict @param parent reference to the parent widget @type QWidget @@ -97,7 +98,8 @@ @param options dictionary containing the connection options to populate the dialog with. It must have the keys "ClientId", "Keepalive", "CleanSession", "Username", "Password", "WillTopic", "WillMessage", - "WillQos", "WillRetain", "TlsEnable", "TlsCaCert". + "WillQos", "WillRetain", "TlsEnable", "TlsCaCert", + "ConnectionTimeout". @type dict """ if options is None: @@ -105,6 +107,7 @@ # general self.clientIdEdit.setText(options["ClientId"]) + self.connectionTimeoutSpinBox.setValue(options["ConnectionTimeout"]) self.keepaliveSpinBox.setValue(options["Keepalive"]) self.cleanSessionCheckBox.setChecked(options["CleanSession"]) @@ -129,11 +132,12 @@ @return dictionary containing the connection options. It has the keys "ClientId", "Keepalive", "CleanSession", "Username", "Password", "WillTopic", "WillMessage", "WillQos", "WillRetain", "TlsEnable", - "TlsCaCert". + "TlsCaCert", "ConnectionTimeout". @rtype tuple of (int, dict) """ return { "ClientId": self.clientIdEdit.text(), + "ConnectionTimeout": self.connectionTimeoutSpinBox.value(), "Keepalive": self.keepaliveSpinBox.value(), "CleanSession": self.cleanSessionCheckBox.isChecked(), "Username": self.usernameEdit.text(),
diff -r 17ef10819773 -r 40582e448c4b MqttMonitor/MqttConnectionOptionsDialog.ui --- a/MqttMonitor/MqttConnectionOptionsDialog.ui Sun Sep 09 12:21:19 2018 +0200 +++ b/MqttMonitor/MqttConnectionOptionsDialog.ui Sun Sep 09 17:32:54 2018 +0200 @@ -7,7 +7,7 @@ <x>0</x> <y>0</y> <width>550</width> - <height>600</height> + <height>650</height> </rect> </property> <property name="windowTitle"> @@ -48,13 +48,59 @@ </widget> </item> <item row="1" column="0"> + <widget class="QLabel" name="label_6"> + <property name="text"> + <string>Connection Timeout:</string> + </property> + </widget> + </item> + <item row="1" column="1" colspan="2"> + <layout class="QHBoxLayout" name="horizontalLayout_2"> + <item> + <widget class="QSpinBox" name="connectionTimeoutSpinBox"> + <property name="toolTip"> + <string>Enter the connection timeout in seconds</string> + </property> + <property name="alignment"> + <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set> + </property> + <property name="suffix"> + <string> s</string> + </property> + <property name="maximum"> + <number>300</number> + </property> + <property name="singleStep"> + <number>5</number> + </property> + <property name="value"> + <number>15</number> + </property> + </widget> + </item> + <item> + <spacer name="horizontalSpacer_2"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>148</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + </layout> + </item> + <item row="2" column="0"> <widget class="QLabel" name="label_2"> <property name="text"> <string>Keep Alive Interval:</string> </property> </widget> </item> - <item row="1" column="1" colspan="2"> + <item row="2" column="1" colspan="2"> <layout class="QHBoxLayout" name="horizontalLayout"> <item> <widget class="QSpinBox" name="keepaliveSpinBox"> @@ -93,7 +139,7 @@ </item> </layout> </item> - <item row="2" column="0" colspan="3"> + <item row="3" column="0" colspan="3"> <widget class="QCheckBox" name="cleanSessionCheckBox"> <property name="toolTip"> <string>Select to start with a clean session</string> @@ -278,6 +324,7 @@ <tabstops> <tabstop>clientIdEdit</tabstop> <tabstop>generateIdButton</tabstop> + <tabstop>connectionTimeoutSpinBox</tabstop> <tabstop>keepaliveSpinBox</tabstop> <tabstop>cleanSessionCheckBox</tabstop> <tabstop>usernameEdit</tabstop> @@ -286,6 +333,8 @@ <tabstop>willMessageEdit</tabstop> <tabstop>willQosSpinBox</tabstop> <tabstop>willRetainCheckBox</tabstop> + <tabstop>tlsEnableCheckBox</tabstop> + <tabstop>tlsCertsFilePicker</tabstop> </tabstops> <resources/> <connections> @@ -296,8 +345,8 @@ <slot>accept()</slot> <hints> <hint type="sourcelabel"> - <x>257</x> - <y>590</y> + <x>266</x> + <y>640</y> </hint> <hint type="destinationlabel"> <x>157</x> @@ -312,8 +361,8 @@ <slot>reject()</slot> <hints> <hint type="sourcelabel"> - <x>325</x> - <y>590</y> + <x>334</x> + <y>640</y> </hint> <hint type="destinationlabel"> <x>286</x> @@ -328,12 +377,12 @@ <slot>setEnabled(bool)</slot> <hints> <hint type="sourcelabel"> - <x>82</x> - <y>523</y> + <x>103</x> + <y>572</y> </hint> <hint type="destinationlabel"> - <x>92</x> - <y>544</y> + <x>164</x> + <y>596</y> </hint> </hints> </connection>
diff -r 17ef10819773 -r 40582e448c4b MqttMonitor/MqttConnectionProfilesDialog.py --- a/MqttMonitor/MqttConnectionProfilesDialog.py Sun Sep 09 12:21:19 2018 +0200 +++ b/MqttMonitor/MqttConnectionProfilesDialog.py Sun Sep 09 17:32:54 2018 +0200 @@ -40,7 +40,7 @@ "BrokerAddress", "BrokerPort", "ClientId", "Keepalive", "CleanSession", "Username", "Password", "WillTopic", "WillMessage", "WillQos", "WillRetain", "TlsEnable", "TlsCaCert", - "TlsClientCert", "TlsClientKey". + "TlsClientCert", "TlsClientKey", "ConnectionTimeout". @type dict @param parent reference to the parent widget @type QWidget @@ -231,7 +231,8 @@ connection profiles. Each entry have the keys "BrokerAddress", "BrokerPort", "ClientId", "Keepalive", "CleanSession", "Username", "Password", "WillTopic", "WillMessage", "WillQos", "WillRetain", - "TlsEnable", "TlsCaCert", "TlsClientCert", "TlsClientKey". + "TlsEnable", "TlsCaCert", "TlsClientCert", "TlsClientKey", + "ConnectionTimeout". @rtype dict """ profilesDict = {} @@ -250,6 +251,7 @@ "BrokerAddress": self.brokerAddressEdit.text(), "BrokerPort": self.brokerPortSpinBox.value(), "ClientId": self.clientIdEdit.text(), + "ConnectionTimeout": self.connectionTimeoutSpinBox.value(), "Keepalive": self.keepaliveSpinBox.value(), "CleanSession": self.cleanSessionCheckBox.isChecked(), "Username": self.usernameEdit.text(), @@ -336,6 +338,7 @@ self.brokerAddressEdit.setText(profile["BrokerAddress"]) self.brokerPortSpinBox.setValue(profile["BrokerPort"]) self.clientIdEdit.setText(profile["ClientId"]) + self.connectionTimeoutSpinBox.setValue(profile["ConnectionTimeout"]) self.keepaliveSpinBox.setValue(profile["Keepalive"]) self.cleanSessionCheckBox.setChecked(profile["CleanSession"]) self.usernameEdit.setText(profile["Username"]) @@ -427,6 +430,8 @@ self.brokerAddressEdit.text() != profile["BrokerAddress"] or self.brokerPortSpinBox.value() != profile["BrokerPort"] or self.clientIdEdit.text() != profile["ClientId"] or + self.connectionTimeoutSpinBox.value() != + profile["ConnectionTimeout"] or self.keepaliveSpinBox.value() != profile["Keepalive"] or self.cleanSessionCheckBox.isChecked() != profile["CleanSession"] or
diff -r 17ef10819773 -r 40582e448c4b MqttMonitor/MqttConnectionProfilesDialog.ui --- a/MqttMonitor/MqttConnectionProfilesDialog.ui Sun Sep 09 12:21:19 2018 +0200 +++ b/MqttMonitor/MqttConnectionProfilesDialog.ui Sun Sep 09 17:32:54 2018 +0200 @@ -208,7 +208,7 @@ <item> <widget class="QTabWidget" name="profileTabWidget"> <property name="currentIndex"> - <number>0</number> + <number>3</number> </property> <widget class="QWidget" name="generalTab"> <attribute name="title"> @@ -216,13 +216,59 @@ </attribute> <layout class="QGridLayout" name="gridLayout_2"> <item row="0" column="0"> + <widget class="QLabel" name="label_12"> + <property name="text"> + <string>Connection Timeout:</string> + </property> + </widget> + </item> + <item row="0" column="1"> + <layout class="QHBoxLayout" name="horizontalLayout_5"> + <item> + <widget class="QSpinBox" name="connectionTimeoutSpinBox"> + <property name="toolTip"> + <string>Enter the connection timeout in seconds</string> + </property> + <property name="alignment"> + <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set> + </property> + <property name="suffix"> + <string> s</string> + </property> + <property name="maximum"> + <number>300</number> + </property> + <property name="singleStep"> + <number>5</number> + </property> + <property name="value"> + <number>15</number> + </property> + </widget> + </item> + <item> + <spacer name="horizontalSpacer_6"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>148</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + </layout> + </item> + <item row="1" column="0"> <widget class="QLabel" name="label_5"> <property name="text"> <string>Keep Alive Interval:</string> </property> </widget> </item> - <item row="0" column="1"> + <item row="1" column="1"> <layout class="QHBoxLayout" name="horizontalLayout_4"> <item> <widget class="QSpinBox" name="keepaliveSpinBox"> @@ -261,7 +307,7 @@ </item> </layout> </item> - <item row="1" column="0" colspan="2"> + <item row="2" column="0" colspan="2"> <widget class="QCheckBox" name="cleanSessionCheckBox"> <property name="toolTip"> <string>Select to start with a clean session</string> @@ -271,7 +317,7 @@ </property> </widget> </item> - <item row="2" column="1"> + <item row="3" column="1"> <spacer name="verticalSpacer"> <property name="orientation"> <enum>Qt::Vertical</enum> @@ -673,6 +719,7 @@ <tabstop>clientIdEdit</tabstop> <tabstop>generateIdButton</tabstop> <tabstop>profileTabWidget</tabstop> + <tabstop>connectionTimeoutSpinBox</tabstop> <tabstop>keepaliveSpinBox</tabstop> <tabstop>cleanSessionCheckBox</tabstop> <tabstop>usernameEdit</tabstop>
diff -r 17ef10819773 -r 40582e448c4b MqttMonitor/MqttMonitorWidget.py --- a/MqttMonitor/MqttMonitorWidget.py Sun Sep 09 12:21:19 2018 +0200 +++ b/MqttMonitor/MqttMonitorWidget.py Sun Sep 09 17:32:54 2018 +0200 @@ -26,7 +26,8 @@ from .Ui_MqttMonitorWidget import Ui_MqttMonitorWidget -from .MqttClient import MqttClient, mqttConnackMessage, mqttErrorMessage +from .MqttClient import MqttClient, mqttConnackMessage, mqttErrorMessage, \ + mqttLogLevelString import UI.PixmapCache import Utilities @@ -60,6 +61,16 @@ self.pixmapLabel.setPixmap(UI.PixmapCache.getPixmap( os.path.join("MqttMonitor", "icons", "mqtt48.png"))) + for logLevel in (MqttClient.LogDebug, + MqttClient.LogInfo, + MqttClient.LogNotice, + MqttClient.LogWarning, + MqttClient.LogError): + self.logLevelComboBox.addItem(mqttLogLevelString( + logLevel, isMqttLogLevel=False), logLevel) + self.logLevelComboBox.setCurrentIndex( + self.logLevelComboBox.count() - 1) + self.brokerWidget.setCurrentIndex(0) self.__connectionModeProfile = True @@ -135,10 +146,13 @@ # connect the MQTT client signals self.__client.onConnect.connect(self.__brokerConnected) self.__client.onDisconnected.connect(self.__brokerDisconnected) + self.__client.onLog.connect(self.__clientLog) self.__client.onMessage.connect(self.__messageReceived) self.__client.onPublish.connect(self.__messagePublished) self.__client.onSubscribe.connect(self.__topicSubscribed) self.__client.onUnsubscribe.connect(self.__topicUnsubscribed) + + self.__client.connectTimeout.connect(self.__connectTimeout) ####################################################################### ## Slots handling MQTT related signals @@ -183,6 +197,14 @@ else: self.__client.stopLoop() + @pyqtSlot() + def __connectTimeout(self): + """ + Private slot handling a timeout during a connection attempt. + """ + self.__flashBrokerStatusLabel(self.tr("Connection timed out")) + self.__setConnectButtonState() + @pyqtSlot(int) def __brokerDisconnected(self, rc): """ @@ -203,7 +225,7 @@ self.__flashBrokerStatusLabel(msg) self.connectButton.setIcon(UI.PixmapCache.getIcon("ircConnect.png")) - self.connectButton.setEnabled(True) + self.__setConnectButtonState() self.__subscribedTopics = [] self.__topicQueue = {} @@ -217,6 +239,34 @@ self.__statusLoadValues.clear() + @pyqtSlot(int, str) + def __clientLog(self, level, message): + """ + Private slot to handle the receipt of a log message. + + @param level log level + @type int + @param message log message + @type str + """ + try: + if MqttClient.LogLevelMap[level] < self.logLevelComboBox.itemData( + self.logLevelComboBox.currentIndex()): + return + except KeyError: + # always show unknown log levels + pass + + txt = self.tr("{0}: {1}").format(mqttLogLevelString(level), message) + if not txt.endswith(("\r\n", "\r", "\n")): + txt += "\n" + + tc = self.logEdit.textCursor() + tc.movePosition(QTextCursor.End) + self.logEdit.setTextCursor(tc) + self.logEdit.insertPlainText(Utilities.filterAnsiSequences(txt)) + self.logEdit.ensureCursorVisible() + @pyqtSlot(str, bytes, int, bool) def __messageReceived(self, topic, payload, qos, retain): """ @@ -309,6 +359,16 @@ self.__setConnectionMode(not self.__connectionModeProfile) @pyqtSlot(str) + def on_profileComboBox_currentIndexChanged(self, profileName): + """ + Private slot handling the change of the selected profile. + + @param profileName name of the selected profile + @type str + """ + self.__setConnectButtonState() + + @pyqtSlot(str) def on_brokerComboBox_editTextChanged(self, host): """ Private slot to handling entering or selecting a broker host name. @@ -730,7 +790,7 @@ if host: self.brokerStatusLabel.setText( self.tr("Connecting to {0}:{1} ...").format( - host, port)) + host, port)) self.brokerStatusLabel.show() self.__addBrokerToRecent(host, port) @@ -756,7 +816,7 @@ self.brokerStatusLabel.setText( self.tr("Connecting to {0}:{1} ...").format( - host, port)) + host, port)) self.brokerStatusLabel.show() self.connectButton.setEnabled(False)
diff -r 17ef10819773 -r 40582e448c4b MqttMonitor/MqttMonitorWidget.ui --- a/MqttMonitor/MqttMonitorWidget.ui Sun Sep 09 12:21:19 2018 +0200 +++ b/MqttMonitor/MqttMonitorWidget.ui Sun Sep 09 17:32:54 2018 +0200 @@ -144,7 +144,7 @@ <item> <widget class="QTabWidget" name="brokerWidget"> <property name="currentIndex"> - <number>0</number> + <number>3</number> </property> <widget class="QWidget" name="pubSubTab"> <attribute name="title"> @@ -479,8 +479,8 @@ <rect> <x>0</x> <y>0</y> - <width>339</width> - <height>670</height> + <width>178</width> + <height>840</height> </rect> </property> <layout class="QFormLayout" name="formLayout"> @@ -1197,6 +1197,80 @@ </item> </layout> </widget> + <widget class="QWidget" name="logTab"> + <attribute name="title"> + <string>Log</string> + </attribute> + <layout class="QVBoxLayout" name="verticalLayout_6"> + <item> + <layout class="QHBoxLayout" name="horizontalLayout_17"> + <item> + <widget class="QLabel" name="label_41"> + <property name="text"> + <string>Max. Log Level:</string> + </property> + </widget> + </item> + <item> + <widget class="QComboBox" name="logLevelComboBox"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Expanding" vsizetype="Fixed"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="toolTip"> + <string>Select the maximum log level to show</string> + </property> + </widget> + </item> + </layout> + </item> + <item> + <widget class="QPlainTextEdit" name="logEdit"> + <property name="tabChangesFocus"> + <bool>true</bool> + </property> + <property name="lineWrapMode"> + <enum>QPlainTextEdit::NoWrap</enum> + </property> + <property name="readOnly"> + <bool>true</bool> + </property> + <property name="textInteractionFlags"> + <set>Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse</set> + </property> + </widget> + </item> + <item> + <layout class="QHBoxLayout" name="horizontalLayout_16"> + <item> + <spacer name="horizontalSpacer_4"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>40</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + <item> + <widget class="QPushButton" name="logClearButton"> + <property name="toolTip"> + <string>Press to clear the list of received log messages</string> + </property> + <property name="text"> + <string>Clear</string> + </property> + </widget> + </item> + </layout> + </item> + </layout> + </widget> </widget> </item> </layout> @@ -1232,10 +1306,13 @@ <tabstop>publishRetainCheckBox</tabstop> <tabstop>publishClearButton</tabstop> <tabstop>publishButton</tabstop> + <tabstop>clearPublishCheckBox</tabstop> <tabstop>messagesEdit</tabstop> <tabstop>messagesClearButton</tabstop> <tabstop>brokerStatusButton</tabstop> <tabstop>scrollArea</tabstop> + <tabstop>logEdit</tabstop> + <tabstop>logClearButton</tabstop> </tabstops> <resources/> <connections> @@ -1271,5 +1348,21 @@ </hint> </hints> </connection> + <connection> + <sender>logClearButton</sender> + <signal>clicked()</signal> + <receiver>logEdit</receiver> + <slot>clear()</slot> + <hints> + <hint type="sourcelabel"> + <x>354</x> + <y>559</y> + </hint> + <hint type="destinationlabel"> + <x>274</x> + <y>456</y> + </hint> + </hints> + </connection> </connections> </ui>