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, |
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": |
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) |