Thu, 04 Feb 2021 14:38:01 +0100
MicroPython: added buttons to go to the 'home' directory (local and on device) to the MicroPython file manager and improved the workspace handling.
--- a/eric6/MicroPython/CircuitPythonDevices.py Thu Feb 04 14:35:50 2021 +0100 +++ b/eric6/MicroPython/CircuitPythonDevices.py Thu Feb 04 14:38:01 2021 +0100 @@ -137,6 +137,7 @@ @return flag indicated a mounted device @rtype bool """ + self.__workspace = "" # reset before checking return self.DeviceVolumeName in self.getWorkspace(silent=True) def getWorkspace(self, silent=False): @@ -157,7 +158,7 @@ def __findWorkspace(self, silent=False): """ - Public method to find the workspace directory. + Private method to find the workspace directory. @param silent flag indicating silent operations @type bool @@ -167,7 +168,7 @@ # Attempts to find the paths on the filesystem that represents the # plugged in CIRCUITPY boards. deviceDirectories = Utilities.findVolume(self.DeviceVolumeName, - all=True) + findAll=True) if deviceDirectories: if len(deviceDirectories) == 1: @@ -181,11 +182,12 @@ E5MessageBox.warning( self.microPython, self.tr("Workspace Directory"), - self.tr("Python files for CircuitPython devices are stored" - " on the device. Therefore, to edit these files" - " you need to have the device plugged in. Until" - " you plug in a device, the standard directory" - " will be used.")) + self.tr("Python files for CircuitPython can be edited in" + " place, if the device volume is locally" + " available. Such a volume was not found. In" + " place editing will not be available." + ) + ) return super(CircuitPythonDevice, self).getWorkspace() @@ -265,15 +267,6 @@ @rtype str """ return Preferences.getMicroPython("CircuitPythonDocuUrl") -## -## def getFirmwareUrl(self): -## """ -## Public method to get the device firmware download URL. -## -## @return firmware download URL of the device -## @rtype str -## """ -## return Preferences.getMicroPython("CircuitPythonFirmwareUrl") def getDownloadMenuEntries(self): """
--- a/eric6/MicroPython/CircuitPythonFirmwareSelectionDialog.py Thu Feb 04 14:35:50 2021 +0100 +++ b/eric6/MicroPython/CircuitPythonFirmwareSelectionDialog.py Thu Feb 04 14:38:01 2021 +0100 @@ -142,7 +142,8 @@ if volumeName and volumeName != self.__manualMarker: # check if the user selected a board and the board is in # bootloader mode - deviceDirectories = Utilities.findVolume(volumeName, all=True) + deviceDirectories = Utilities.findVolume(volumeName, + findAll=True) if len(deviceDirectories) > 1: enable = False E5MessageBox.warning(
--- a/eric6/MicroPython/MicroPythonDevices.py Thu Feb 04 14:35:50 2021 +0100 +++ b/eric6/MicroPython/MicroPythonDevices.py Thu Feb 04 14:38:01 2021 +0100 @@ -360,8 +360,11 @@ @return workspace directory used for saving files @rtype str """ - return (Preferences.getMultiProject("Workspace") or - os.path.expanduser("~")) + return ( + Preferences.getMicroPython("MpyWorkspace") or + Preferences.getMultiProject("Workspace") or + os.path.expanduser("~") + ) def selectDeviceDirectory(self, deviceDirectories): """
--- a/eric6/MicroPython/MicroPythonFileManagerWidget.py Thu Feb 04 14:35:50 2021 +0100 +++ b/eric6/MicroPython/MicroPythonFileManagerWidget.py Thu Feb 04 14:38:01 2021 +0100 @@ -64,11 +64,14 @@ self.getButton.setIcon(UI.PixmapCache.getIcon("1leftarrow")) self.getAsButton.setIcon(UI.PixmapCache.getIcon("getAs")) self.localUpButton.setIcon(UI.PixmapCache.getIcon("1uparrow")) + self.localHomeButton.setIcon(UI.PixmapCache.getIcon("home")) self.localReloadButton.setIcon(UI.PixmapCache.getIcon("reload")) self.deviceUpButton.setIcon(UI.PixmapCache.getIcon("1uparrow")) + self.deviceHomeButton.setIcon(UI.PixmapCache.getIcon("home")) self.deviceReloadButton.setIcon(UI.PixmapCache.getIcon("reload")) self.deviceUpButton.setEnabled(not self.__repl.isMicrobit()) + self.deviceHomeButton.setEnabled(not self.__repl.isMicrobit()) self.putButton.setEnabled(False) self.putAsButton.setEnabled(False) @@ -154,16 +157,21 @@ if aw: dirname = os.path.dirname(aw.getFileName()) if not dirname: - dirname = (Preferences.getMultiProject("Workspace") or - os.path.expanduser("~")) + dirname = ( + Preferences.getMicroPython("MpyWorkspace") or + Preferences.getMultiProject("Workspace") or + os.path.expanduser("~") + ) self.__listLocalFiles(dirname) if self.__deviceWithLocalAccess: dirname = self.__repl.getDeviceWorkspace() if dirname: self.__listLocalFiles(dirname, True) - else: - self.__fileManager.pwd() + return + + # list files via device script + self.__fileManager.pwd() def stop(self): """ @@ -298,6 +306,18 @@ self.__listLocalFiles(dirname) @pyqtSlot() + def on_localHomeButton_clicked(self): + """ + Private slot to change directory to the configured workspace. + """ + dirname = ( + Preferences.getMicroPython("MpyWorkspace") or + Preferences.getMultiProject("Workspace") or + os.path.expanduser("~") + ) + self.__listLocalFiles(dirname) + + @pyqtSlot() def on_localReloadButton_clicked(self): """ Private slot to reload the local list. @@ -318,14 +338,19 @@ @param column column of the activation @type int """ - name = os.path.join(self.deviceCwd.text(), item.text(0)) if self.__deviceWithLocalAccess: + name = os.path.join(self.deviceCwd.text(), item.text(0)) if name.endswith("/"): # directory names end with a '/' self.__listLocalFiles(name[:-1], True) elif Utilities.MimeTypes.isTextFile(name): e5App().getObject("ViewManager").getEditor(name) else: + cwd = self.deviceCwd.text() + if cwd.endswith("/"): + name = cwd + item.text(0) + else: + name = "{0}/{1}".format(cwd, item.text(0)) if name.endswith("/"): # directory names end with a '/' self.__fileManager.cd(name[:-1]) @@ -356,6 +381,20 @@ self.__fileManager.cd(dirname) @pyqtSlot() + def on_deviceHomeButton_clicked(self): + """ + Private slot to move to the device home directory. + """ + if self.__deviceWithLocalAccess: + dirname = self.__repl.getDeviceWorkspace() + if dirname: + self.__listLocalFiles(dirname, True) + return + + # list files via device script + self.__fileManager.cd("/") + + @pyqtSlot() def on_deviceReloadButton_clicked(self): """ Private slot to reload the device list.
--- a/eric6/MicroPython/MicroPythonFileManagerWidget.ui Thu Feb 04 14:35:50 2021 +0100 +++ b/eric6/MicroPython/MicroPythonFileManagerWidget.ui Thu Feb 04 14:38:01 2021 +0100 @@ -213,6 +213,13 @@ </widget> </item> <item> + <widget class="QToolButton" name="localHomeButton"> + <property name="toolTip"> + <string>Press to move to the configured home directory</string> + </property> + </widget> + </item> + <item> <widget class="QToolButton" name="localReloadButton"> <property name="toolTip"> <string>Press to reload the list</string> @@ -241,6 +248,13 @@ </widget> </item> <item> + <widget class="QToolButton" name="deviceHomeButton"> + <property name="toolTip"> + <string>Press to move to the device workspace directory</string> + </property> + </widget> + </item> + <item> <widget class="QToolButton" name="deviceReloadButton"> <property name="toolTip"> <string>Press to reload the list</string> @@ -269,9 +283,11 @@ <tabstop>getAsButton</tabstop> <tabstop>localCwd</tabstop> <tabstop>localUpButton</tabstop> + <tabstop>localHomeButton</tabstop> <tabstop>localReloadButton</tabstop> <tabstop>deviceCwd</tabstop> <tabstop>deviceUpButton</tabstop> + <tabstop>deviceHomeButton</tabstop> <tabstop>deviceReloadButton</tabstop> </tabstops> <resources/>
--- a/eric6/MicroPython/MicroPythonGraphWidget.py Thu Feb 04 14:35:50 2021 +0100 +++ b/eric6/MicroPython/MicroPythonGraphWidget.py Thu Feb 04 14:38:01 2021 +0100 @@ -306,8 +306,11 @@ @return flag indicating success @rtype bool """ - baseDir = (Preferences.getMultiProject("Workspace") or - os.path.expanduser("~")) + baseDir = ( + Preferences.getMicroPython("MpyWorkspace") or + Preferences.getMultiProject("Workspace") or + os.path.expanduser("~") + ) dataDir = os.path.join(baseDir, "data_capture") if not os.path.exists(dataDir):
--- a/eric6/MicroPython/MicroPythonWidget.py Thu Feb 04 14:35:50 2021 +0100 +++ b/eric6/MicroPython/MicroPythonWidget.py Thu Feb 04 14:38:01 2021 +0100 @@ -1000,14 +1000,15 @@ self.__showNoDeviceMessage() return - workspace = self.__device.getWorkspace() - fileName = E5FileDialog.getOpenFileName( - self, - self.tr("Open Python File"), - workspace, - self.tr("Python3 Files (*.py);;All Files (*)")) - if fileName: - e5App().getObject("ViewManager").openSourceFile(fileName) + workspace = self.getDeviceWorkspace() + if workspace: + fileName = E5FileDialog.getOpenFileName( + self, + self.tr("Open Python File"), + workspace, + self.tr("Python3 Files (*.py);;All Files (*)")) + if fileName: + e5App().getObject("ViewManager").openSourceFile(fileName) @pyqtSlot() def on_saveButton_clicked(self): @@ -1018,10 +1019,11 @@ self.__showNoDeviceMessage() return - workspace = self.__device.getWorkspace() aw = e5App().getObject("ViewManager").activeWindow() if aw: - aw.saveFileAs(workspace) + workspace = self.getDeviceWorkspace() + if workspace: + aw.saveFileAs(workspace) @pyqtSlot(bool) def on_chartButton_clicked(self, checked): @@ -1132,21 +1134,26 @@ """<p>Reason: {0}</p>""").format(reason)) return - if not self.__interface.isConnected(): - self.__connectToDevice() - self.__fileManagerWidget = MicroPythonFileManagerWidget( - self.__interface, self.__device.supportsLocalFileAccess(), - self) - - self.__ui.addSideWidget(self.__ui.BottomSide, - self.__fileManagerWidget, - UI.PixmapCache.getIcon("filemanager"), - self.tr("µPy Files")) - self.__ui.showSideWidget(self.__fileManagerWidget) + with E5OverrideCursor(): + if not self.__interface.isConnected(): + self.__connectToDevice() + if self.__connected: + self.__fileManagerWidget = MicroPythonFileManagerWidget( + self.__interface, + self.__device.supportsLocalFileAccess(), + self) + + self.__ui.addSideWidget( + self.__ui.BottomSide, + self.__fileManagerWidget, + UI.PixmapCache.getIcon("filemanager"), + self.tr("µPy Files") + ) + self.__ui.showSideWidget(self.__fileManagerWidget) - self.__device.setFileManager(True) - - self.__fileManagerWidget.start() + self.__device.setFileManager(True) + + self.__fileManagerWidget.start() else: self.__fileManagerWidget.stop() @@ -1497,7 +1504,11 @@ if fn: defaultDirectory = os.path.dirname(fn) if not defaultDirectory: - defaultDirectory = Preferences.getMultiProject("Workspace") + defaultDirectory = ( + Preferences.getMicroPython("MpyWorkspace") or + Preferences.getMultiProject("Workspace") or + os.path.expanduser("~") + ) pythonFile = E5FileDialog.getOpenFileName( self, title,
--- a/eric6/MicroPython/MicrobitDevices.py Thu Feb 04 14:35:50 2021 +0100 +++ b/eric6/MicroPython/MicrobitDevices.py Thu Feb 04 14:38:01 2021 +0100 @@ -42,8 +42,6 @@ super(MicrobitDevice, self).__init__(microPythonWidget, parent) self.__deviceType = deviceType - - self.__workspace = self.__findWorkspace() def setButtons(self): """ @@ -127,52 +125,6 @@ """ return True, "" - def getWorkspace(self): - """ - Public method to get the workspace directory. - - @return workspace directory used for saving files - @rtype str - """ - if self.__workspace: - # return cached entry - return self.__workspace - else: - self.__workspace = self.__findWorkspace() - return self.__workspace - - def __findWorkspace(self): - """ - Public method to find the workspace directory. - - @return workspace directory used for saving files - @rtype str - """ - # Attempts to find the path on the filesystem that represents the - # plugged in MICROBIT or MINI board. - if self.__deviceType == "bbc_microbit": - # BBC micro:bit - deviceDirectories = Utilities.findVolume("MICROBIT", all=True) - else: - # Calliope mini - deviceDirectories = Utilities.findVolume("MINI", all=True) - - if deviceDirectories: - if len(deviceDirectories) == 1: - return deviceDirectories[0] - else: - return self.selectDeviceDirectory(deviceDirectories) - else: - # return the default workspace and give the user a warning - E5MessageBox.warning( - self.microPython, - self.tr("Workspace Directory"), - self.tr("Could not find an attached {0}.\n\n" - "Please make sure the device is plugged " - "into this computer.").format(self.deviceName())) - - return super(MicrobitDevice, self).getWorkspace() - def hasTimeCommands(self): """ Public method to check, if the device supports time commands. @@ -230,17 +182,18 @@ # BBC micro:bit if firmware: deviceDirectories = Utilities.findVolume("MAINTENANCE", - all=True) + findAll=True) else: deviceDirectories = Utilities.findVolume("MICROBIT", - all=True) + findAll=True) else: # Calliope mini if firmware: deviceDirectories = Utilities.findVolume("MAINTENANCE", - all=True) + findAll=True) else: - deviceDirectories = Utilities.findVolume("MINI", all=True) + deviceDirectories = Utilities.findVolume("MINI", + findAll=True) if len(deviceDirectories) == 0: if self.__deviceType == "bbc_microbit": # BBC micro:bit is not ready or not mounted
--- a/eric6/MicroPython/PyBoardDevices.py Thu Feb 04 14:35:50 2021 +0100 +++ b/eric6/MicroPython/PyBoardDevices.py Thu Feb 04 14:38:01 2021 +0100 @@ -162,7 +162,7 @@ def __findWorkspace(self, silent=False): """ - Public method to find the workspace directory. + Private method to find the workspace directory. @param silent flag indicating silent operations @type bool @@ -172,7 +172,7 @@ # Attempts to find the path on the filesystem that represents the # plugged in PyBoard board. deviceDirectories = Utilities.findVolume(self.DeviceVolumeName, - all=True) + findAll=True) if deviceDirectories: if len(deviceDirectories) == 1: @@ -186,11 +186,12 @@ E5MessageBox.warning( self.microPython, self.tr("Workspace Directory"), - self.tr("Python files for PyBoard devices are stored" - " on the device. Therefore, to edit these files" - " you need to have the device plugged in. Until" - " you plug in a device, the standard directory" - " will be used.")) + self.tr("Python files for PyBoard can be edited in" + " place, if the device volume is locally" + " available. Such a volume was not found. In" + " place editing will not be available." + ) + ) return super(PyBoardDevice, self).getWorkspace()
--- a/eric6/Preferences/ConfigurationPages/MicroPythonPage.py Thu Feb 04 14:35:50 2021 +0100 +++ b/eric6/Preferences/ConfigurationPages/MicroPythonPage.py Thu Feb 04 14:38:01 2021 +0100 @@ -13,6 +13,7 @@ from .Ui_MicroPythonPage import Ui_MicroPythonPage import Preferences +import Utilities from MicroPython.MicroPythonWidget import AnsiColorSchemes @@ -32,6 +33,8 @@ self.setupUi(self) self.setObjectName("MicroPythonPage") + self.workspacePicker.setMode(E5PathPickerModes.DirectoryMode) + self.colorSchemeComboBox.addItems(sorted(AnsiColorSchemes.keys())) # populate the chart theme combobox @@ -66,6 +69,12 @@ self.dfuUtilPathPicker.setFilters(self.tr("All Files (*)")) # set initial values + # workspace + self.workspacePicker.setText( + Utilities.toNativeSeparators( + Preferences.getMicroPython("MpyWorkspace") or + Utilities.getHomeDir())) + # serial link parameters self.timeoutSpinBox.setValue( Preferences.getMicroPython("SerialTimeout") / 1000) @@ -130,6 +139,11 @@ """ Public slot to save the MicroPython configuration. """ + # workspace + Preferences.setMicroPython( + "MpyWorkspace", + self.workspacePicker.text()) + # serial link parameters Preferences.setMicroPython( "SerialTimeout",
--- a/eric6/Preferences/ConfigurationPages/MicroPythonPage.ui Thu Feb 04 14:35:50 2021 +0100 +++ b/eric6/Preferences/ConfigurationPages/MicroPythonPage.ui Thu Feb 04 14:38:01 2021 +0100 @@ -7,7 +7,7 @@ <x>0</x> <y>0</y> <width>476</width> - <height>1031</height> + <height>1087</height> </rect> </property> <layout class="QVBoxLayout" name="verticalLayout"> @@ -32,6 +32,31 @@ </widget> </item> <item> + <widget class="QGroupBox" name="groupBox_4"> + <property name="title"> + <string>Workspace</string> + </property> + <layout class="QHBoxLayout" name="horizontalLayout_4"> + <item> + <widget class="E5PathPicker" name="workspacePicker" native="true"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Expanding" vsizetype="Preferred"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="focusPolicy"> + <enum>Qt::StrongFocus</enum> + </property> + <property name="toolTip"> + <string>Enter the name of the MicroPython workspace directory</string> + </property> + </widget> + </item> + </layout> + </widget> + </item> + <item> <widget class="QGroupBox" name="groupBox_2"> <property name="title"> <string>Serial Link</string> @@ -449,6 +474,7 @@ </customwidget> </customwidgets> <tabstops> + <tabstop>workspacePicker</tabstop> <tabstop>timeoutSpinBox</tabstop> <tabstop>syncTimeCheckBox</tabstop> <tabstop>colorSchemeComboBox</tabstop>
--- a/eric6/Preferences/__init__.py Thu Feb 04 14:35:50 2021 +0100 +++ b/eric6/Preferences/__init__.py Thu Feb 04 14:38:01 2021 +0100 @@ -1445,6 +1445,7 @@ # defaults for MicroPython microPythonDefaults = { + "MpyWorkspace": "", "SerialTimeout": 2000, # timeout in milliseconds "ReplLineWrap": True, # wrap the REPL lines "SyncTimeAfterConnect": True,
--- a/eric6/Utilities/__init__.py Thu Feb 04 14:35:50 2021 +0100 +++ b/eric6/Utilities/__init__.py Thu Feb 04 14:38:01 2021 +0100 @@ -1238,21 +1238,19 @@ return dirs -def findVolume(volumeName, all=False): +def findVolume(volumeName, findAll=False): """ Function to find the directory belonging to a given volume name. @param volumeName name of the volume to search for @type str - @param all flag indicating to get the directories for all volumes + @param findAll flag indicating to get the directories for all volumes starting with the given name (defaults to False) @type bool (optional) @return directory path or list of directory paths for the given volume name @rtype str or list of str """ - # TODO: add option to get all (i.e. all starting with volumeName) - # and return a list of found directories volumeDirectories = [] volumeDirectory = None @@ -1285,7 +1283,7 @@ for disk in "ABCDEFGHIJKLMNOPQRSTUVWXYZ": dirpath = "{0}:\\".format(disk) if os.path.exists(dirpath): - if all: + if findAll: if getVolumeName(dirpath).startswith(volumeName): volumeDirectories.append(dirpath) else: @@ -1302,7 +1300,7 @@ subprocess.check_output(mountCommand).splitlines() # secok ) mountedVolumes = [x.split()[2] for x in mountOutput] - if all: + if findAll: for volume in mountedVolumes: if volumeName in volume.decode("utf-8"): volumeDirectories.append(volume.decode("utf-8")) @@ -1318,7 +1316,7 @@ except FileNotFoundError: pass - if all: + if findAll: return volumeDirectories else: return volumeDirectory