eric6/MicroPython/MicroPythonFileManagerWidget.py

branch
micropython
changeset 7082
ec199ef0cfc6
parent 7081
ed510767c096
child 7083
217862c28319
--- a/eric6/MicroPython/MicroPythonFileManagerWidget.py	Tue Jul 23 19:43:14 2019 +0200
+++ b/eric6/MicroPython/MicroPythonFileManagerWidget.py	Wed Jul 24 20:12:19 2019 +0200
@@ -11,10 +11,13 @@
 
 import os
 
-from PyQt5.QtCore import pyqtSlot, Qt
-from PyQt5.QtWidgets import QWidget, QTreeWidgetItem, QHeaderView
+from PyQt5.QtCore import pyqtSlot, Qt, QPoint
+from PyQt5.QtWidgets import (
+    QWidget, QTreeWidgetItem, QHeaderView, QMenu, QInputDialog, QLineEdit
+)
 
-from E5Gui import E5MessageBox
+from E5Gui import E5MessageBox, E5PathPickerDialog
+from E5Gui.E5PathPicker import E5PathPickerModes
 from E5Gui.E5Application import e5App
 
 from .Ui_MicroPythonFileManagerWidget import Ui_MicroPythonFileManagerWidget
@@ -64,34 +67,49 @@
         self.__fileManager.longListFiles.connect(self.__handleLongListFiles)
         self.__fileManager.currentDir.connect(self.__handleCurrentDir)
         self.__fileManager.currentDirChanged.connect(self.__handleCurrentDir)
-        self.__fileManager.putFileDone.connect(self.__handlePutDone)
+        self.__fileManager.putFileDone.connect(self.__newDeviceList)
         self.__fileManager.getFileDone.connect(self.__handleGetDone)
         self.__fileManager.rsyncDone.connect(self.__handleRsyncDone)
         self.__fileManager.rsyncMessages.connect(self.__handleRsyncMessages)
+        self.__fileManager.removeDirectoryDone.connect(self.__newDeviceList)
+        self.__fileManager.createDirectoryDone.connect(self.__newDeviceList)
+        self.__fileManager.deleteFileDone.connect(self.__newDeviceList)
+        self.__fileManager.synchTimeDone.connect(self.__timeSynchronized)
+        self.__fileManager.showTimeDone.connect(self.__deviceTimeReceived)
+        self.__fileManager.showVersionDone.connect(
+            self.__deviceVersionReceived)
         
-        self.__fileManager.longListFilesFailed.connect(self.__handleError)
-        self.__fileManager.currentDirFailed.connect(self.__handleError)
-        self.__fileManager.currentDirChangeFailed.connect(self.__handleError)
-        self.__fileManager.putFileFailed.connect(self.__handleError)
-        self.__fileManager.getFileFailed.connect(self.__handleError)
-        self.__fileManager.rsyncFailed.connect(self.__handleError)
+        self.__fileManager.error.connect(self.__handleError)
+        
+        self.localFileTreeWidget.customContextMenuRequested.connect(
+            self.__showLocalContextMenu)
+        self.deviceFileTreeWidget.customContextMenuRequested.connect(
+            self.__showDeviceContextMenu)
+        
+        self.__localMenu = QMenu(self)
+        self.__localMenu.addAction(self.tr("Change Directory"),
+                                   self.__changeLocalDirectory)
         
-        # TODO: add context menus for panes (separate menus)
-        # local pane:
-        #  Change Directory
-        #
-        # device pane:
-        #  Change Directory
-        #  Create Directory
-        #  Delete Directory
-        #  Delete Directory Tree (= recursive delete)
-        #  ----------------------------
-        #  Delete File
-        #  ----------------------------
-        #  Synchronize Time
-        #  Show Time
-        #  ----------------------------
-        #  Show Version
+        self.__deviceMenu = QMenu(self)
+        self.__deviceMenu.addAction(
+            self.tr("Change Directory"), self.__changeDeviceDirectory)
+        self.__deviceMenu.addAction(
+            self.tr("Create Directory"), self.__createDeviceDirectory)
+        self.__devDelDirAct = self.__deviceMenu.addAction(
+            self.tr("Delete Directory"), self.__deleteDeviceDirectory)
+        self.__devDelDirTreeAct = self.__deviceMenu.addAction(
+            self.tr("Delete Directory Tree"), self.__deleteDeviceDirectoryTree)
+        self.__deviceMenu.addSeparator()
+        self.__devDelFileAct = self.__deviceMenu.addAction(
+            self.tr("Delete File"), self.__deleteDeviceFile)
+        self.__deviceMenu.addSeparator()
+        self.__deviceMenu.addAction(
+            self.tr("Synchronize Time"), self.__synchronizeTime)
+        self.__deviceMenu.addAction(
+            self.tr("Show Time"), self.__showDeviceTime)
+        self.__deviceMenu.addSeparator()
+        self.__deviceMenu.addAction(
+            self.tr("Show Version"), self.__showDeviceVersion)
     
     def start(self):
         """
@@ -117,11 +135,13 @@
         """
         self.__fileManager.disconnect()
     
