MqttMonitor/MqttMonitorWidget.py

branch
eric7
changeset 123
3d7e63ed4fd1
parent 114
8c0e9e602124
child 127
8982ef7b7d67
equal deleted inserted replaced
122:28d69b9e1b6a 123:3d7e63ed4fd1
21 from EricWidgets.EricPathPicker import EricPathPickerModes 21 from EricWidgets.EricPathPicker import EricPathPickerModes
22 22
23 from .Ui_MqttMonitorWidget import Ui_MqttMonitorWidget 23 from .Ui_MqttMonitorWidget import Ui_MqttMonitorWidget
24 24
25 from .MqttClient import ( 25 from .MqttClient import (
26 MqttClient, mqttConnackMessage, mqttErrorMessage, mqttLogLevelString 26 MqttClient,
27 mqttConnackMessage,
28 mqttErrorMessage,
29 mqttLogLevelString,
27 ) 30 )
28 from .MqttReasonCodes import mqttReasonCode 31 from .MqttReasonCodes import mqttReasonCode
29 from .MqttProtocols import MqttProtocols 32 from .MqttProtocols import MqttProtocols
30 33
31 import UI.PixmapCache 34 import UI.PixmapCache
34 37
35 class MqttMonitorWidget(QWidget, Ui_MqttMonitorWidget): 38 class MqttMonitorWidget(QWidget, Ui_MqttMonitorWidget):
36 """ 39 """
37 Class implementing the MQTT Monitor widget. 40 Class implementing the MQTT Monitor widget.
38 """ 41 """
42
39 BrokerStatusTopicPrefix = "$SYS/broker/" 43 BrokerStatusTopicPrefix = "$SYS/broker/"
40 BrokerStatusTopic = "$SYS/broker/#" 44 BrokerStatusTopic = "$SYS/broker/#"
41 BrokerStatusTopicLoadPrefix = "$SYS/broker/load/" 45 BrokerStatusTopicLoadPrefix = "$SYS/broker/load/"
42 46
43 def __init__(self, plugin, usesDarkPalette, parent=None): 47 def __init__(self, plugin, usesDarkPalette, parent=None):
44 """ 48 """
45 Constructor 49 Constructor
46 50
47 @param plugin reference to the plug-in object 51 @param plugin reference to the plug-in object
48 @type MqttMonitorPlugin 52 @type MqttMonitorPlugin
49 @param usesDarkPalette flag indicating the use of a dark application 53 @param usesDarkPalette flag indicating the use of a dark application
50 palette 54 palette
51 @type bool 55 @type bool
52 @param parent reference to the parent widget 56 @param parent reference to the parent widget
53 @type QWidget 57 @type QWidget
54 """ 58 """
55 super().__init__(parent) 59 super().__init__(parent)
56 self.setupUi(self) 60 self.setupUi(self)
57 61
58 self.layout().setContentsMargins(0, 3, 0, 0) 62 self.layout().setContentsMargins(0, 3, 0, 0)
59 63
60 self.__plugin = plugin 64 self.__plugin = plugin
61 self.__iconSuffix = "dark" if usesDarkPalette else "light" 65 self.__iconSuffix = "dark" if usesDarkPalette else "light"
62 66
63 self.__connectedToBroker = False 67 self.__connectedToBroker = False
64 self.__brokerStatusTopicSubscribed = False 68 self.__brokerStatusTopicSubscribed = False
65 69
66 with contextlib.suppress(AttributeError): 70 with contextlib.suppress(AttributeError):
67 # backward compatibility 71 # backward compatibility
68 if not ericApp().usesSmallScreen(): 72 if not ericApp().usesSmallScreen():
69 self.pixmapLabel.setPixmap(UI.PixmapCache.getPixmap( 73 self.pixmapLabel.setPixmap(
70 os.path.join("MqttMonitor", "icons", 74 UI.PixmapCache.getPixmap(
71 "mqtt48-{0}".format(self.__iconSuffix)) 75 os.path.join(
72 )) 76 "MqttMonitor",
73 77 "icons",
74 self.publishPayloadFilePicker.setMode( 78 "mqtt48-{0}".format(self.__iconSuffix),
75 EricPathPickerModes.OPEN_FILE_MODE) 79 )
80 )
81 )
82
83 self.publishPayloadFilePicker.setMode(EricPathPickerModes.OPEN_FILE_MODE)
76 self.publishPayloadFilePicker.setFilters(self.tr("All Files (*)")) 84 self.publishPayloadFilePicker.setFilters(self.tr("All Files (*)"))
77 85
78 self.brokerComboBox.lineEdit().setClearButtonEnabled(True) 86 self.brokerComboBox.lineEdit().setClearButtonEnabled(True)
79 self.publishTopicComboBox.lineEdit().setClearButtonEnabled(True) 87 self.publishTopicComboBox.lineEdit().setClearButtonEnabled(True)
80 88
81 self.__messagesFormat = self.messagesEdit.currentCharFormat() 89 self.__messagesFormat = self.messagesEdit.currentCharFormat()
82 self.__messagesTopicFormat = self.messagesEdit.currentCharFormat() 90 self.__messagesTopicFormat = self.messagesEdit.currentCharFormat()
83 self.__messagesTopicFormat.setFontWeight(QFont.Weight.Bold) 91 self.__messagesTopicFormat.setFontWeight(QFont.Weight.Bold)
84 self.__messagesQosFormat = self.messagesEdit.currentCharFormat() 92 self.__messagesQosFormat = self.messagesEdit.currentCharFormat()
85 self.__messagesQosFormat.setFontItalic(True) 93 self.__messagesQosFormat.setFontItalic(True)
86 self.__messagesSubheaderFormat = self.messagesEdit.currentCharFormat() 94 self.__messagesSubheaderFormat = self.messagesEdit.currentCharFormat()
87 self.__messagesSubheaderFormat.setFontUnderline(True) 95 self.__messagesSubheaderFormat.setFontUnderline(True)
88 96
89 self.__propertiesFormat = self.propertiesEdit.currentCharFormat() 97 self.__propertiesFormat = self.propertiesEdit.currentCharFormat()
90 self.__propertiesTopicFormat = self.propertiesEdit.currentCharFormat() 98 self.__propertiesTopicFormat = self.propertiesEdit.currentCharFormat()
91 self.__propertiesTopicFormat.setFontWeight(QFont.Weight.Bold) 99 self.__propertiesTopicFormat.setFontWeight(QFont.Weight.Bold)
92 self.__propertiesNameFormat = self.propertiesEdit.currentCharFormat() 100 self.__propertiesNameFormat = self.propertiesEdit.currentCharFormat()
93 self.__propertiesNameFormat.setFontItalic(True) 101 self.__propertiesNameFormat.setFontItalic(True)
94 102
95 self.messagesSearchWidget.attachTextEdit(self.messagesEdit) 103 self.messagesSearchWidget.attachTextEdit(self.messagesEdit)
96 self.messagesSearchWidget.setWidthForHeight(False) 104 self.messagesSearchWidget.setWidthForHeight(False)
97 105
98 self.__isMessageAlternate = False 106 self.__isMessageAlternate = False
99 self.__isPropertiesAlternate = False 107 self.__isPropertiesAlternate = False
100 108
101 for logLevel in (MqttClient.LogDisabled, 109 for logLevel in (
102 MqttClient.LogDebug, 110 MqttClient.LogDisabled,
103 MqttClient.LogInfo, 111 MqttClient.LogDebug,
104 MqttClient.LogNotice, 112 MqttClient.LogInfo,
105 MqttClient.LogWarning, 113 MqttClient.LogNotice,
106 MqttClient.LogError): 114 MqttClient.LogWarning,
107 self.logLevelComboBox.addItem(mqttLogLevelString( 115 MqttClient.LogError,
108 logLevel, isMqttLogLevel=False), logLevel) 116 ):
109 self.logLevelComboBox.setCurrentIndex( 117 self.logLevelComboBox.addItem(
110 self.logLevelComboBox.count() - 1) 118 mqttLogLevelString(logLevel, isMqttLogLevel=False), logLevel
111 119 )
120 self.logLevelComboBox.setCurrentIndex(self.logLevelComboBox.count() - 1)
121
112 if usesDarkPalette: 122 if usesDarkPalette:
113 self.__logMessagesBackgrounds = { 123 self.__logMessagesBackgrounds = {
114 MqttClient.LogDebug: QBrush(QColor("#2f2f2f")), 124 MqttClient.LogDebug: QBrush(QColor("#2f2f2f")),
115 MqttClient.LogInfo: QBrush(QColor("#868686")), 125 MqttClient.LogInfo: QBrush(QColor("#868686")),
116 MqttClient.LogNotice: QBrush(QColor("#009900")), 126 MqttClient.LogNotice: QBrush(QColor("#009900")),
127 MqttClient.LogWarning: QBrush(Qt.GlobalColor.yellow), 137 MqttClient.LogWarning: QBrush(Qt.GlobalColor.yellow),
128 MqttClient.LogError: QBrush(Qt.GlobalColor.red), 138 MqttClient.LogError: QBrush(Qt.GlobalColor.red),
129 MqttClient.LogDisabled: QBrush(Qt.GlobalColor.magenta) 139 MqttClient.LogDisabled: QBrush(Qt.GlobalColor.magenta)
130 # reuse LogDisabled for unknown log levels 140 # reuse LogDisabled for unknown log levels
131 } 141 }
132 142
133 self.logSearchWidget.attachTextEdit(self.logEdit) 143 self.logSearchWidget.attachTextEdit(self.logEdit)
134 self.logSearchWidget.setWidthForHeight(False) 144 self.logSearchWidget.setWidthForHeight(False)
135 145
136 self.brokerWidget.setCurrentIndex(0) 146 self.brokerWidget.setCurrentIndex(0)
137 147
138 self.__connectionModeProfile = True 148 self.__connectionModeProfile = True
139 self.__setConnectionMode(True) # initial mode is 'profile connection' 149 self.__setConnectionMode(True) # initial mode is 'profile connection'
140 self.__populateProfileComboBox() 150 self.__populateProfileComboBox()
141 151
142 self.connectButton.setIcon(UI.PixmapCache.getIcon("ircConnect")) 152 self.connectButton.setIcon(UI.PixmapCache.getIcon("ircConnect"))
143 self.brokerConnectionOptionsButton.setIcon(UI.PixmapCache.getIcon( 153 self.brokerConnectionOptionsButton.setIcon(
144 os.path.join("MqttMonitor", "icons", 154 UI.PixmapCache.getIcon(
145 "connectionOptions-{0}".format(self.__iconSuffix)) 155 os.path.join(
146 )) 156 "MqttMonitor",
157 "icons",
158 "connectionOptions-{0}".format(self.__iconSuffix),
159 )
160 )
161 )
147 self.__populateBrokerComboBoxes() 162 self.__populateBrokerComboBoxes()
148 self.brokerStatusLabel.hide() 163 self.brokerStatusLabel.hide()
149 self.clearWillButton.setIcon( 164 self.clearWillButton.setIcon(UI.PixmapCache.getIcon("certificateDelete"))
150 UI.PixmapCache.getIcon("certificateDelete")) 165
151
152 self.subscribeTopicComboBox.lineEdit().setClearButtonEnabled(True) 166 self.subscribeTopicComboBox.lineEdit().setClearButtonEnabled(True)
153 self.subscribeTopicComboBox.lineEdit().returnPressed.connect( 167 self.subscribeTopicComboBox.lineEdit().returnPressed.connect(
154 self.on_subscribeButton_clicked) 168 self.on_subscribeButton_clicked
169 )
155 self.__populateSubscribeTopicComboBox() 170 self.__populateSubscribeTopicComboBox()
156 171
157 self.subscribeButton.setIcon(UI.PixmapCache.getIcon("plus")) 172 self.subscribeButton.setIcon(UI.PixmapCache.getIcon("plus"))
158 self.subscribeButton.setEnabled(False) 173 self.subscribeButton.setEnabled(False)
159 self.subscribePropertiesButton.setIcon( 174 self.subscribePropertiesButton.setIcon(UI.PixmapCache.getIcon("listSelection"))
160 UI.PixmapCache.getIcon("listSelection"))
161 self.subscribePropertiesButton.setEnabled(False) 175 self.subscribePropertiesButton.setEnabled(False)
162 self.subscribePropertiesButton.setVisible(False) 176 self.subscribePropertiesButton.setVisible(False)
163 177
164 self.unsubscribeButton.setIcon(UI.PixmapCache.getIcon("minus")) 178 self.unsubscribeButton.setIcon(UI.PixmapCache.getIcon("minus"))
165 self.unsubscribeButton.setEnabled(False) 179 self.unsubscribeButton.setEnabled(False)
166 self.unsubscribePropertiesButton.setIcon( 180 self.unsubscribePropertiesButton.setIcon(
167 UI.PixmapCache.getIcon("listSelection")) 181 UI.PixmapCache.getIcon("listSelection")
182 )
168 self.unsubscribePropertiesButton.setEnabled(False) 183 self.unsubscribePropertiesButton.setEnabled(False)
169 self.unsubscribePropertiesButton.setVisible(False) 184 self.unsubscribePropertiesButton.setVisible(False)
170 185
171 self.__initPropertiesEditMenu() 186 self.__initPropertiesEditMenu()
172 187
173 self.__subscribedTopics = [] 188 self.__subscribedTopics = []
174 self.__topicQueue = {} 189 self.__topicQueue = {}
175 self.__updateUnsubscribeTopicComboBox() 190 self.__updateUnsubscribeTopicComboBox()
176 191
177 self.__publishedTopics = [] 192 self.__publishedTopics = []
178 self.__updatePublishTopicComboBox() 193 self.__updatePublishTopicComboBox()
179 self.publishButton.setEnabled(False) 194 self.publishButton.setEnabled(False)
180 self.publishPropertiesButton.setIcon( 195 self.publishPropertiesButton.setIcon(UI.PixmapCache.getIcon("listSelection"))
181 UI.PixmapCache.getIcon("listSelection"))
182 self.publishPropertiesButton.setEnabled(False) 196 self.publishPropertiesButton.setEnabled(False)
183 self.publishPropertiesButton.setVisible(False) 197 self.publishPropertiesButton.setVisible(False)
184 198
185 self.__connectionOptions = None 199 self.__connectionOptions = None
186 200
187 prefix = MqttMonitorWidget.BrokerStatusTopicPrefix 201 prefix = MqttMonitorWidget.BrokerStatusTopicPrefix
188 self.__statusLabelMapping = { 202 self.__statusLabelMapping = {
189 # broker 203 # broker
190 prefix + "version": self.versionLabel, 204 prefix + "version": self.versionLabel,
191 prefix + "timestamp": self.timestampLabel, 205 prefix + "timestamp": self.timestampLabel,
204 prefix + "store/messages/count": self.messagesStoredLabel, 218 prefix + "store/messages/count": self.messagesStoredLabel,
205 prefix + "messages/inflight": self.messagesInflightLabel, 219 prefix + "messages/inflight": self.messagesInflightLabel,
206 prefix + "retained messages/count": self.messagesRetainedLabel, 220 prefix + "retained messages/count": self.messagesRetainedLabel,
207 # publish messages 221 # publish messages
208 prefix + "publish/messages/sent": self.publishMessagesSentLabel, 222 prefix + "publish/messages/sent": self.publishMessagesSentLabel,
209 prefix + "publish/messages/received": 223 prefix + "publish/messages/received": self.publishMessagesReceivedLabel,
210 self.publishMessagesReceivedLabel, 224 prefix + "publish/messages/dropped": self.publishMessagesDroppedLabel,
211 prefix + "publish/messages/dropped":
212 self.publishMessagesDroppedLabel,
213 # traffic 225 # traffic
214 prefix + "bytes/sent": self.bytesSentLabel, 226 prefix + "bytes/sent": self.bytesSentLabel,
215 prefix + "bytes/received": self.bytesReceivedLabel, 227 prefix + "bytes/received": self.bytesReceivedLabel,
216 # load 228 # load
217 prefix + "load/bytes/sent": self.loadBytesSentLabel, 229 prefix + "load/bytes/sent": self.loadBytesSentLabel,
222 prefix + "load/publish/received": self.loadPublishReceivedLabel, 234 prefix + "load/publish/received": self.loadPublishReceivedLabel,
223 prefix + "load/publish/dropped": self.loadPublishDroppedLabel, 235 prefix + "load/publish/dropped": self.loadPublishDroppedLabel,
224 prefix + "load/connections": self.loadConnectionsLabel, 236 prefix + "load/connections": self.loadConnectionsLabel,
225 prefix + "load/sockets": self.loadSocketsLabel, 237 prefix + "load/sockets": self.loadSocketsLabel,
226 } 238 }
227 239
228 self.__statusLoadValues = collections.defaultdict( 240 self.__statusLoadValues = collections.defaultdict(self.__loadDefaultDictFactory)
229 self.__loadDefaultDictFactory) 241
230 242 def __createClient(self, clientId="", cleanSession=None, protocol=None):
231 def __createClient(self, clientId="", cleanSession=None,
232 protocol=None):
233 """ 243 """
234 Private method to instantiate a MQTT client for a given protocol. 244 Private method to instantiate a MQTT client for a given protocol.
235 245
236 @param clientId ID to be used for the client 246 @param clientId ID to be used for the client
237 @type str 247 @type str
238 @param cleanSession flag indicating to start a clean session 248 @param cleanSession flag indicating to start a clean session
239 @type bool 249 @type bool
240 @param protocol MQTT protocol version to be used (defaults to None) 250 @param protocol MQTT protocol version to be used (defaults to None)
242 @return created and connected MQTT client object 252 @return created and connected MQTT client object
243 @rtype MqttClient 253 @rtype MqttClient
244 """ 254 """
245 if protocol is None: 255 if protocol is None:
246 protocol = self.__plugin.getPreferences("DefaultProtocol") 256 protocol = self.__plugin.getPreferences("DefaultProtocol")
247 257
248 client = MqttClient(clientId=clientId, cleanSession=cleanSession, 258 client = MqttClient(
249 protocol=protocol) 259 clientId=clientId, cleanSession=cleanSession, protocol=protocol
250 260 )
261
251 # connect the MQTT client signals 262 # connect the MQTT client signals
252 client.onConnectV3.connect(self.__brokerConnected) 263 client.onConnectV3.connect(self.__brokerConnected)
253 client.onConnectV5.connect(self.__brokerConnected) 264 client.onConnectV5.connect(self.__brokerConnected)
254 client.onDisconnectedV3.connect(self.__brokerDisconnected) 265 client.onDisconnectedV3.connect(self.__brokerDisconnected)
255 client.onDisconnectedV5.connect(self.__brokerDisconnected) 266 client.onDisconnectedV5.connect(self.__brokerDisconnected)
259 client.onPublish.connect(self.__messagePublished) 270 client.onPublish.connect(self.__messagePublished)
260 client.onSubscribeV3.connect(self.__topicSubscribed) 271 client.onSubscribeV3.connect(self.__topicSubscribed)
261 client.onSubscribeV5.connect(self.__topicSubscribedV5) 272 client.onSubscribeV5.connect(self.__topicSubscribedV5)
262 client.onUnsubscribeV3.connect(self.__topicUnsubscribed) 273 client.onUnsubscribeV3.connect(self.__topicUnsubscribed)
263 client.onUnsubscribeV5.connect(self.__topicUnsubscribedV5) 274 client.onUnsubscribeV5.connect(self.__topicUnsubscribedV5)
264 275
265 client.connectTimeout.connect(self.__connectTimeout) 276 client.connectTimeout.connect(self.__connectTimeout)
266 277
267 return client 278 return client
268 279
269 def __initPropertiesEditMenu(self): 280 def __initPropertiesEditMenu(self):
270 """ 281 """
271 Private method to create the properties output context menu. 282 Private method to create the properties output context menu.
272 """ 283 """
273 self.__propertiesEditMenu = QMenu(self) 284 self.__propertiesEditMenu = QMenu(self)
274 self.__copyPropertiesAct = self.__propertiesEditMenu.addAction( 285 self.__copyPropertiesAct = self.__propertiesEditMenu.addAction(
275 UI.PixmapCache.getIcon("editCopy"), 286 UI.PixmapCache.getIcon("editCopy"),
276 self.tr("Copy"), self.propertiesEdit.copy) 287 self.tr("Copy"),
288 self.propertiesEdit.copy,
289 )
277 self.__propertiesEditMenu.addSeparator() 290 self.__propertiesEditMenu.addSeparator()
278 self.__selectAllPropertiesAct = self.__propertiesEditMenu.addAction( 291 self.__selectAllPropertiesAct = self.__propertiesEditMenu.addAction(
279 UI.PixmapCache.getIcon("editSelectAll"), 292 UI.PixmapCache.getIcon("editSelectAll"),
280 self.tr("Select All"), self.propertiesEdit.selectAll) 293 self.tr("Select All"),
294 self.propertiesEdit.selectAll,
295 )
281 self.__propertiesEditMenu.addSeparator() 296 self.__propertiesEditMenu.addSeparator()
282 self.__clearPropertiesAct = self.__propertiesEditMenu.addAction( 297 self.__clearPropertiesAct = self.__propertiesEditMenu.addAction(
283 UI.PixmapCache.getIcon("editDelete"), 298 UI.PixmapCache.getIcon("editDelete"),
284 self.tr("Clear"), self.propertiesEdit.clear) 299 self.tr("Clear"),
285 300 self.propertiesEdit.clear,
286 self.propertiesEdit.copyAvailable.connect( 301 )
287 self.__copyPropertiesAct.setEnabled) 302
288 303 self.propertiesEdit.copyAvailable.connect(self.__copyPropertiesAct.setEnabled)
304
289 self.__copyPropertiesAct.setEnabled(False) 305 self.__copyPropertiesAct.setEnabled(False)
290 306
291 ####################################################################### 307 #######################################################################
292 ## Slots handling MQTT related signals 308 ## Slots handling MQTT related signals
293 ####################################################################### 309 #######################################################################
294 310
295 @pyqtSlot(dict, int) 311 @pyqtSlot(dict, int)
296 @pyqtSlot(dict, int, int, dict) 312 @pyqtSlot(dict, int, int, dict)
297 def __brokerConnected(self, flags, rc, packetType=None, properties=None): 313 def __brokerConnected(self, flags, rc, packetType=None, properties=None):
298 """ 314 """
299 Private slot to handle being connected to a broker. 315 Private slot to handle being connected to a broker.
300 316
301 @param flags flags set for the connection 317 @param flags flags set for the connection
302 @type dict 318 @type dict
303 @param rc CONNACK result code or MQTTv5 reason code 319 @param rc CONNACK result code or MQTTv5 reason code
304 @type int 320 @type int
305 @param packetType packet type as reported by the client 321 @param packetType packet type as reported by the client
307 @param properties dictionary containing the received connection 323 @param properties dictionary containing the received connection
308 properties 324 properties
309 @type dict 325 @type dict
310 """ 326 """
311 self.brokerStatusLabel.hide() 327 self.brokerStatusLabel.hide()
312 328
313 if rc == 0: 329 if rc == 0:
314 self.__connectedToBroker = True 330 self.__connectedToBroker = True
315 self.__connectionOptions = None 331 self.__connectionOptions = None
316 332
317 try: 333 try:
318 sessionPresent = flags["session present"] == 1 334 sessionPresent = flags["session present"] == 1
319 except KeyError: 335 except KeyError:
320 sessionPresent = False 336 sessionPresent = False
321 337
322 msg = ( 338 msg = (
323 mqttReasonCode(rc, packetType) 339 mqttReasonCode(rc, packetType)
324 if packetType is not None else 340 if packetType is not None
325 mqttConnackMessage(rc) 341 else mqttConnackMessage(rc)
326 ) 342 )
327 if sessionPresent: 343 if sessionPresent:
328 msg = self.tr("{0} - Session still present").format(msg) 344 msg = self.tr("{0} - Session still present").format(msg)
329 self.__flashBrokerStatusLabel(msg) 345 self.__flashBrokerStatusLabel(msg)
330 346
331 if properties: 347 if properties:
332 self.__showProperties("Connect", properties) 348 self.__showProperties("Connect", properties)
333 349
334 self.connectButton.setEnabled(True) 350 self.connectButton.setEnabled(True)
335 if rc == 0: 351 if rc == 0:
336 self.__connectedToBroker = True 352 self.__connectedToBroker = True
337 self.__connectionOptions = None 353 self.__connectionOptions = None
338 354
339 self.connectButton.setIcon( 355 self.connectButton.setIcon(UI.PixmapCache.getIcon("ircDisconnect"))
340 UI.PixmapCache.getIcon("ircDisconnect")) 356
341
342 self.subscribeGroup.setEnabled(True) 357 self.subscribeGroup.setEnabled(True)
343 self.subscribePropertiesButton.setVisible( 358 self.subscribePropertiesButton.setVisible(
344 self.__client.getProtocol() == MqttProtocols.MQTTv5) 359 self.__client.getProtocol() == MqttProtocols.MQTTv5
360 )
345 self.unsubscribeGroup.setEnabled(True) 361 self.unsubscribeGroup.setEnabled(True)
346 self.unsubscribePropertiesButton.setVisible( 362 self.unsubscribePropertiesButton.setVisible(
347 self.__client.getProtocol() == MqttProtocols.MQTTv5) 363 self.__client.getProtocol() == MqttProtocols.MQTTv5
364 )
348 self.publishGroup.setEnabled(True) 365 self.publishGroup.setEnabled(True)
349 self.brokerStatusButton.setEnabled(True) 366 self.brokerStatusButton.setEnabled(True)
350 self.publishPropertiesButton.setVisible( 367 self.publishPropertiesButton.setVisible(
351 self.__client.getProtocol() == MqttProtocols.MQTTv5) 368 self.__client.getProtocol() == MqttProtocols.MQTTv5
352 369 )
370
353 self.__statusLoadValues.clear() 371 self.__statusLoadValues.clear()
354 self.__clearBrokerStatusLabels() 372 self.__clearBrokerStatusLabels()
355 self.__setBrokerStatusSubscribed(False) 373 self.__setBrokerStatusSubscribed(False)
356 else: 374 else:
357 self.__client.stopLoop() 375 self.__client.stopLoop()
358 376
359 @pyqtSlot() 377 @pyqtSlot()
360 def __connectTimeout(self): 378 def __connectTimeout(self):
361 """ 379 """
362 Private slot handling a timeout during a connection attempt. 380 Private slot handling a timeout during a connection attempt.
363 """ 381 """
364 self.__flashBrokerStatusLabel(self.tr("Connection timed out")) 382 self.__flashBrokerStatusLabel(self.tr("Connection timed out"))
365 self.__setConnectButtonState() 383 self.__setConnectButtonState()
366 384
367 @pyqtSlot(int) 385 @pyqtSlot(int)
368 @pyqtSlot(int, int) 386 @pyqtSlot(int, int)
369 def __brokerDisconnected(self, rc, packetType=None): 387 def __brokerDisconnected(self, rc, packetType=None):
370 """ 388 """
371 Private slot to handle a disconnection from the broker. 389 Private slot to handle a disconnection from the broker.
372 390
373 @param rc MQTT error result code 391 @param rc MQTT error result code
374 @type int 392 @type int
375 @param packetType packet type as reported by the client 393 @param packetType packet type as reported by the client
376 @type int 394 @type int
377 """ 395 """
378 self.__connectedToBroker = False 396 self.__connectedToBroker = False
379 397
380 # ensure, the client loop is stopped 398 # ensure, the client loop is stopped
381 self.__client.stopLoop() 399 self.__client.stopLoop()
382 400
383 msg = ( 401 msg = (
384 # MQTT v5 402 # MQTT v5
385 mqttReasonCode(rc, packetType) 403 mqttReasonCode(rc, packetType)
386 if packetType is not None else 404 if packetType is not None
405 else
387 # MQTT v3 406 # MQTT v3
388 ( 407 (
389 mqttErrorMessage(rc) 408 mqttErrorMessage(rc)
390 if rc > 0 else 409 if rc > 0
391 self.tr("Connection to Broker shut down cleanly.") 410 else self.tr("Connection to Broker shut down cleanly.")
392 ) 411 )
393 ) 412 )
394 self.__flashBrokerStatusLabel(msg) 413 self.__flashBrokerStatusLabel(msg)
395 414
396 self.connectButton.setIcon(UI.PixmapCache.getIcon("ircConnect")) 415 self.connectButton.setIcon(UI.PixmapCache.getIcon("ircConnect"))
397 self.__setConnectButtonState() 416 self.__setConnectButtonState()
398 417
399 self.__subscribedTopics = [] 418 self.__subscribedTopics = []
400 self.__topicQueue = {} 419 self.__topicQueue = {}
401 self.__updateUnsubscribeTopicComboBox() 420 self.__updateUnsubscribeTopicComboBox()
402 self.__updatePublishTopicComboBox() 421 self.__updatePublishTopicComboBox()
403 422
404 self.subscribeGroup.setEnabled(False) 423 self.subscribeGroup.setEnabled(False)
405 self.subscribePropertiesButton.setVisible(False) 424 self.subscribePropertiesButton.setVisible(False)
406 self.unsubscribeGroup.setEnabled(False) 425 self.unsubscribeGroup.setEnabled(False)
407 self.unsubscribePropertiesButton.setVisible(False) 426 self.unsubscribePropertiesButton.setVisible(False)
408 self.publishGroup.setEnabled(False) 427 self.publishGroup.setEnabled(False)
409 self.publishPropertiesButton.setVisible(False) 428 self.publishPropertiesButton.setVisible(False)
410 self.brokerStatusButton.setEnabled(False) 429 self.brokerStatusButton.setEnabled(False)
411 430
412 self.__statusLoadValues.clear() 431 self.__statusLoadValues.clear()
413 432
414 @pyqtSlot(int, str) 433 @pyqtSlot(int, str)
415 def __clientLog(self, level, message): 434 def __clientLog(self, level, message):
416 """ 435 """
417 Private slot to handle the receipt of a log message. 436 Private slot to handle the receipt of a log message.
418 437
419 @param level log level 438 @param level log level
420 @type int 439 @type int
421 @param message log message 440 @param message log message
422 @type str 441 @type str
423 """ 442 """
424 with contextlib.suppress(KeyError): 443 with contextlib.suppress(KeyError):
425 if MqttClient.LogLevelMap[level] < self.logLevelComboBox.itemData( 444 if MqttClient.LogLevelMap[level] < self.logLevelComboBox.itemData(
426 self.logLevelComboBox.currentIndex()): 445 self.logLevelComboBox.currentIndex()
446 ):
427 return 447 return
428 448
429 scrollbarValue = self.logEdit.verticalScrollBar().value() 449 scrollbarValue = self.logEdit.verticalScrollBar().value()
430 450
431 textCursor = self.logEdit.textCursor() 451 textCursor = self.logEdit.textCursor()
432 if not self.logEdit.document().isEmpty(): 452 if not self.logEdit.document().isEmpty():
433 textCursor.movePosition(QTextCursor.MoveOperation.End) 453 textCursor.movePosition(QTextCursor.MoveOperation.End)
434 self.logEdit.setTextCursor(textCursor) 454 self.logEdit.setTextCursor(textCursor)
435 self.logEdit.insertPlainText("\n") 455 self.logEdit.insertPlainText("\n")
436 456
437 textBlockFormat = textCursor.blockFormat() 457 textBlockFormat = textCursor.blockFormat()
438 try: 458 try:
439 textBlockFormat.setBackground( 459 textBlockFormat.setBackground(
440 self.__logMessagesBackgrounds[MqttClient.LogLevelMap[level]]) 460 self.__logMessagesBackgrounds[MqttClient.LogLevelMap[level]]
461 )
441 except KeyError: 462 except KeyError:
442 textBlockFormat.setBackground( 463 textBlockFormat.setBackground(
443 self.__logMessagesBackgrounds[MqttClient.LogDisabled]) 464 self.__logMessagesBackgrounds[MqttClient.LogDisabled]
465 )
444 textCursor.setBlockFormat(textBlockFormat) 466 textCursor.setBlockFormat(textBlockFormat)
445 textCursor.movePosition(QTextCursor.MoveOperation.End) 467 textCursor.movePosition(QTextCursor.MoveOperation.End)
446 self.logEdit.setTextCursor(textCursor) 468 self.logEdit.setTextCursor(textCursor)
447 469
448 txt = self.tr("{0}: {1}").format(mqttLogLevelString(level), message) 470 txt = self.tr("{0}: {1}").format(mqttLogLevelString(level), message)
449 self.logEdit.insertPlainText(Utilities.filterAnsiSequences(txt)) 471 self.logEdit.insertPlainText(Utilities.filterAnsiSequences(txt))
450 472
451 if self.followLogMessagesCheckBox.isChecked(): 473 if self.followLogMessagesCheckBox.isChecked():
452 self.logEdit.ensureCursorVisible() 474 self.logEdit.ensureCursorVisible()
453 else: 475 else:
454 self.logEdit.verticalScrollBar().setValue(scrollbarValue) 476 self.logEdit.verticalScrollBar().setValue(scrollbarValue)
455 477
456 @pyqtSlot(str, bytes, int, bool) 478 @pyqtSlot(str, bytes, int, bool)
457 @pyqtSlot(str, bytes, int, bool, dict) 479 @pyqtSlot(str, bytes, int, bool, dict)
458 def __messageReceived(self, topic, payload, qos, retain, properties=None): 480 def __messageReceived(self, topic, payload, qos, retain, properties=None):
459 """ 481 """
460 Private slot to handle the receipt of a message. 482 Private slot to handle the receipt of a message.
461 483
462 @param topic topic of the message 484 @param topic topic of the message
463 @type str 485 @type str
464 @param payload payload (i.e. data) of the message 486 @param payload payload (i.e. data) of the message
465 @type bytes 487 @type bytes
466 @param qos quality of service indicator 488 @param qos quality of service indicator
472 """ 494 """
473 if topic.startswith(MqttMonitorWidget.BrokerStatusTopicPrefix): 495 if topic.startswith(MqttMonitorWidget.BrokerStatusTopicPrefix):
474 # handle broker status messages 496 # handle broker status messages
475 self.__handleBrokerStatusMessage(topic, payload) 497 self.__handleBrokerStatusMessage(topic, payload)
476 else: 498 else:
477 self.__appendMessage(topic, payload, qos, retain, 499 self.__appendMessage(topic, payload, qos, retain, properties=properties)
478 properties=properties) 500
479
480 @pyqtSlot(int) 501 @pyqtSlot(int)
481 def __messagePublished(self, mid): 502 def __messagePublished(self, mid):
482 """ 503 """
483 Private slot to handle a message being published. 504 Private slot to handle a message being published.
484 505
485 @param mid ID of the published message 506 @param mid ID of the published message
486 @type int 507 @type int
487 """ 508 """
488 # nothing to show for this 509 # nothing to show for this
489 pass 510 pass
490 511
491 @pyqtSlot(int) 512 @pyqtSlot(int)
492 def __topicSubscribed(self, mid): 513 def __topicSubscribed(self, mid):
493 """ 514 """
494 Private slot to handle being subscribed to topics (MQTT v3.1, 515 Private slot to handle being subscribed to topics (MQTT v3.1,
495 MQTT v3.1.1). 516 MQTT v3.1.1).
496 517
497 @param mid ID of the subscribe request 518 @param mid ID of the subscribe request
498 @type int 519 @type int
499 """ 520 """
500 if mid in self.__topicQueue: 521 if mid in self.__topicQueue:
501 topic = self.__topicQueue.pop(mid) 522 topic = self.__topicQueue.pop(mid)
502 self.__subscribedTopics.append(topic) 523 self.__subscribedTopics.append(topic)
503 self.__addTopicToRecent(topic) 524 self.__addTopicToRecent(topic)
504 525
505 self.__updateUnsubscribeTopicComboBox() 526 self.__updateUnsubscribeTopicComboBox()
506 self.__updatePublishTopicComboBox() 527 self.__updatePublishTopicComboBox()
507 528
508 @pyqtSlot(int, list, dict) 529 @pyqtSlot(int, list, dict)
509 def __topicSubscribedV5(self, mid, reasonCodes, properties): 530 def __topicSubscribedV5(self, mid, reasonCodes, properties):
510 """ 531 """
511 Private slot to handle being subscribed to topics (MQTT v5). 532 Private slot to handle being subscribed to topics (MQTT v5).
512 533
513 @param mid ID of the subscribe request 534 @param mid ID of the subscribe request
514 @type int 535 @type int
515 @param reasonCodes list of reason codes, one for each topic 536 @param reasonCodes list of reason codes, one for each topic
516 @type list of ReasonCodes 537 @type list of ReasonCodes
517 @param properties dictionary containing the received subscribe 538 @param properties dictionary containing the received subscribe
518 properties 539 properties
519 @type dict 540 @type dict
520 """ 541 """
521 msg = mqttReasonCode(reasonCodes[0].value, reasonCodes[0].packetType) 542 msg = mqttReasonCode(reasonCodes[0].value, reasonCodes[0].packetType)
522 self.__flashBrokerStatusLabel(msg) 543 self.__flashBrokerStatusLabel(msg)
523 544
524 if properties: 545 if properties:
525 self.__showProperties("Subscribe", properties) 546 self.__showProperties("Subscribe", properties)
526 547
527 self.__topicSubscribed(mid) 548 self.__topicSubscribed(mid)
528 549
529 @pyqtSlot(int) 550 @pyqtSlot(int)
530 def __topicUnsubscribed(self, mid): 551 def __topicUnsubscribed(self, mid):
531 """ 552 """
532 Private slot to handle being unsubcribed from a topic (MQTT v3.1, 553 Private slot to handle being unsubcribed from a topic (MQTT v3.1,
533 MQTT v3.1.1). 554 MQTT v3.1.1).
534 555
535 @param mid ID of the unsubscribe request 556 @param mid ID of the unsubscribe request
536 @type int 557 @type int
537 """ 558 """
538 if mid in self.__topicQueue: 559 if mid in self.__topicQueue:
539 topic = self.__topicQueue.pop(mid) 560 topic = self.__topicQueue.pop(mid)
540 with contextlib.suppress(ValueError): 561 with contextlib.suppress(ValueError):
541 self.__subscribedTopics.remove(topic) 562 self.__subscribedTopics.remove(topic)
542 self.__updateUnsubscribeTopicComboBox() 563 self.__updateUnsubscribeTopicComboBox()
543 self.__updatePublishTopicComboBox() 564 self.__updatePublishTopicComboBox()
544 565
545 @pyqtSlot(int, int, int, dict) 566 @pyqtSlot(int, int, int, dict)
546 def __topicUnsubscribedV5(self, mid, rc, packetType, properties): 567 def __topicUnsubscribedV5(self, mid, rc, packetType, properties):
547 """ 568 """
548 Private slot to handle being unsubscribed to topics (MQTT v5). 569 Private slot to handle being unsubscribed to topics (MQTT v5).
549 570
550 @param mid ID of the subscribe request 571 @param mid ID of the subscribe request
551 @type int 572 @type int
552 @param rc MQTTv5 reason code 573 @param rc MQTTv5 reason code
553 @type int 574 @type int
554 @param packetType packet type as reported by the client 575 @param packetType packet type as reported by the client
557 properties 578 properties
558 @type dict 579 @type dict
559 """ 580 """
560 msg = mqttReasonCode(rc, packetType) 581 msg = mqttReasonCode(rc, packetType)
561 self.__flashBrokerStatusLabel(msg) 582 self.__flashBrokerStatusLabel(msg)
562 583
563 if properties: 584 if properties:
564 self.__showProperties("Unsubscribe", properties) 585 self.__showProperties("Unsubscribe", properties)
565 586
566 self.__topicUnsubscribed(mid) 587 self.__topicUnsubscribed(mid)
567 588
568 ####################################################################### 589 #######################################################################
569 ## Slots handling UI interactions 590 ## Slots handling UI interactions
570 ####################################################################### 591 #######################################################################
571 592
572 @pyqtSlot() 593 @pyqtSlot()
573 def __flashBrokerStatusLabel(self, message): 594 def __flashBrokerStatusLabel(self, message):
574 """ 595 """
575 Private slot to show the broker status label with some text for 596 Private slot to show the broker status label with some text for
576 5 seconds. 597 5 seconds.
577 598
578 @param message message to be shown 599 @param message message to be shown
579 @type str 600 @type str
580 """ 601 """
581 self.brokerStatusLabel.setText(message) 602 self.brokerStatusLabel.setText(message)
582 self.brokerStatusLabel.show() 603 self.brokerStatusLabel.show()
583 QTimer.singleShot(5000, self.brokerStatusLabel.hide) 604 QTimer.singleShot(5000, self.brokerStatusLabel.hide)
584 605
585 @pyqtSlot() 606 @pyqtSlot()
586 def on_modeButton_clicked(self): 607 def on_modeButton_clicked(self):
587 """ 608 """
588 Private slot to switch between connection profiles and direct 609 Private slot to switch between connection profiles and direct
589 connection mode. 610 connection mode.
590 """ 611 """
591 self.__setConnectionMode(not self.__connectionModeProfile) 612 self.__setConnectionMode(not self.__connectionModeProfile)
592 613
593 @pyqtSlot(str) 614 @pyqtSlot(str)
594 def on_profileComboBox_currentIndexChanged(self, profileName): 615 def on_profileComboBox_currentIndexChanged(self, profileName):
595 """ 616 """
596 Private slot handling the change of the selected profile. 617 Private slot handling the change of the selected profile.
597 618
598 @param profileName name of the selected profile 619 @param profileName name of the selected profile
599 @type str 620 @type str
600 """ 621 """
601 self.__setConnectButtonState() 622 self.__setConnectButtonState()
602 623
603 @pyqtSlot(str) 624 @pyqtSlot(str)
604 def on_brokerComboBox_editTextChanged(self, host): 625 def on_brokerComboBox_editTextChanged(self, host):
605 """ 626 """
606 Private slot to handling entering or selecting a broker host name. 627 Private slot to handling entering or selecting a broker host name.
607 628
608 @param host host name of the broker 629 @param host host name of the broker
609 @type str 630 @type str
610 """ 631 """
611 self.__setConnectButtonState() 632 self.__setConnectButtonState()
612 633
613 @pyqtSlot() 634 @pyqtSlot()
614 def on_brokerConnectionOptionsButton_clicked(self): 635 def on_brokerConnectionOptionsButton_clicked(self):
615 """ 636 """
616 Private slot to show a dialog to modify connection options or a 637 Private slot to show a dialog to modify connection options or a
617 dialog to edit connection profiles. 638 dialog to edit connection profiles.
618 """ 639 """
619 if self.__connectionModeProfile: 640 if self.__connectionModeProfile:
620 from .MqttConnectionProfilesDialog import ( 641 from .MqttConnectionProfilesDialog import MqttConnectionProfilesDialog
621 MqttConnectionProfilesDialog 642
622 )
623 profileName = self.profileComboBox.currentText() 643 profileName = self.profileComboBox.currentText()
624 dlg = MqttConnectionProfilesDialog( 644 dlg = MqttConnectionProfilesDialog(
625 self.__plugin.getPreferences("BrokerProfiles"), 645 self.__plugin.getPreferences("BrokerProfiles"),
626 currentProfile=profileName, parent=self) 646 currentProfile=profileName,
647 parent=self,
648 )
627 if dlg.exec() == QDialog.DialogCode.Accepted: 649 if dlg.exec() == QDialog.DialogCode.Accepted:
628 profilesDict = dlg.getProfiles() 650 profilesDict = dlg.getProfiles()
629 self.__plugin.setPreferences("BrokerProfiles", profilesDict) 651 self.__plugin.setPreferences("BrokerProfiles", profilesDict)
630 self.__populateProfileComboBox() 652 self.__populateProfileComboBox()
631 else: 653 else:
632 from .MqttConnectionOptionsDialog import ( 654 from .MqttConnectionOptionsDialog import MqttConnectionOptionsDialog
633 MqttConnectionOptionsDialog 655
634 ) 656 dlg = MqttConnectionOptionsDialog(self.__connectionOptions, parent=self)
635 dlg = MqttConnectionOptionsDialog(
636 self.__connectionOptions, parent=self)
637 if dlg.exec() == QDialog.DialogCode.Accepted: 657 if dlg.exec() == QDialog.DialogCode.Accepted:
638 self.__connectionOptions = dlg.getConnectionOptions() 658 self.__connectionOptions = dlg.getConnectionOptions()
639 if self.__connectionOptions["TlsEnable"]: 659 if self.__connectionOptions["TlsEnable"]:
640 port = self.brokerPortComboBox.currentText().strip() 660 port = self.brokerPortComboBox.currentText().strip()
641 if port == "1883": 661 if port == "1883":
644 else: 664 else:
645 port = self.brokerPortComboBox.currentText().strip() 665 port = self.brokerPortComboBox.currentText().strip()
646 if port == "8883": 666 if port == "8883":
647 # it is default TLS port => set to non-encrypted port 667 # it is default TLS port => set to non-encrypted port
648 self.brokerPortComboBox.setEditText("1883") 668 self.brokerPortComboBox.setEditText("1883")
649 669
650 @pyqtSlot() 670 @pyqtSlot()
651 def on_connectButton_clicked(self): 671 def on_connectButton_clicked(self):
652 """ 672 """
653 Private slot to handle a connect or disconnect request. 673 Private slot to handle a connect or disconnect request.
654 """ 674 """
657 else: 677 else:
658 if self.__connectionModeProfile: 678 if self.__connectionModeProfile:
659 self.__profileConnectToBroker() 679 self.__profileConnectToBroker()
660 else: 680 else:
661 self.__directConnectToBroker() 681 self.__directConnectToBroker()
662 682
663 @pyqtSlot() 683 @pyqtSlot()
664 def on_subscribePropertiesButton_clicked(self): 684 def on_subscribePropertiesButton_clicked(self):
665 """ 685 """
666 Private slot to edit the subscribe user properties. 686 Private slot to edit the subscribe user properties.
667 """ 687 """
668 topic = self.subscribeTopicComboBox.currentText() 688 topic = self.subscribeTopicComboBox.currentText()
669 self.__editProperties( 689 self.__editProperties(
670 "subscribe", 690 "subscribe",
671 self.tr("SUBSCRIBE: User Properties for '{0}'").format(topic), 691 self.tr("SUBSCRIBE: User Properties for '{0}'").format(topic),
672 topic 692 topic,
673 ) 693 )
674 694
675 @pyqtSlot(str) 695 @pyqtSlot(str)
676 def on_subscribeTopicComboBox_editTextChanged(self, topic): 696 def on_subscribeTopicComboBox_editTextChanged(self, topic):
677 """ 697 """
678 Private slot to handle a change of the entered topic. 698 Private slot to handle a change of the entered topic.
679 699
680 @param topic entered topic text 700 @param topic entered topic text
681 @type str 701 @type str
682 """ 702 """
683 self.subscribeButton.setEnabled(bool(topic)) 703 self.subscribeButton.setEnabled(bool(topic))
684 self.subscribePropertiesButton.setEnabled(bool(topic)) 704 self.subscribePropertiesButton.setEnabled(bool(topic))
685 705
686 @pyqtSlot() 706 @pyqtSlot()
687 def on_subscribeButton_clicked(self): 707 def on_subscribeButton_clicked(self):
688 """ 708 """
689 Private slot to subscribe to the entered topic. 709 Private slot to subscribe to the entered topic.
690 """ 710 """
693 if topic: 713 if topic:
694 if topic.startswith(MqttMonitorWidget.BrokerStatusTopicPrefix): 714 if topic.startswith(MqttMonitorWidget.BrokerStatusTopicPrefix):
695 EricMessageBox.warning( 715 EricMessageBox.warning(
696 self, 716 self,
697 self.tr("Subscribe to Topic"), 717 self.tr("Subscribe to Topic"),
698 self.tr("Subscriptions to the Status topic '$SYS' shall" 718 self.tr(
699 " be done on the 'Status' tab.")) 719 "Subscriptions to the Status topic '$SYS' shall"
720 " be done on the 'Status' tab."
721 ),
722 )
700 else: 723 else:
701 properties = ( 724 properties = (
702 self.__plugin.getPreferences("SubscribeProperties") 725 self.__plugin.getPreferences("SubscribeProperties").get(topic, [])
703 .get(topic, []) 726 if self.__client.getProtocol() == MqttProtocols.MQTTv5
704 if self.__client.getProtocol() == MqttProtocols.MQTTv5 else 727 else None
705 None
706 ) 728 )
707 result, mid = self.__client.subscribe( 729 result, mid = self.__client.subscribe(
708 topic, qos=qos, properties=properties) 730 topic, qos=qos, properties=properties
731 )
709 self.__topicQueue[mid] = topic 732 self.__topicQueue[mid] = topic
710 733
711 @pyqtSlot() 734 @pyqtSlot()
712 def on_unsubscribePropertiesButton_clicked(self): 735 def on_unsubscribePropertiesButton_clicked(self):
713 """ 736 """
714 Private slot to edit the unsubscribe user properties. 737 Private slot to edit the unsubscribe user properties.
715 """ 738 """
716 topic = self.unsubscribeTopicComboBox.currentText() 739 topic = self.unsubscribeTopicComboBox.currentText()
717 self.__editProperties( 740 self.__editProperties(
718 "unsubscribe", 741 "unsubscribe",
719 self.tr("UNSUBSCRIBE: User Properties for '{0}'").format(topic), 742 self.tr("UNSUBSCRIBE: User Properties for '{0}'").format(topic),
720 topic 743 topic,
721 ) 744 )
722 745
723 @pyqtSlot(str) 746 @pyqtSlot(str)
724 def on_unsubscribeTopicComboBox_currentIndexChanged(self, topic): 747 def on_unsubscribeTopicComboBox_currentIndexChanged(self, topic):
725 """ 748 """
726 Private slot to handle the selection of a topic to unsubscribe from. 749 Private slot to handle the selection of a topic to unsubscribe from.
727 750
728 @param topic topic text 751 @param topic topic text
729 @type str 752 @type str
730 """ 753 """
731 self.unsubscribeButton.setEnabled(bool(topic)) 754 self.unsubscribeButton.setEnabled(bool(topic))
732 self.unsubscribePropertiesButton.setEnabled(bool(topic)) 755 self.unsubscribePropertiesButton.setEnabled(bool(topic))
733 756
734 @pyqtSlot() 757 @pyqtSlot()
735 def on_unsubscribeButton_clicked(self): 758 def on_unsubscribeButton_clicked(self):
736 """ 759 """
737 Private slot to unsubscribe from the selected topic. 760 Private slot to unsubscribe from the selected topic.
738 """ 761 """
739 topic = self.unsubscribeTopicComboBox.currentText() 762 topic = self.unsubscribeTopicComboBox.currentText()
740 if topic: 763 if topic:
741 properties = ( 764 properties = (
742 self.__plugin.getPreferences("SubscribeProperties") 765 self.__plugin.getPreferences("SubscribeProperties").get(topic, [])
743 .get(topic, []) 766 if self.__client.getProtocol() == MqttProtocols.MQTTv5
744 if self.__client.getProtocol() == MqttProtocols.MQTTv5 else 767 else None
745 None 768 )
746 ) 769 result, mid = self.__client.unsubscribe(topic, properties=properties)
747 result, mid = self.__client.unsubscribe(
748 topic, properties=properties)
749 self.__topicQueue[mid] = topic 770 self.__topicQueue[mid] = topic
750 771
751 @pyqtSlot() 772 @pyqtSlot()
752 def on_publishPropertiesButton_clicked(self): 773 def on_publishPropertiesButton_clicked(self):
753 """ 774 """
754 Private slot to edit the publish user properties. 775 Private slot to edit the publish user properties.
755 """ 776 """
756 topic = self.publishTopicComboBox.currentText() 777 topic = self.publishTopicComboBox.currentText()
757 self.__editProperties( 778 self.__editProperties(
758 "publish", 779 "publish",
759 self.tr("PUBLISH: User Properties for '{0}'").format(topic), 780 self.tr("PUBLISH: User Properties for '{0}'").format(topic),
760 topic 781 topic,
761 ) 782 )
762 783
763 @pyqtSlot(str) 784 @pyqtSlot(str)
764 def on_publishTopicComboBox_editTextChanged(self, topic): 785 def on_publishTopicComboBox_editTextChanged(self, topic):
765 """ 786 """
766 Private slot to handle changes of the publish topic name. 787 Private slot to handle changes of the publish topic name.
767 788
768 @param topic topic text 789 @param topic topic text
769 @type str 790 @type str
770 """ 791 """
771 self.publishButton.setEnabled(bool(topic)) 792 self.publishButton.setEnabled(bool(topic))
772 self.publishPropertiesButton.setEnabled(bool(topic)) 793 self.publishPropertiesButton.setEnabled(bool(topic))
773 794
774 @pyqtSlot() 795 @pyqtSlot()
775 def on_publishButton_clicked(self): 796 def on_publishButton_clicked(self):
776 """ 797 """
777 Private slot to publish the entered message. 798 Private slot to publish the entered message.
778 """ 799 """
779 topic = self.publishTopicComboBox.currentText() 800 topic = self.publishTopicComboBox.currentText()
780 qos = self.publishQosSpinBox.value() 801 qos = self.publishQosSpinBox.value()
781 retain = self.publishRetainCheckBox.isChecked() 802 retain = self.publishRetainCheckBox.isChecked()
782 payloadFile = self.publishPayloadFilePicker.text() 803 payloadFile = self.publishPayloadFilePicker.text()
783 if ( 804 if (
784 bool(payloadFile) and 805 bool(payloadFile)
785 os.path.exists(payloadFile) and 806 and os.path.exists(payloadFile)
786 os.path.getsize(payloadFile) <= 268435455 807 and os.path.getsize(payloadFile) <= 268435455
787 ): 808 ):
788 # payload size limit is 268,435,455 bytes 809 # payload size limit is 268,435,455 bytes
789 try: 810 try:
790 with open(payloadFile, "rb") as f: 811 with open(payloadFile, "rb") as f:
791 payloadStr = f.read() 812 payloadStr = f.read()
792 except EnvironmentError as err: 813 except EnvironmentError as err:
793 EricMessageBox.critical( 814 EricMessageBox.critical(
794 self, 815 self,
795 self.tr("Read Payload from File"), 816 self.tr("Read Payload from File"),
796 self.tr("""<p>The file <b>{0}</b> could not be read.""" 817 self.tr(
797 """ Aborting...</p><p>Reason: {1}</p>""").format( 818 """<p>The file <b>{0}</b> could not be read."""
798 payloadFile, str(err))) 819 """ Aborting...</p><p>Reason: {1}</p>"""
820 ).format(payloadFile, str(err)),
821 )
799 return 822 return
800 else: 823 else:
801 payloadStr = self.publishPayloadEdit.toPlainText() 824 payloadStr = self.publishPayloadEdit.toPlainText()
802 if not payloadStr: 825 if not payloadStr:
803 # use empty string together with the retain flag to clean 826 # use empty string together with the retain flag to clean
804 # a retained message by sending None instead 827 # a retained message by sending None instead
805 payloadStr = None 828 payloadStr = None
806 properties = ( 829 properties = (
807 self.__plugin.getPreferences("PublishProperties").get(topic, []) 830 self.__plugin.getPreferences("PublishProperties").get(topic, [])
808 if self.__client.getProtocol() == MqttProtocols.MQTTv5 else 831 if self.__client.getProtocol() == MqttProtocols.MQTTv5
809 None 832 else None
810 ) 833 )
811 834
812 msgInfo = self.__client.publish( 835 msgInfo = self.__client.publish(
813 topic, payload=payloadStr, qos=qos, retain=retain, 836 topic, payload=payloadStr, qos=qos, retain=retain, properties=properties
814 properties=properties) 837 )
815 if msgInfo.rc == 0: 838 if msgInfo.rc == 0:
816 if topic not in self.__publishedTopics: 839 if topic not in self.__publishedTopics:
817 self.__publishedTopics.append(topic) 840 self.__publishedTopics.append(topic)
818 self.__updatePublishTopicComboBox(resetTopic=False) 841 self.__updatePublishTopicComboBox(resetTopic=False)
819 if self.clearPublishCheckBox.isChecked(): 842 if self.clearPublishCheckBox.isChecked():
820 self.on_publishClearButton_clicked() 843 self.on_publishClearButton_clicked()
821 844
822 @pyqtSlot() 845 @pyqtSlot()
823 def on_publishClearRetainedButton_clicked(self): 846 def on_publishClearRetainedButton_clicked(self):
824 """ 847 """
825 Private slot to clear the retained messages for the topic. 848 Private slot to clear the retained messages for the topic.
826 """ 849 """
827 topic = self.publishTopicComboBox.currentText() 850 topic = self.publishTopicComboBox.currentText()
828 properties = ( 851 properties = (
829 self.__plugin.getPreferences("PublishProperties").get(topic, []) 852 self.__plugin.getPreferences("PublishProperties").get(topic, [])
830 if self.__client.getProtocol() == MqttProtocols.MQTTv5 else 853 if self.__client.getProtocol() == MqttProtocols.MQTTv5
831 None 854 else None
832 ) 855 )
833 856
834 msgInfo = self.__client.publish( 857 msgInfo = self.__client.publish(
835 topic, payload=None, retain=True, properties=properties) 858 topic, payload=None, retain=True, properties=properties
859 )
836 if msgInfo.rc == 0: 860 if msgInfo.rc == 0:
837 if topic not in self.__publishedTopics: 861 if topic not in self.__publishedTopics:
838 self.__publishedTopics.append(topic) 862 self.__publishedTopics.append(topic)
839 self.__updatePublishTopicComboBox(resetTopic=False) 863 self.__updatePublishTopicComboBox(resetTopic=False)
840 864
841 @pyqtSlot() 865 @pyqtSlot()
842 def on_publishClearButton_clicked(self): 866 def on_publishClearButton_clicked(self):
843 """ 867 """
844 Private slot to clear the publish data fields. 868 Private slot to clear the publish data fields.
845 """ 869 """
846 self.publishTopicComboBox.clearEditText() 870 self.publishTopicComboBox.clearEditText()
847 self.publishPayloadEdit.clear() 871 self.publishPayloadEdit.clear()
848 self.publishQosSpinBox.setValue(0) 872 self.publishQosSpinBox.setValue(0)
849 self.publishRetainCheckBox.setChecked(False) 873 self.publishRetainCheckBox.setChecked(False)
850 self.publishPayloadFilePicker.clear() 874 self.publishPayloadFilePicker.clear()
851 875
852 @pyqtSlot(str) 876 @pyqtSlot(str)
853 def on_publishPayloadFilePicker_textChanged(self, path): 877 def on_publishPayloadFilePicker_textChanged(self, path):
854 """ 878 """
855 Private slot handling a change of path of the payload file. 879 Private slot handling a change of path of the payload file.
856 880
857 @param path path of the payload file 881 @param path path of the payload file
858 @type str 882 @type str
859 """ 883 """
860 self.publishPayloadEdit.setEnabled(not bool(path)) 884 self.publishPayloadEdit.setEnabled(not bool(path))
861 885
862 @pyqtSlot(QPoint) 886 @pyqtSlot(QPoint)
863 def on_propertiesEdit_customContextMenuRequested(self, pos): 887 def on_propertiesEdit_customContextMenuRequested(self, pos):
864 """ 888 """
865 Private slot to show the context menu for the properties output. 889 Private slot to show the context menu for the properties output.
866 890
867 @param pos the position of the mouse pointer 891 @param pos the position of the mouse pointer
868 @type QPoint 892 @type QPoint
869 """ 893 """
870 self.__propertiesEditMenu.popup(self.propertiesEdit.mapToGlobal(pos)) 894 self.__propertiesEditMenu.popup(self.propertiesEdit.mapToGlobal(pos))
871 895
872 @pyqtSlot() 896 @pyqtSlot()
873 def on_brokerStatusButton_clicked(self): 897 def on_brokerStatusButton_clicked(self):
874 """ 898 """
875 Private slot to subscribe or unsubscribe the broker status topic. 899 Private slot to subscribe or unsubscribe the broker status topic.
876 """ 900 """
877 if self.__brokerStatusTopicSubscribed: 901 if self.__brokerStatusTopicSubscribed:
878 # unsubscribe status topic 902 # unsubscribe status topic
879 rc, _ = self.__client.unsubscribe( 903 rc, _ = self.__client.unsubscribe(MqttMonitorWidget.BrokerStatusTopic)
880 MqttMonitorWidget.BrokerStatusTopic)
881 if rc == 0: 904 if rc == 0:
882 # successfully sent 905 # successfully sent
883 self.__setBrokerStatusSubscribed(False) 906 self.__setBrokerStatusSubscribed(False)
884 else: 907 else:
885 # subscribe status topic 908 # subscribe status topic
886 rc, _ = self.__client.subscribe( 909 rc, _ = self.__client.subscribe(MqttMonitorWidget.BrokerStatusTopic)
887 MqttMonitorWidget.BrokerStatusTopic)
888 if rc == 0: 910 if rc == 0:
889 # successfully sent 911 # successfully sent
890 self.__setBrokerStatusSubscribed(True) 912 self.__setBrokerStatusSubscribed(True)
891 913
892 @pyqtSlot(int) 914 @pyqtSlot(int)
893 def on_messagesEdit_blockCountChanged(self, newBlockCount): 915 def on_messagesEdit_blockCountChanged(self, newBlockCount):
894 """ 916 """
895 Private slot handling changes of received messages. 917 Private slot handling changes of received messages.
896 918
897 @param newBlockCount (ignored) 919 @param newBlockCount (ignored)
898 @type int 920 @type int
899 """ 921 """
900 enable = not self.messagesEdit.document().isEmpty() 922 enable = not self.messagesEdit.document().isEmpty()
901 self.saveMessagesButton.setEnabled(enable) 923 self.saveMessagesButton.setEnabled(enable)
902 self.clearMessagesButton.setEnabled(enable) 924 self.clearMessagesButton.setEnabled(enable)
903 925
904 @pyqtSlot() 926 @pyqtSlot()
905 def on_saveMessagesButton_clicked(self): 927 def on_saveMessagesButton_clicked(self):
906 """ 928 """
907 Private slot to save the received messages. 929 Private slot to save the received messages.
908 """ 930 """
910 self, 932 self,
911 self.tr("Save Messages"), 933 self.tr("Save Messages"),
912 "", 934 "",
913 self.tr("Messages Files (*.txt);;All Files (*)"), 935 self.tr("Messages Files (*.txt);;All Files (*)"),
914 "", 936 "",
915 EricFileDialog.DontConfirmOverwrite) 937 EricFileDialog.DontConfirmOverwrite,
916 938 )
939
917 if fn: 940 if fn:
918 if fn.endswith("."): 941 if fn.endswith("."):
919 fn = fn[:-1] 942 fn = fn[:-1]
920 943
921 ext = QFileInfo(fn).suffix() 944 ext = QFileInfo(fn).suffix()
922 if not ext: 945 if not ext:
923 ex = selectedFilter.split("(*")[1].split(")")[0] 946 ex = selectedFilter.split("(*")[1].split(")")[0]
924 if ex: 947 if ex:
925 fn += ex 948 fn += ex
926 if QFileInfo(fn).exists(): 949 if QFileInfo(fn).exists():
927 res = EricMessageBox.yesNo( 950 res = EricMessageBox.yesNo(
928 self, 951 self,
929 self.tr("Save Messages"), 952 self.tr("Save Messages"),
930 self.tr("<p>The file <b>{0}</b> already exists." 953 self.tr(
931 " Overwrite it?</p>").format(fn), 954 "<p>The file <b>{0}</b> already exists." " Overwrite it?</p>"
932 icon=EricMessageBox.Warning) 955 ).format(fn),
956 icon=EricMessageBox.Warning,
957 )
933 if not res: 958 if not res:
934 return 959 return
935 960
936 fn = Utilities.toNativeSeparators(fn) 961 fn = Utilities.toNativeSeparators(fn)
937 try: 962 try:
938 with open(fn, "w") as f: 963 with open(fn, "w") as f:
939 f.write(self.messagesEdit.toPlainText()) 964 f.write(self.messagesEdit.toPlainText())
940 except EnvironmentError as err: 965 except EnvironmentError as err:
941 EricMessageBox.critical( 966 EricMessageBox.critical(
942 self, 967 self,
943 self.tr("Save Messages"), 968 self.tr("Save Messages"),
944 self.tr("""<p>The file <b>{0}</b> could not be written.""" 969 self.tr(
945 """</p><p>Reason: {1}</p>""").format( 970 """<p>The file <b>{0}</b> could not be written."""
946 fn, str(err))) 971 """</p><p>Reason: {1}</p>"""
947 972 ).format(fn, str(err)),
973 )
974
948 @pyqtSlot(int) 975 @pyqtSlot(int)
949 def on_logEdit_blockCountChanged(self, newBlockCount): 976 def on_logEdit_blockCountChanged(self, newBlockCount):
950 """ 977 """
951 Private slot handling changes of received messages. 978 Private slot handling changes of received messages.
952 979
953 @param newBlockCount (ignored) 980 @param newBlockCount (ignored)
954 @type int 981 @type int
955 """ 982 """
956 enable = not self.logEdit.document().isEmpty() 983 enable = not self.logEdit.document().isEmpty()
957 self.saveLogMessagesButton.setEnabled(enable) 984 self.saveLogMessagesButton.setEnabled(enable)
958 self.clearLogMessagesButton.setEnabled(enable) 985 self.clearLogMessagesButton.setEnabled(enable)
959 986
960 @pyqtSlot() 987 @pyqtSlot()
961 def on_saveLogMessagesButton_clicked(self): 988 def on_saveLogMessagesButton_clicked(self):
962 """ 989 """
963 Private slot to save the log messages. 990 Private slot to save the log messages.
964 """ 991 """
966 self, 993 self,
967 self.tr("Save Log Messages"), 994 self.tr("Save Log Messages"),
968 "", 995 "",
969 self.tr("Log Files (*.log);;All Files (*)"), 996 self.tr("Log Files (*.log);;All Files (*)"),
970 "", 997 "",
971 EricFileDialog.DontConfirmOverwrite) 998 EricFileDialog.DontConfirmOverwrite,
972 999 )
1000
973 if fn: 1001 if fn:
974 if fn.endswith("."): 1002 if fn.endswith("."):
975 fn = fn[:-1] 1003 fn = fn[:-1]
976 1004
977 ext = QFileInfo(fn).suffix() 1005 ext = QFileInfo(fn).suffix()
978 if not ext: 1006 if not ext:
979 ex = selectedFilter.split("(*")[1].split(")")[0] 1007 ex = selectedFilter.split("(*")[1].split(")")[0]
980 if ex: 1008 if ex:
981 fn += ex 1009 fn += ex
982 if QFileInfo(fn).exists(): 1010 if QFileInfo(fn).exists():
983 res = EricMessageBox.yesNo( 1011 res = EricMessageBox.yesNo(
984 self, 1012 self,
985 self.tr("Save Log Messages"), 1013 self.tr("Save Log Messages"),
986 self.tr("<p>The file <b>{0}</b> already exists." 1014 self.tr(
987 " Overwrite it?</p>").format(fn), 1015 "<p>The file <b>{0}</b> already exists." " Overwrite it?</p>"
988 icon=EricMessageBox.Warning) 1016 ).format(fn),
1017 icon=EricMessageBox.Warning,
1018 )
989 if not res: 1019 if not res:
990 return 1020 return
991 1021
992 fn = Utilities.toNativeSeparators(fn) 1022 fn = Utilities.toNativeSeparators(fn)
993 try: 1023 try:
994 with open(fn, "w") as f: 1024 with open(fn, "w") as f:
995 f.write(self.logEdit.toPlainText()) 1025 f.write(self.logEdit.toPlainText())
996 except EnvironmentError as err: 1026 except EnvironmentError as err:
997 EricMessageBox.critical( 1027 EricMessageBox.critical(
998 self, 1028 self,
999 self.tr("Save Log Messages"), 1029 self.tr("Save Log Messages"),
1000 self.tr("""<p>The file <b>{0}</b> could not be written.""" 1030 self.tr(
1001 """</p><p>Reason: {1}</p>""").format( 1031 """<p>The file <b>{0}</b> could not be written."""
1002 fn, str(err))) 1032 """</p><p>Reason: {1}</p>"""
1003 1033 ).format(fn, str(err)),
1034 )
1035
1004 ####################################################################### 1036 #######################################################################
1005 ## Utility methods 1037 ## Utility methods
1006 ####################################################################### 1038 #######################################################################
1007 1039
1008 def __setBrokerStatusSubscribed(self, subscribed): 1040 def __setBrokerStatusSubscribed(self, subscribed):
1009 """ 1041 """
1010 Private method to set the subscription status for the broker status 1042 Private method to set the subscription status for the broker status
1011 topics. 1043 topics.
1012 1044
1013 @param subscribed subscription status for the broker status topics 1045 @param subscribed subscription status for the broker status topics
1014 @type bool 1046 @type bool
1015 """ 1047 """
1016 self.__brokerStatusTopicSubscribed = subscribed 1048 self.__brokerStatusTopicSubscribed = subscribed
1017 if subscribed: 1049 if subscribed:
1018 self.brokerStatusButton.setText(self.tr("Unsubscribe")) 1050 self.brokerStatusButton.setText(self.tr("Unsubscribe"))
1019 self.brokerStatusButton.setToolTip( 1051 self.brokerStatusButton.setToolTip(
1020 self.tr("Press to deactivate the status display")) 1052 self.tr("Press to deactivate the status display")
1053 )
1021 else: 1054 else:
1022 self.brokerStatusButton.setText(self.tr("Subscribe")) 1055 self.brokerStatusButton.setText(self.tr("Subscribe"))
1023 self.brokerStatusButton.setToolTip( 1056 self.brokerStatusButton.setToolTip(
1024 self.tr("Press to activate the status display")) 1057 self.tr("Press to activate the status display")
1025 1058 )
1059
1026 def __addBrokerToRecent(self, host, port): 1060 def __addBrokerToRecent(self, host, port):
1027 """ 1061 """
1028 Private method to add a host name to the list of recently connected 1062 Private method to add a host name to the list of recently connected
1029 brokers. 1063 brokers.
1030 1064
1031 @param host host name of broker 1065 @param host host name of broker
1032 @type str 1066 @type str
1033 @param port port number of the connection 1067 @param port port number of the connection
1034 @type int 1068 @type int
1035 """ 1069 """
1040 brokerList.insert(0, hostAndPort) 1074 brokerList.insert(0, hostAndPort)
1041 # limit the most recently used entries 1075 # limit the most recently used entries
1042 maxBrokers = self.__plugin.getPreferences("RecentBrokersNumber") 1076 maxBrokers = self.__plugin.getPreferences("RecentBrokersNumber")
1043 brokerList = brokerList[:maxBrokers] 1077 brokerList = brokerList[:maxBrokers]
1044 self.__plugin.setPreferences("RecentBrokersWithPort", brokerList) 1078 self.__plugin.setPreferences("RecentBrokersWithPort", brokerList)
1045 1079
1046 self.__populateBrokerComboBoxes() 1080 self.__populateBrokerComboBoxes()
1047 1081
1048 def __populateBrokerComboBoxes(self): 1082 def __populateBrokerComboBoxes(self):
1049 """ 1083 """
1050 Private method to populate the broker name and port combo boxes. 1084 Private method to populate the broker name and port combo boxes.
1051 """ 1085 """
1052 brokerPortList = self.__plugin.getPreferences("RecentBrokersWithPort") 1086 brokerPortList = self.__plugin.getPreferences("RecentBrokersWithPort")
1053 1087
1054 # step 1: clear combo boxes 1088 # step 1: clear combo boxes
1055 self.brokerComboBox.clear() 1089 self.brokerComboBox.clear()
1056 self.brokerPortComboBox.clear() 1090 self.brokerPortComboBox.clear()
1057 1091
1058 # step 2a: populate the broker name list 1092 # step 2a: populate the broker name list
1059 currentBroker = brokerPortList[0][0] if brokerPortList else "" 1093 currentBroker = brokerPortList[0][0] if brokerPortList else ""
1060 brokerSet = {b[0].strip() for b in brokerPortList} 1094 brokerSet = {b[0].strip() for b in brokerPortList}
1061 self.brokerComboBox.addItems(sorted(brokerSet)) 1095 self.brokerComboBox.addItems(sorted(brokerSet))
1062 index = self.brokerComboBox.findText(currentBroker) 1096 index = self.brokerComboBox.findText(currentBroker)
1063 self.brokerComboBox.setCurrentIndex(index) 1097 self.brokerComboBox.setCurrentIndex(index)
1064 1098
1065 # step 2b: populate the broker ports list 1099 # step 2b: populate the broker ports list
1066 currentPort = brokerPortList[0][1] if brokerPortList else 1883 1100 currentPort = brokerPortList[0][1] if brokerPortList else 1883
1067 currentPortStr = "{0:5}".format(currentPort) 1101 currentPortStr = "{0:5}".format(currentPort)
1068 portsSet = {b[1] for b in brokerPortList} 1102 portsSet = {b[1] for b in brokerPortList}
1069 portsSet.update({1883, 8883}) 1103 portsSet.update({1883, 8883})
1070 self.brokerPortComboBox.addItems( 1104 self.brokerPortComboBox.addItems(sorted("{0:5}".format(p) for p in portsSet))
1071 sorted("{0:5}".format(p) for p in portsSet))
1072 index = self.brokerPortComboBox.findText(currentPortStr) 1105 index = self.brokerPortComboBox.findText(currentPortStr)
1073 self.brokerPortComboBox.setCurrentIndex(index) 1106 self.brokerPortComboBox.setCurrentIndex(index)
1074 1107
1075 # step 3: update the connect button state 1108 # step 3: update the connect button state
1076 self.__setConnectButtonState() 1109 self.__setConnectButtonState()
1077 1110
1078 def __populateProfileComboBox(self): 1111 def __populateProfileComboBox(self):
1079 """ 1112 """
1080 Private method to populate the profiles selection box. 1113 Private method to populate the profiles selection box.
1081 """ 1114 """
1082 profilesDict = self.__plugin.getPreferences("BrokerProfiles") 1115 profilesDict = self.__plugin.getPreferences("BrokerProfiles")
1083 mostRecentProfile = self.__plugin.getPreferences("MostRecentProfile") 1116 mostRecentProfile = self.__plugin.getPreferences("MostRecentProfile")
1084 1117
1085 self.profileComboBox.clear() 1118 self.profileComboBox.clear()
1086 self.profileComboBox.addItems(sorted(profilesDict.keys())) 1119 self.profileComboBox.addItems(sorted(profilesDict.keys()))
1087 if mostRecentProfile: 1120 if mostRecentProfile:
1088 index = self.profileComboBox.findText(mostRecentProfile) 1121 index = self.profileComboBox.findText(mostRecentProfile)
1089 if index >= 0: 1122 if index >= 0:
1090 self.profileComboBox.setCurrentIndex(index) 1123 self.profileComboBox.setCurrentIndex(index)
1091 1124
1092 self.__setConnectButtonState() 1125 self.__setConnectButtonState()
1093 1126
1094 def __addTopicToRecent(self, topic): 1127 def __addTopicToRecent(self, topic):
1095 """ 1128 """
1096 Private method to add a topic to the list of recently subscribed 1129 Private method to add a topic to the list of recently subscribed
1097 topics. 1130 topics.
1098 1131
1099 @param topic subscribed topic 1132 @param topic subscribed topic
1100 @type str 1133 @type str
1101 """ 1134 """
1102 topicsList = self.__plugin.getPreferences("RecentTopics") 1135 topicsList = self.__plugin.getPreferences("RecentTopics")
1103 if topic in topicsList: 1136 if topic in topicsList:
1105 topicsList.insert(0, topic) 1138 topicsList.insert(0, topic)
1106 # limit the most recently used entries 1139 # limit the most recently used entries
1107 maxTopics = self.__plugin.getPreferences("RecentTopicsNumber") 1140 maxTopics = self.__plugin.getPreferences("RecentTopicsNumber")
1108 topicsList = topicsList[:maxTopics] 1141 topicsList = topicsList[:maxTopics]
1109 self.__plugin.setPreferences("RecentTopics", topicsList) 1142 self.__plugin.setPreferences("RecentTopics", topicsList)
1110 1143
1111 self.__populateSubscribeTopicComboBox() 1144 self.__populateSubscribeTopicComboBox()
1112 1145
1113 def __populateSubscribeTopicComboBox(self): 1146 def __populateSubscribeTopicComboBox(self):
1114 """ 1147 """
1115 Private method to populate the subscribe topic combo box. 1148 Private method to populate the subscribe topic combo box.
1116 """ 1149 """
1117 topicsList = self.__plugin.getPreferences("RecentTopics") 1150 topicsList = self.__plugin.getPreferences("RecentTopics")
1118 1151
1119 self.subscribeTopicComboBox.clear() 1152 self.subscribeTopicComboBox.clear()
1120 self.subscribeTopicComboBox.addItems(sorted(topicsList)) 1153 self.subscribeTopicComboBox.addItems(sorted(topicsList))
1121 self.subscribeTopicComboBox.clearEditText() 1154 self.subscribeTopicComboBox.clearEditText()
1122 1155
1123 def __updateUnsubscribeTopicComboBox(self): 1156 def __updateUnsubscribeTopicComboBox(self):
1124 """ 1157 """
1125 Private method to update the unsubcribe topic combo box. 1158 Private method to update the unsubcribe topic combo box.
1126 """ 1159 """
1127 self.unsubscribeTopicComboBox.clear() 1160 self.unsubscribeTopicComboBox.clear()
1128 self.unsubscribeTopicComboBox.addItems(sorted(self.__subscribedTopics)) 1161 self.unsubscribeTopicComboBox.addItems(sorted(self.__subscribedTopics))
1129 self.unsubscribeButton.setEnabled( 1162 self.unsubscribeButton.setEnabled(bool(self.__subscribedTopics))
1130 bool(self.__subscribedTopics)) 1163 self.unsubscribePropertiesButton.setEnabled(bool(self.__subscribedTopics))
1131 self.unsubscribePropertiesButton.setEnabled( 1164
1132 bool(self.__subscribedTopics))
1133
1134 def __updatePublishTopicComboBox(self, resetTopic=True): 1165 def __updatePublishTopicComboBox(self, resetTopic=True):
1135 """ 1166 """
1136 Private method to update the publish topic combo box. 1167 Private method to update the publish topic combo box.
1137 1168
1138 @param resetTopic flag indicating to reset the topic 1169 @param resetTopic flag indicating to reset the topic
1139 @type bool 1170 @type bool
1140 """ 1171 """
1141 currentTopic = self.publishTopicComboBox.currentText() 1172 currentTopic = self.publishTopicComboBox.currentText()
1142 self.publishTopicComboBox.clear() 1173 self.publishTopicComboBox.clear()
1143 self.publishTopicComboBox.addItems( 1174 self.publishTopicComboBox.addItems(
1144 list(set(self.__publishedTopics + self.__subscribedTopics))) 1175 list(set(self.__publishedTopics + self.__subscribedTopics))
1176 )
1145 if resetTopic: 1177 if resetTopic:
1146 self.publishTopicComboBox.clearEditText() 1178 self.publishTopicComboBox.clearEditText()
1147 else: 1179 else:
1148 topicIndex = self.publishTopicComboBox.findText(currentTopic) 1180 topicIndex = self.publishTopicComboBox.findText(currentTopic)
1149 self.publishTopicComboBox.setCurrentIndex(topicIndex) 1181 self.publishTopicComboBox.setCurrentIndex(topicIndex)
1150 1182
1151 def __appendMessage(self, topic, payload, qos, retain, properties=None): 1183 def __appendMessage(self, topic, payload, qos, retain, properties=None):
1152 """ 1184 """
1153 Private method to append a received message to the output. 1185 Private method to append a received message to the output.
1154 1186
1155 @param topic topic of the received message 1187 @param topic topic of the received message
1156 @type str 1188 @type str
1157 @param payload payload of the received message 1189 @param payload payload of the received message
1158 @type bytes 1190 @type bytes
1159 @param qos quality of service indicator (0, 1, 2) 1191 @param qos quality of service indicator (0, 1, 2)
1162 @type bool 1194 @type bool
1163 @param properties properties sent with the message (MQTT v5) 1195 @param properties properties sent with the message (MQTT v5)
1164 @type dict 1196 @type dict
1165 """ 1197 """
1166 scrollbarValue = self.messagesEdit.verticalScrollBar().value() 1198 scrollbarValue = self.messagesEdit.verticalScrollBar().value()
1167 1199
1168 textCursor = self.messagesEdit.textCursor() 1200 textCursor = self.messagesEdit.textCursor()
1169 if not self.messagesEdit.document().isEmpty(): 1201 if not self.messagesEdit.document().isEmpty():
1170 textCursor.movePosition(QTextCursor.MoveOperation.End) 1202 textCursor.movePosition(QTextCursor.MoveOperation.End)
1171 self.messagesEdit.setTextCursor(textCursor) 1203 self.messagesEdit.setTextCursor(textCursor)
1172 self.messagesEdit.insertPlainText("\n") 1204 self.messagesEdit.insertPlainText("\n")
1173 1205
1174 textBlockFormat = textCursor.blockFormat() 1206 textBlockFormat = textCursor.blockFormat()
1175 if self.__isMessageAlternate: 1207 if self.__isMessageAlternate:
1176 textBlockFormat.setBackground( 1208 textBlockFormat.setBackground(self.messagesEdit.palette().alternateBase())
1177 self.messagesEdit.palette().alternateBase()) 1209 else:
1178 else: 1210 textBlockFormat.setBackground(self.messagesEdit.palette().base())
1179 textBlockFormat.setBackground(
1180 self.messagesEdit.palette().base())
1181 textCursor.setBlockFormat(textBlockFormat) 1211 textCursor.setBlockFormat(textBlockFormat)
1182 textCursor.movePosition(QTextCursor.MoveOperation.End) 1212 textCursor.movePosition(QTextCursor.MoveOperation.End)
1183 self.messagesEdit.setTextCursor(textCursor) 1213 self.messagesEdit.setTextCursor(textCursor)
1184 1214
1185 self.messagesEdit.setCurrentCharFormat(self.__messagesTopicFormat) 1215 self.messagesEdit.setCurrentCharFormat(self.__messagesTopicFormat)
1186 self.messagesEdit.insertPlainText(topic + "\n") 1216 self.messagesEdit.insertPlainText(topic + "\n")
1187 1217
1188 self.messagesEdit.setCurrentCharFormat(self.__messagesQosFormat) 1218 self.messagesEdit.setCurrentCharFormat(self.__messagesQosFormat)
1189 self.messagesEdit.insertPlainText(self.tr("QoS: {0}\n").format(qos)) 1219 self.messagesEdit.insertPlainText(self.tr("QoS: {0}\n").format(qos))
1190 1220
1191 if retain: 1221 if retain:
1192 self.messagesEdit.setCurrentCharFormat(self.__messagesQosFormat) 1222 self.messagesEdit.setCurrentCharFormat(self.__messagesQosFormat)
1193 self.messagesEdit.insertPlainText(self.tr("Retained Message\n")) 1223 self.messagesEdit.insertPlainText(self.tr("Retained Message\n"))
1194 1224
1195 if properties: 1225 if properties:
1196 self.messagesEdit.setCurrentCharFormat( 1226 self.messagesEdit.setCurrentCharFormat(self.__messagesSubheaderFormat)
1197 self.__messagesSubheaderFormat)
1198 self.messagesEdit.insertPlainText(self.tr("Properties:\n")) 1227 self.messagesEdit.insertPlainText(self.tr("Properties:\n"))
1199 self.messagesEdit.setCurrentCharFormat(self.__messagesFormat) 1228 self.messagesEdit.setCurrentCharFormat(self.__messagesFormat)
1200 for name, value in sorted(properties.items()): 1229 for name, value in sorted(properties.items()):
1201 self.messagesEdit.insertPlainText( 1230 self.messagesEdit.insertPlainText(
1202 self.tr("{0}: {1}\n", "property name, property value") 1231 self.tr("{0}: {1}\n", "property name, property value").format(
1203 .format(name, value) 1232 name, value
1204 ) 1233 )
1205 1234 )
1235
1206 self.messagesEdit.setCurrentCharFormat(self.__messagesSubheaderFormat) 1236 self.messagesEdit.setCurrentCharFormat(self.__messagesSubheaderFormat)
1207 self.messagesEdit.insertPlainText(self.tr("Message:\n")) 1237 self.messagesEdit.insertPlainText(self.tr("Message:\n"))
1208 payloadStr = str(payload, encoding="utf-8", errors="replace") 1238 payloadStr = str(payload, encoding="utf-8", errors="replace")
1209 payloadStr = Utilities.filterAnsiSequences(payloadStr) 1239 payloadStr = Utilities.filterAnsiSequences(payloadStr)
1210 self.messagesEdit.setCurrentCharFormat(self.__messagesFormat) 1240 self.messagesEdit.setCurrentCharFormat(self.__messagesFormat)
1211 if payloadStr: 1241 if payloadStr:
1212 self.messagesEdit.insertPlainText(payloadStr) 1242 self.messagesEdit.insertPlainText(payloadStr)
1213 else: 1243 else:
1214 self.messagesEdit.insertPlainText(self.tr("<empty>")) 1244 self.messagesEdit.insertPlainText(self.tr("<empty>"))
1215 1245
1216 if self.followMessagesCheckBox.isChecked(): 1246 if self.followMessagesCheckBox.isChecked():
1217 self.messagesEdit.ensureCursorVisible() 1247 self.messagesEdit.ensureCursorVisible()
1218 else: 1248 else:
1219 self.messagesEdit.verticalScrollBar().setValue(scrollbarValue) 1249 self.messagesEdit.verticalScrollBar().setValue(scrollbarValue)
1220 1250
1221 self.__isMessageAlternate = not self.__isMessageAlternate 1251 self.__isMessageAlternate = not self.__isMessageAlternate
1222 1252
1223 def __handleBrokerStatusMessage(self, topic, payload): 1253 def __handleBrokerStatusMessage(self, topic, payload):
1224 """ 1254 """
1225 Private method to handle a status message of the broker. 1255 Private method to handle a status message of the broker.
1226 1256
1227 @param topic topic of the received message 1257 @param topic topic of the received message
1228 @type str 1258 @type str
1229 @param payload payload of the received message 1259 @param payload payload of the received message
1230 @type bytes 1260 @type bytes
1231 """ 1261 """
1232 payloadStr = str(payload, encoding="utf-8", errors="replace").strip() 1262 payloadStr = str(payload, encoding="utf-8", errors="replace").strip()
1233 topic = topic.strip() 1263 topic = topic.strip()
1234 1264
1235 if topic.startswith(MqttMonitorWidget.BrokerStatusTopicLoadPrefix): 1265 if topic.startswith(MqttMonitorWidget.BrokerStatusTopicLoadPrefix):
1236 self.__handleBrokerLoadStatusMessage(topic, payloadStr) 1266 self.__handleBrokerLoadStatusMessage(topic, payloadStr)
1237 else: 1267 else:
1238 with contextlib.suppress(KeyError): 1268 with contextlib.suppress(KeyError):
1239 label = self.__statusLabelMapping[topic] 1269 label = self.__statusLabelMapping[topic]
1240 label.setText(payloadStr) 1270 label.setText(payloadStr)
1241 1271
1242 def __handleBrokerLoadStatusMessage(self, topic, payloadStr): 1272 def __handleBrokerLoadStatusMessage(self, topic, payloadStr):
1243 """ 1273 """
1244 Private method to append a received message to the output. 1274 Private method to append a received message to the output.
1245 1275
1246 @param topic topic of the received message 1276 @param topic topic of the received message
1247 @type str 1277 @type str
1248 @param payloadStr string representation of the payload of the 1278 @param payloadStr string representation of the payload of the
1249 received message 1279 received message
1250 @type str 1280 @type str
1251 """ 1281 """
1252 subtopic, topicElement = topic.rsplit("/", 1) 1282 subtopic, topicElement = topic.rsplit("/", 1)
1253 self.__statusLoadValues[subtopic][topicElement] = payloadStr 1283 self.__statusLoadValues[subtopic][topicElement] = payloadStr
1254 1284
1255 with contextlib.suppress(KeyError): 1285 with contextlib.suppress(KeyError):
1256 label = self.__statusLabelMapping[subtopic] 1286 label = self.__statusLabelMapping[subtopic]
1257 label.setText("{0} / {1} / {2}".format( 1287 label.setText(
1258 self.__statusLoadValues[subtopic]["1min"], 1288 "{0} / {1} / {2}".format(
1259 self.__statusLoadValues[subtopic]["5min"], 1289 self.__statusLoadValues[subtopic]["1min"],
1260 self.__statusLoadValues[subtopic]["15min"], 1290 self.__statusLoadValues[subtopic]["5min"],
1261 )) 1291 self.__statusLoadValues[subtopic]["15min"],
1262 1292 )
1293 )
1294
1263 def __clearBrokerStatusLabels(self): 1295 def __clearBrokerStatusLabels(self):
1264 """ 1296 """
1265 Private method to clear the broker status labels. 1297 Private method to clear the broker status labels.
1266 """ 1298 """
1267 for statusLabelKey in self.__statusLabelMapping: 1299 for statusLabelKey in self.__statusLabelMapping:
1268 label = ( 1300 label = (
1269 "- / - / -" 1301 "- / - / -"
1270 if statusLabelKey.startswith( 1302 if statusLabelKey.startswith(
1271 MqttMonitorWidget.BrokerStatusTopicLoadPrefix) else 1303 MqttMonitorWidget.BrokerStatusTopicLoadPrefix
1272 "-" 1304 )
1305 else "-"
1273 ) 1306 )
1274 self.__statusLabelMapping[statusLabelKey].setText(label) 1307 self.__statusLabelMapping[statusLabelKey].setText(label)
1275 1308
1276 def __loadDefaultDictFactory(self): 1309 def __loadDefaultDictFactory(self):
1277 """ 1310 """
1278 Private method to populate non-existing load items. 1311 Private method to populate non-existing load items.
1279 1312
1280 @return default dictionary entry 1313 @return default dictionary entry
1281 @rtype dict 1314 @rtype dict
1282 """ 1315 """
1283 return { 1316 return {
1284 "1min": "-", 1317 "1min": "-",
1285 "5min": "-", 1318 "5min": "-",
1286 "15min": "-", 1319 "15min": "-",
1287 } 1320 }
1288 1321
1289 def __setConnectionMode(self, profileMode): 1322 def __setConnectionMode(self, profileMode):
1290 """ 1323 """
1291 Private method to set the connection mode. 1324 Private method to set the connection mode.
1292 1325
1293 @param profileMode flag indicating the profile connection mode 1326 @param profileMode flag indicating the profile connection mode
1294 @type bool 1327 @type bool
1295 """ 1328 """
1296 self.__connectionModeProfile = profileMode 1329 self.__connectionModeProfile = profileMode
1297 if profileMode: 1330 if profileMode:
1298 self.modeButton.setIcon(UI.PixmapCache.getIcon( 1331 self.modeButton.setIcon(
1299 os.path.join("MqttMonitor", "icons", 1332 UI.PixmapCache.getIcon(
1300 "profiles-{0}".format(self.__iconSuffix)) 1333 os.path.join(
1301 )) 1334 "MqttMonitor", "icons", "profiles-{0}".format(self.__iconSuffix)
1302 else: 1335 )
1303 self.modeButton.setIcon(UI.PixmapCache.getIcon( 1336 )
1304 os.path.join("MqttMonitor", "icons", 1337 )
1305 "quickopen-{0}".format(self.__iconSuffix)) 1338 else:
1306 )) 1339 self.modeButton.setIcon(
1307 1340 UI.PixmapCache.getIcon(
1341 os.path.join(
1342 "MqttMonitor",
1343 "icons",
1344 "quickopen-{0}".format(self.__iconSuffix),
1345 )
1346 )
1347 )
1348
1308 self.profileComboBox.setVisible(profileMode) 1349 self.profileComboBox.setVisible(profileMode)
1309 self.brokerConnectionWidget.setVisible(not profileMode) 1350 self.brokerConnectionWidget.setVisible(not profileMode)
1310 self.__setConnectButtonState() 1351 self.__setConnectButtonState()
1311 1352
1312 def __setConnectButtonState(self): 1353 def __setConnectButtonState(self):
1313 """ 1354 """
1314 Private method to set the enabled state of the connect button. 1355 Private method to set the enabled state of the connect button.
1315 """ 1356 """
1316 if self.__connectionModeProfile: 1357 if self.__connectionModeProfile:
1317 self.connectButton.setEnabled( 1358 self.connectButton.setEnabled(bool(self.profileComboBox.currentText()))
1318 bool(self.profileComboBox.currentText())) 1359 else:
1319 else: 1360 self.connectButton.setEnabled(bool(self.brokerComboBox.currentText()))
1320 self.connectButton.setEnabled( 1361
1321 bool(self.brokerComboBox.currentText()))
1322
1323 def __directConnectToBroker(self): 1362 def __directConnectToBroker(self):
1324 """ 1363 """
1325 Private method to connect to the broker with entered data. 1364 Private method to connect to the broker with entered data.
1326 """ 1365 """
1327 host = self.brokerComboBox.currentText() 1366 host = self.brokerComboBox.currentText()
1331 except ValueError: 1370 except ValueError:
1332 # use standard port at 1883 1371 # use standard port at 1883
1333 port = 1883 1372 port = 1883
1334 if host: 1373 if host:
1335 self.brokerStatusLabel.setText( 1374 self.brokerStatusLabel.setText(
1336 self.tr("Connecting to {0}:{1} ...").format( 1375 self.tr("Connecting to {0}:{1} ...").format(host, port)
1337 host, port)) 1376 )
1338 self.brokerStatusLabel.show() 1377 self.brokerStatusLabel.show()
1339 1378
1340 self.__addBrokerToRecent(host, port) 1379 self.__addBrokerToRecent(host, port)
1341 self.connectButton.setEnabled(False) 1380 self.connectButton.setEnabled(False)
1342 1381
1343 if self.clearWillButton.isChecked(): 1382 if self.clearWillButton.isChecked():
1344 clearWill = True 1383 clearWill = True
1345 self.clearWillButton.setChecked(False) 1384 self.clearWillButton.setChecked(False)
1346 else: 1385 else:
1347 clearWill = False 1386 clearWill = False
1348 1387
1349 if self.__connectionOptions is None: 1388 if self.__connectionOptions is None:
1350 self.__client = self.__createClient() 1389 self.__client = self.__createClient()
1351 self.__client.connectToServer( 1390 self.__client.connectToServer(host, port=port, clearWill=clearWill)
1352 host, port=port, clearWill=clearWill)
1353 else: 1391 else:
1354 self.__client = self.__createClient( 1392 self.__client = self.__createClient(
1355 clientId=self.__connectionOptions["ClientId"], 1393 clientId=self.__connectionOptions["ClientId"],
1356 cleanSession=self.__connectionOptions["CleanSession"], 1394 cleanSession=self.__connectionOptions["CleanSession"],
1357 protocol=self.__connectionOptions["Protocol"] 1395 protocol=self.__connectionOptions["Protocol"],
1358 ) 1396 )
1359 self.__client.connectToServerWithOptions( 1397 self.__client.connectToServerWithOptions(
1360 host, port=port, options=self.__connectionOptions, 1398 host,
1361 clearWill=clearWill) 1399 port=port,
1362 1400 options=self.__connectionOptions,
1401 clearWill=clearWill,
1402 )
1403
1363 def __profileConnectToBroker(self): 1404 def __profileConnectToBroker(self):
1364 """ 1405 """
1365 Private method to connect to the broker with selected profile. 1406 Private method to connect to the broker with selected profile.
1366 """ 1407 """
1367 profileName = self.profileComboBox.currentText() 1408 profileName = self.profileComboBox.currentText()
1368 if profileName: 1409 if profileName:
1369 self.__plugin.setPreferences("MostRecentProfile", profileName) 1410 self.__plugin.setPreferences("MostRecentProfile", profileName)
1370 1411
1371 profilesDict = self.__plugin.getPreferences("BrokerProfiles") 1412 profilesDict = self.__plugin.getPreferences("BrokerProfiles")
1372 connectionProfile = copy.deepcopy(profilesDict[profileName]) 1413 connectionProfile = copy.deepcopy(profilesDict[profileName])
1373 host = connectionProfile["BrokerAddress"] 1414 host = connectionProfile["BrokerAddress"]
1374 port = connectionProfile["BrokerPort"] 1415 port = connectionProfile["BrokerPort"]
1375 try: 1416 try:
1376 protocol = connectionProfile["Protocol"] 1417 protocol = connectionProfile["Protocol"]
1377 except KeyError: 1418 except KeyError:
1378 protocol = MqttProtocols( 1419 protocol = MqttProtocols(
1379 self.__plugin.getPreferences("DefaultProtocol")) 1420 self.__plugin.getPreferences("DefaultProtocol")
1380 1421 )
1422
1381 self.brokerStatusLabel.setText( 1423 self.brokerStatusLabel.setText(
1382 self.tr("Connecting to {0}:{1} ...").format( 1424 self.tr("Connecting to {0}:{1} ...").format(host, port)
1383 host, port)) 1425 )
1384 self.brokerStatusLabel.show() 1426 self.brokerStatusLabel.show()
1385 1427
1386 self.connectButton.setEnabled(False) 1428 self.connectButton.setEnabled(False)
1387 1429
1388 if self.clearWillButton.isChecked(): 1430 if self.clearWillButton.isChecked():
1389 clearWill = True 1431 clearWill = True
1390 self.clearWillButton.setChecked(False) 1432 self.clearWillButton.setChecked(False)
1391 else: 1433 else:
1392 clearWill = False 1434 clearWill = False
1393 1435
1394 self.__client = self.__createClient( 1436 self.__client = self.__createClient(
1395 clientId=connectionProfile["ClientId"], 1437 clientId=connectionProfile["ClientId"],
1396 cleanSession=connectionProfile["CleanSession"], 1438 cleanSession=connectionProfile["CleanSession"],
1397 protocol=protocol 1439 protocol=protocol,
1398 ) 1440 )
1399 self.__client.connectToServerWithOptions( 1441 self.__client.connectToServerWithOptions(
1400 host, port=port, options=connectionProfile, 1442 host, port=port, options=connectionProfile, clearWill=clearWill
1401 clearWill=clearWill) 1443 )
1402 1444
1403 def __showProperties(self, typeStr, properties): 1445 def __showProperties(self, typeStr, properties):
1404 """ 1446 """
1405 Private method to display the received properties in the properties 1447 Private method to display the received properties in the properties
1406 pane. 1448 pane.
1407 1449
1408 @param typeStr message type 1450 @param typeStr message type
1409 @type str 1451 @type str
1410 @param properties dictionary containing the relevant properties 1452 @param properties dictionary containing the relevant properties
1411 @type dict 1453 @type dict
1412 """ 1454 """
1413 textCursor = self.propertiesEdit.textCursor() 1455 textCursor = self.propertiesEdit.textCursor()
1414 if not self.propertiesEdit.document().isEmpty(): 1456 if not self.propertiesEdit.document().isEmpty():
1415 textCursor.movePosition(QTextCursor.MoveOperation.End) 1457 textCursor.movePosition(QTextCursor.MoveOperation.End)
1416 self.propertiesEdit.setTextCursor(textCursor) 1458 self.propertiesEdit.setTextCursor(textCursor)
1417 1459
1418 textBlockFormat = textCursor.blockFormat() 1460 textBlockFormat = textCursor.blockFormat()
1419 if self.__isPropertiesAlternate: 1461 if self.__isPropertiesAlternate:
1420 textBlockFormat.setBackground( 1462 textBlockFormat.setBackground(self.propertiesEdit.palette().alternateBase())
1421 self.propertiesEdit.palette().alternateBase()) 1463 else:
1422 else: 1464 textBlockFormat.setBackground(self.propertiesEdit.palette().base())
1423 textBlockFormat.setBackground(
1424 self.propertiesEdit.palette().base())
1425 textCursor.setBlockFormat(textBlockFormat) 1465 textCursor.setBlockFormat(textBlockFormat)
1426 textCursor.movePosition(QTextCursor.MoveOperation.End) 1466 textCursor.movePosition(QTextCursor.MoveOperation.End)
1427 self.propertiesEdit.setTextCursor(textCursor) 1467 self.propertiesEdit.setTextCursor(textCursor)
1428 1468
1429 self.propertiesEdit.setCurrentCharFormat(self.__propertiesTopicFormat) 1469 self.propertiesEdit.setCurrentCharFormat(self.__propertiesTopicFormat)
1430 self.propertiesEdit.insertPlainText(typeStr + "\n") 1470 self.propertiesEdit.insertPlainText(typeStr + "\n")
1431 1471
1432 for name, value in sorted(properties.items()): 1472 for name, value in sorted(properties.items()):
1433 self.propertiesEdit.setCurrentCharFormat( 1473 self.propertiesEdit.setCurrentCharFormat(self.__propertiesNameFormat)
1434 self.__propertiesNameFormat)
1435 self.propertiesEdit.insertPlainText("{0}: ".format(name)) 1474 self.propertiesEdit.insertPlainText("{0}: ".format(name))
1436 self.propertiesEdit.setCurrentCharFormat(self.__propertiesFormat) 1475 self.propertiesEdit.setCurrentCharFormat(self.__propertiesFormat)
1437 self.propertiesEdit.insertPlainText("{0}\n".format(str(value))) 1476 self.propertiesEdit.insertPlainText("{0}\n".format(str(value)))
1438 1477
1439 self.propertiesEdit.ensureCursorVisible() 1478 self.propertiesEdit.ensureCursorVisible()
1440 1479
1441 self.__isPropertiesAlternate = not self.__isPropertiesAlternate 1480 self.__isPropertiesAlternate = not self.__isPropertiesAlternate
1442 1481
1443 def __editProperties(self, propertiesType, header, key): 1482 def __editProperties(self, propertiesType, header, key):
1444 """ 1483 """
1445 Private method to edit user properties of a given type. 1484 Private method to edit user properties of a given type.
1446 1485
1447 @param propertiesType properties type (one of 'subscribe', 1486 @param propertiesType properties type (one of 'subscribe',
1448 'unsubscribe', 'publish') 1487 'unsubscribe', 'publish')
1449 @type str 1488 @type str
1450 @param header header to be shown in the edit dialog 1489 @param header header to be shown in the edit dialog
1451 @type str 1490 @type str
1452 @param key key to retrieve the right properties 1491 @param key key to retrieve the right properties
1453 @type str 1492 @type str
1454 """ 1493 """
1455 from .MqttUserPropertiesEditor import MqttUserPropertiesEditorDialog 1494 from .MqttUserPropertiesEditor import MqttUserPropertiesEditorDialog
1456 1495
1457 preferencesKey = "{0}Properties".format(propertiesType.capitalize()) 1496 preferencesKey = "{0}Properties".format(propertiesType.capitalize())
1458 properties = self.__plugin.getPreferences(preferencesKey) 1497 properties = self.__plugin.getPreferences(preferencesKey)
1459 dlg = MqttUserPropertiesEditorDialog( 1498 dlg = MqttUserPropertiesEditorDialog(header, properties.get(key, []), self)
1460 header, properties.get(key, []), self)
1461 if dlg.exec() == QDialog.DialogCode.Accepted: 1499 if dlg.exec() == QDialog.DialogCode.Accepted:
1462 properties[key] = dlg.getProperties() 1500 properties[key] = dlg.getProperties()
1463 self.__plugin.setPreferences(preferencesKey, properties) 1501 self.__plugin.setPreferences(preferencesKey, properties)

eric ide

mercurial