Wed, 03 May 2023 10:12:03 +0200
MicroPython
- Added a dialog for manual configuration of the WebREPL connection parameters.
--- a/eric7.epj Tue May 02 18:01:34 2023 +0200 +++ b/eric7.epj Wed May 03 10:12:03 2023 +0200 @@ -352,6 +352,7 @@ "src/eric7/MicroPython/IgnoredDevicesDialog.ui", "src/eric7/MicroPython/MicroPythonFileManagerWidget.ui", "src/eric7/MicroPython/MicroPythonProgressInfoDialog.ui", + "src/eric7/MicroPython/MicroPythonWebreplConnectionDialog.ui", "src/eric7/MicroPython/MicroPythonWebreplUrlAddEditDialog.ui", "src/eric7/MicroPython/MicroPythonWebreplUrlsConfigDialog.ui", "src/eric7/MicroPython/MicroPythonWidget.ui", @@ -1351,6 +1352,7 @@ "src/eric7/MicroPython/MicroPythonProgressInfoDialog.py", "src/eric7/MicroPython/MicroPythonSerialDeviceInterface.py", "src/eric7/MicroPython/MicroPythonSerialPort.py", + "src/eric7/MicroPython/MicroPythonWebreplConnectionDialog.py", "src/eric7/MicroPython/MicroPythonWebreplDeviceInterface.py", "src/eric7/MicroPython/MicroPythonWebreplSocket.py", "src/eric7/MicroPython/MicroPythonWebreplUrlAddEditDialog.py",
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/eric7/MicroPython/MicroPythonWebreplConnectionDialog.py Wed May 03 10:12:03 2023 +0200 @@ -0,0 +1,123 @@ +# -*- coding: utf-8 -*- + +# Copyright (c) 2023 Detlev Offenbach <detlev@die-offenbachs.de> +# + +""" +Module implementing a dialog to enter the WebREPL connection parameters. +""" + +from PyQt6.QtCore import pyqtSlot +from PyQt6.QtWidgets import QDialog, QDialogButtonBox, QLineEdit + +from eric7.EricGui import EricPixmapCache + +from .Devices import getSupportedDevices +from .Ui_MicroPythonWebreplConnectionDialog import Ui_MicroPythonWebreplConnectionDialog + + +class MicroPythonWebreplConnectionDialog( + QDialog, Ui_MicroPythonWebreplConnectionDialog +): + """ + Class implementing a dialog to enter the WebREPL connection parameters. + """ + + def __init__(self, currentWebreplUrl, currentType, parent=None): + """ + Constructor + + @param currentWebreplUrl WebREPL URL most recently configured + @type str + @param currentType device type most recently selected + @type str + @param parent reference to the parent widget (defaults to None) + @type QWidget (optional) + """ + super().__init__(parent) + self.setupUi(self) + + self.deviceTypeComboBox.addItem("", "") + for board, description in sorted(getSupportedDevices(), key=lambda x: x[1]): + self.deviceTypeComboBox.addItem(description, board) + + self.showPasswordButton.setIcon(EricPixmapCache.getIcon("showPassword")) + + self.hostEdit.textChanged.connect(self.__updateOkButton) + self.portEdit.textChanged.connect(self.__updateOkButton) + self.deviceTypeComboBox.currentIndexChanged.connect(self.__updateOkButton) + + if currentWebreplUrl: + url = currentWebreplUrl.replace("ws://", "") + password, hostPort = url.split("@", 1) if "@" in url else ("", url) + host, port = hostPort.split(":", 1) if ":" in hostPort else (hostPort, "") + self.hostEdit.setText(host) + self.portEdit.setText(port) + self.passwordEdit.setText(password) + + typeIndex = self.deviceTypeComboBox.findData(currentType) + self.deviceTypeComboBox.setCurrentIndex(typeIndex) + else: + self.__updateOkButton() + + msh = self.minimumSizeHint() + self.resize(max(self.width(), msh.width()), msh.height()) + + @pyqtSlot() + def __updateOkButton(self): + """ + Private slot to update the enabled state of the OK button. + """ + port = self.portEdit.text() + if port == "": + portOk = True + else: + try: + portNo = int(port) + portOk = 1024 < portNo <= 65535 + except ValueError: + portOk = False + self.buttonBox.button(QDialogButtonBox.StandardButton.Ok).setEnabled( + bool(self.hostEdit.text()) + and portOk + and bool(self.deviceTypeComboBox.currentData()) + ) + + @pyqtSlot(bool) + def on_showPasswordButton_clicked(self, checked): + """ + Private slot to show or hide the password. + + @param checked state of the button + @type bool + """ + if checked: + self.passwordEdit.setEchoMode(QLineEdit.EchoMode.Normal) + self.showPasswordButton.setIcon(EricPixmapCache.getIcon("hidePassword")) + self.showPasswordButton.setToolTip(self.tr("Press to hide the password.")) + else: + self.passwordEdit.setEchoMode(QLineEdit.EchoMode.Password) + self.showPasswordButton.setIcon(EricPixmapCache.getIcon("showPassword")) + self.showPasswordButton.setToolTip(self.tr("Press to show the password.")) + + def getWebreplConnectionParameters(self): + """ + Public method to retrieve the entered WebREPL connection data. + + @return tuple containing the URL and device type for the WebREPL connection + @rtype tuple of (str, str) + """ + password = self.passwordEdit.text() + host = self.hostEdit.text() + port = self.portEdit.text() + + if password and port: + url = f"ws://{password}@{host}:{port}" + elif password: + url = f"ws://{password}@{host}" + elif port: + url = f"ws://{host}:{port}" + else: + url = f"ws://{host}" + + return (url, self.deviceTypeComboBox.currentData())
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/eric7/MicroPython/MicroPythonWebreplConnectionDialog.ui Wed May 03 10:12:03 2023 +0200 @@ -0,0 +1,157 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> + <class>MicroPythonWebreplConnectionDialog</class> + <widget class="QDialog" name="MicroPythonWebreplConnectionDialog"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>400</width> + <height>172</height> + </rect> + </property> + <property name="windowTitle"> + <string>WebREPL Connection</string> + </property> + <property name="sizeGripEnabled"> + <bool>true</bool> + </property> + <layout class="QGridLayout" name="gridLayout"> + <item row="0" column="0"> + <widget class="QLabel" name="label_3"> + <property name="text"> + <string>Host:</string> + </property> + </widget> + </item> + <item row="0" column="1" colspan="2"> + <widget class="QLineEdit" name="hostEdit"> + <property name="toolTip"> + <string>Enter the host name or IPv4 address of the device.</string> + </property> + <property name="clearButtonEnabled"> + <bool>true</bool> + </property> + </widget> + </item> + <item row="1" column="0"> + <widget class="QLabel" name="label_4"> + <property name="text"> + <string>Port:</string> + </property> + </widget> + </item> + <item row="1" column="1" colspan="2"> + <widget class="QLineEdit" name="portEdit"> + <property name="toolTip"> + <string>Enter the port of the WebREPL (empty for default port 8266).</string> + </property> + <property name="clearButtonEnabled"> + <bool>true</bool> + </property> + </widget> + </item> + <item row="2" column="0"> + <widget class="QLabel" name="label_5"> + <property name="text"> + <string>Password:</string> + </property> + </widget> + </item> + <item row="2" column="1"> + <widget class="QLineEdit" name="passwordEdit"> + <property name="toolTip"> + <string>Enter the password for this device connection.</string> + </property> + <property name="echoMode"> + <enum>QLineEdit::Password</enum> + </property> + <property name="clearButtonEnabled"> + <bool>true</bool> + </property> + </widget> + </item> + <item row="2" column="2"> + <widget class="QToolButton" name="showPasswordButton"> + <property name="toolTip"> + <string>Press to show the password.</string> + </property> + <property name="checkable"> + <bool>true</bool> + </property> + </widget> + </item> + <item row="3" column="0"> + <widget class="QLabel" name="label_6"> + <property name="text"> + <string>Device Type:</string> + </property> + </widget> + </item> + <item row="3" column="1" colspan="2"> + <widget class="QComboBox" name="deviceTypeComboBox"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Expanding" vsizetype="Fixed"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="toolTip"> + <string>Select the device type</string> + </property> + </widget> + </item> + <item row="4" column="0" colspan="3"> + <widget class="QDialogButtonBox" name="buttonBox"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="standardButtons"> + <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set> + </property> + </widget> + </item> + </layout> + </widget> + <tabstops> + <tabstop>hostEdit</tabstop> + <tabstop>portEdit</tabstop> + <tabstop>passwordEdit</tabstop> + <tabstop>deviceTypeComboBox</tabstop> + </tabstops> + <resources/> + <connections> + <connection> + <sender>buttonBox</sender> + <signal>accepted()</signal> + <receiver>MicroPythonWebreplConnectionDialog</receiver> + <slot>accept()</slot> + <hints> + <hint type="sourcelabel"> + <x>248</x> + <y>254</y> + </hint> + <hint type="destinationlabel"> + <x>157</x> + <y>274</y> + </hint> + </hints> + </connection> + <connection> + <sender>buttonBox</sender> + <signal>rejected()</signal> + <receiver>MicroPythonWebreplConnectionDialog</receiver> + <slot>reject()</slot> + <hints> + <hint type="sourcelabel"> + <x>316</x> + <y>260</y> + </hint> + <hint type="destinationlabel"> + <x>286</x> + <y>274</y> + </hint> + </hints> + </connection> + </connections> +</ui>
--- a/src/eric7/MicroPython/MicroPythonWebreplUrlAddEditDialog.py Tue May 02 18:01:34 2023 +0200 +++ b/src/eric7/MicroPython/MicroPythonWebreplUrlAddEditDialog.py Wed May 03 10:12:03 2023 +0200 @@ -53,6 +53,7 @@ self.__populateFields(connectionParams) else: self.__editName = "" + self.__updateOkButton() msh = self.minimumSizeHint() self.resize(max(self.width(), msh.width()), msh.height()) @@ -68,14 +69,8 @@ self.descriptionEdit.setText(params[1]) url = params[2].replace("ws://", "") - if "@" in url: - password, hostPort = url.split("@", 1) - else: - password, hostPort = "", url - if ":" in hostPort: - host, port = hostPort.split(":", 1) - else: - host, port = hostPort, "" + password, hostPort = url.split("@", 1) if "@" in url else ("", url) + host, port = hostPort.split(":", 1) if ":" in hostPort else (hostPort, "") self.hostEdit.setText(host) self.portEdit.setText(port) self.passwordEdit.setText(password) @@ -115,9 +110,9 @@ """ Public method to retrieve the entered WebREPL connection data. - @return tuple containing the name, description and URL for the WebREPL - connection - @rtype tuple of (str, str, str) + @return tuple containing the name, description, URL and device type for + the WebREPL connection + @rtype tuple of (str, str, str, str) """ password = self.passwordEdit.text() host = self.hostEdit.text()
--- a/src/eric7/MicroPython/MicroPythonWebreplUrlsConfigDialog.py Tue May 02 18:01:34 2023 +0200 +++ b/src/eric7/MicroPython/MicroPythonWebreplUrlsConfigDialog.py Wed May 03 10:12:03 2023 +0200 @@ -35,12 +35,12 @@ super().__init__(parent) self.setupUi(self) - for name in webreplDict: + for name, data in webreplDict.items(): itm = QTreeWidgetItem( self.webreplUrlsList, - [name, webreplDict[name]["description"], webreplDict[name]["url"]], + [name, data["description"], data["url"]], ) - itm.setData(0, Qt.ItemDataRole.UserRole, webreplDict["device_type"]) + itm.setData(0, Qt.ItemDataRole.UserRole, data["device_type"]) self.__sortItems() self.__resizeColumns()
--- a/src/eric7/MicroPython/MicroPythonWidget.py Tue May 02 18:01:34 2023 +0200 +++ b/src/eric7/MicroPython/MicroPythonWidget.py Wed May 03 10:12:03 2023 +0200 @@ -298,6 +298,8 @@ self.__lastPort = None self.__lastDeviceType = None + self.__lastWebreplUrl = None + self.__interface = None self.__device = None self.__connected = False @@ -428,12 +430,13 @@ self.deviceTypeComboBox.setItemData( index, webreplUrlsDict[name]["url"], self.DeviceWebreplUrlRole ) - if webreplUrlsDict: - webreplMessage = self.tr( + webreplMessage = ( + self.tr( "\n%n WebREPL connection(s) defined.", "", len(webreplUrlsDict) ) - else: - webreplMessage = "" + if webreplUrlsDict + else "" + ) self.deviceInfoLabel.setText(supportedMessage + unknownMessage + webreplMessage) @@ -527,7 +530,7 @@ Private slot to configure the list of selectable WebREPL URLs. """ from .MicroPythonWebreplUrlsConfigDialog import ( - MicroPythonWebreplUrlsConfigDialog + MicroPythonWebreplUrlsConfigDialog, ) webreplUrlsDict = Preferences.getMicroPython("WebreplUrls") @@ -808,7 +811,7 @@ """ self.replEdit.clear() if bool(self.__interface) and self.__interface.isConnected(): - self.__interface.write(b"\r") + self.__interface.write(b"\r") @pyqtSlot() def __paste(self, mode=QClipboard.Mode.Clipboard): @@ -891,7 +894,7 @@ tc.movePosition(QTextCursor.MoveOperation.EndOfLine) self.replEdit.setTextCursor(tc) if bool(self.__interface) and self.__interface.isConnected(): - self.__interface.write(msg) + self.__interface.write(msg) return True else: # standard event processing @@ -1228,6 +1231,9 @@ @exception ValueError raised to indicate an unsupported interface type """ from .ConnectionSelectionDialog import ConnectionSelectionDialog + from .MicroPythonWebreplConnectionDialog import ( + MicroPythonWebreplConnectionDialog, + ) interfaceType = ( self.deviceTypeComboBox.currentData(self.DeviceInterfaceTypeRole) @@ -1263,8 +1269,22 @@ elif interfaceType == "webrepl": port = self.deviceTypeComboBox.currentData(self.DeviceWebreplUrlRole) if not port: - # TODO: implement Webrepl parameter dialog (ws:// URL) - return + with EricOverridenCursor(): + dlg = MicroPythonWebreplConnectionDialog( + self.__lastWebreplUrl, self.__lastDeviceType + ) + if dlg.exec() == QDialog.DialogCode.Accepted: + port, deviceType = dlg.getWebreplConnectionParameters() + + self.deviceIconLabel.setPixmap( + Devices.getDeviceIcon(deviceType, False) + ) + self.__device = Devices.getDevice(deviceType, self, None, None) + + self.__lastWebreplUrl = port + self.__lastDeviceType = deviceType + else: + return self.__interface = MicroPythonWebreplDeviceInterface(self)