-    @pyqtSlot(str)
-    def __handleError(self, error):
+    @pyqtSlot(str, str)
+    def __handleError(self, method, error):
         """
         Private slot to handle errors.
         
+        @param method name of the method the error occured in
+        @type str
         @param error error message
         @type str
         """
@@ -129,7 +149,8 @@
             self,
             self.tr("Error handling device"),
             self.tr("<p>There was an error communicating with the connected"
-                    " device.</p><p>Message: {0}</p>").format(error))
+                    " device.</p><p>Method: {0}</p><p>Message: {1}</p>")
+            .format(method, error))
     
     @pyqtSlot(str)
     def __handleCurrentDir(self, dirname):
@@ -305,13 +326,23 @@
                                 " connected device. Overwrite it?</p>")
                         .format(filename)
                     )
-                    if not ok:
-                        return
-                    # TODO: allow to rename the new file
+                    if ok:
+                        deviceFilename = filename
+                    else:
+                        deviceFilename, ok = QInputDialog.getText(
+                            self,
+                            self.tr("Copy File to Device"),
+                            self.tr("Enter a new name:"),
+                            QLineEdit.Normal,
+                            filename)
+                        if not ok or not bool(deviceFilename):
+                            return
+                else:
+                    deviceFilename = filename
                 
                 self.__fileManager.put(
                     os.path.join(self.localCwd.text(), filename),
-                    os.path.join(self.deviceCwd.text(), filename)
+                    os.path.join(self.deviceCwd.text(), deviceFilename)
                 )
     
     @pyqtSlot()
@@ -333,28 +364,26 @@
                                 " Overwrite it?</p>")
                         .format(filename)
                     )
-                    if not ok:
-                        return
-                    # TODO: allow to rename the new file
+                    if ok:
+                        localFilename = filename
+                    else:
+                        localFilename, ok = QInputDialog.getText(
+                            self,
+                            self.tr("Copy File from Device"),
+                            self.tr("Enter a new name:"),
+                            QLineEdit.Normal,
+                            filename)
+                        if not ok or not bool(localFilename):
+                            return
+                else:
+                    localFilename = filename
                 
                 self.__fileManager.get(
                     os.path.join(self.deviceCwd.text(), filename),
-                    os.path.join(self.localCwd.text(), filename)
+                    os.path.join(self.localCwd.text(), localFilename)
                 )
     
     @pyqtSlot(str, str)
-    def __handlePutDone(self, localFile, deviceFile):
-        """
-        Private slot handling a successful copy of a file to the device.
-        
-        @param localFile name of the local file
-        @type str
-        @param deviceFile name of the file on the device
-        @type str
-        """
-        self.__fileManager.lls(self.deviceCwd.text())
-    
-    @pyqtSlot(str, str)
     def __handleGetDone(self, deviceFile, localFile):
         """
         Private slot handling a successful copy of a file from the device.
@@ -406,3 +435,210 @@
                 "</li><li>".join(messages)
             )
         )
+    
+    @pyqtSlot()
+    def __newDeviceList(self):
+        """
+        Private slot to initiate a new long list of the device directory.
+        """
+        self.__fileManager.lls(self.deviceCwd.text())
+    
+    ##################################################################
+    ## Context menu methods for the local files below
+    ##################################################################
+    
+    @pyqtSlot(QPoint)
+    def __showLocalContextMenu(self, pos):
+        """
+        Private slot to show the REPL context menu.
+        
+        @param pos position to show the menu at
+        @type QPoint
+        """
+        self.__localMenu.exec_(self.localFileTreeWidget.mapToGlobal(pos))
+    
+    @pyqtSlot()
+    def __changeLocalDirectory(self):
+        """
+        Private slot to change the local directory.
+        """
+        path, ok = E5PathPickerDialog.getPath(
+            self,
+            self.tr("Change Directory"),
+            self.tr("Select Directory"),
+            E5PathPickerModes.DirectoryShowFilesMode,
+            defaultDirectory=self.localCwd.text(),
+        )
+        if ok and path:
+            self.localCwd.setText(path)
+            self.__listLocalFiles(path)
+    
+    ##################################################################
+    ## Context menu methods for the device files below
+    ##################################################################
+    
+    @pyqtSlot(QPoint)
+    def __showDeviceContextMenu(self, pos):
+        """
+        Private slot to show the REPL context menu.
+        
+        @param pos position to show the menu at
+        @type QPoint
+        """
+        hasSelection = bool(len(self.deviceFileTreeWidget.selectedItems()))
+        if hasSelection:
+            name = self.deviceFileTreeWidget.selectedItems()[0].text(0)
+            isDir = name.endswith("/")
+            isFile = not isDir
+        else:
+            isDir = False
+            isFile = False
+        self.__devDelDirAct.setEnabled(isDir)
+        self.__devDelDirTreeAct.setEnabled(isDir)
+        self.__devDelFileAct.setEnabled(isFile)
+        
+        self.__deviceMenu.exec_(self.deviceFileTreeWidget.mapToGlobal(pos))
+    
+    @pyqtSlot()
+    def __changeDeviceDirectory(self):
+        """
+        Private slot to change the current directory of the device.
+        
+        Note: This triggers a re-population of the device list for the new
+        current directory.
+        """
+        dirPath, ok = QInputDialog.getText(
+            self,
+            self.tr("Change Directory"),
+            self.tr("Enter the full directory path on the device:"),
+            QLineEdit.Normal,
+            self.deviceCwd.text())
+        if ok and dirPath:
+            self.__fileManager.cd(dirPath)
+    
+    @pyqtSlot()
+    def __createDeviceDirectory(self):
+        """
+        Private slot to create a directory on the device.
+        """
+        dirPath, ok = QInputDialog.getText(
+            self,
+            self.tr("Create Directory"),
+            self.tr("Enter directory name:"),
+            QLineEdit.Normal)
+        if ok and dirPath:
+            self.__fileManager.mkdir(dirPath)
+    
+    @pyqtSlot()
+    def __deleteDeviceDirectory(self):
+        """
+        Private slot to delete an empty directory on the device.
+        """
+        if bool(len(self.deviceFileTreeWidget.selectedItems())):
+            name = self.deviceFileTreeWidget.selectedItems()[0].text(0)
+            dirname = self.deviceCwd.text() + "/" + name[:-1]
+            self.__fileManager.rmdir(dirname)
+    
+    @pyqtSlot()
+    def __deleteDeviceDirectoryTree(self):
+        """
+        Private slot to delete a directory and all its subdirectories
+        recursively.
+        """
+        if bool(len(self.deviceFileTreeWidget.selectedItems())):
+            name = self.deviceFileTreeWidget.selectedItems()[0].text(0)
+            dirname = self.deviceCwd.text() + "/" + name[:-1]
+            self.__fileManager.rmdir(dirname, recursive=True)
+    
+    @pyqtSlot()
+    def __deleteDeviceFile(self):
+        """
+        Private slot to delete a file
+        """
+        if bool(len(self.deviceFileTreeWidget.selectedItems())):
+            name = self.deviceFileTreeWidget.selectedItems()[0].text(0)
+            filename = self.deviceCwd.text() + "/" + name
+            self.__fileManager.delete(filename)
+    
+    @pyqtSlot()
+    def __synchronizeTime(self):
+        """
+        Private slot to synchronize the local time to the device.
+        """
+        self.__fileManager.synchronizeTime()
+    
+    @pyqtSlot()
+    def __timeSynchronized(self):
+        """
+        Private slot handling the successful syncronization of the time.
+        """
+        E5MessageBox.information(
+            self,
+            self.tr("Synchronize Time"),
+            self.tr("The time of the connected device was synchronized with"
+                    " the local time."))
+    
+    @pyqtSlot()
+    def __showDeviceTime(self):
+        """
+        Private slot to show the date and time of the connected device.
+        """
+        self.__fileManager.showTime()
+    
+    @pyqtSlot(str)
+    def __deviceTimeReceived(self, dateTimeString):
+        """
+        Private slot handling the receipt of the device date and time.
+        
+        @param dateTimeString string containg the date and time of the device
+        @type str
+        """
+        try:
+            date, time = dateTimeString.strip().split(None, 1)
+            msg = self.tr(
+                "<h3>Device Date and Time</h3>"
+                "<table>"
+                "<tr><td><b>Date</b></td><td>{0}</td></tr>"
+                "<tr><td><b>Time</b></td><td>{1}</td></tr>"
+                "</table>"
+            ).format(date, time)
+        except ValueError:
+            msg = self.tr(
+                "<h3>Device Date and Time</h3>"
+                "<p>{0}</p>"
+            ).format(dateTimeString.strip())
+        E5MessageBox.information(
+            self,
+            self.tr("Device Date and Time"),
+            msg)
+    
+    @pyqtSlot()
+    def __showDeviceVersion(self):
+        """
+        Private slot to show some version info about MicroPython of the device.
+        """
+        self.__fileManager.showVersion()
+    
+    @pyqtSlot(dict)
+    def __deviceVersionReceived(self, versionInfo):
+        """
+        Private slot handling the receipt of the version info.
+        
+        @param versionInfo dictionary containing the version information
+        @type dict
+        """
+        if versionInfo:
+            msg = self.tr(
+                "<h3>Device Version Information</h3>"
+            )
+            msg += "<table>"
+            for key, value in versionInfo.items():
+                msg += "<tr><td><b>{0}</b></td><td>{1}</td></tr>".format(
+                    key, value)
+            msg += "</table>"
+        else:
+            msg = self.tr("No version information available.")
+        E5MessageBox.information(
+            self,
+            self.tr("Device Version Information"),
+            msg)

eric ide

mercurial