MicroPython: continued implementing the file manager widget. micropython

Fri, 26 Jul 2019 20:05:49 +0200

author
Detlev Offenbach <detlev@die-offenbachs.de>
date
Fri, 26 Jul 2019 20:05:49 +0200
branch
micropython
changeset 7084
3eddfc540614
parent 7083
217862c28319
child 7085
328f0f44aa95

MicroPython: continued implementing the file manager widget.

eric6/MicroPython/CircuitPythonDevices.py file | annotate | diff | comparison | revisions
eric6/MicroPython/MicroPythonFileManagerWidget.py file | annotate | diff | comparison | revisions
eric6/MicroPython/MicroPythonFileManagerWidget.ui file | annotate | diff | comparison | revisions
eric6/MicroPython/MicroPythonFileSystem.py file | annotate | diff | comparison | revisions
eric6/MicroPython/MicroPythonFileSystemUtilities.py file | annotate | diff | comparison | revisions
eric6/MicroPython/MicroPythonProgressInfoDialog.py file | annotate | diff | comparison | revisions
eric6/MicroPython/MicroPythonProgressInfoDialog.ui file | annotate | diff | comparison | revisions
eric6/MicroPython/MicroPythonSerialPort.py file | annotate | diff | comparison | revisions
--- a/eric6/MicroPython/CircuitPythonDevices.py	Thu Jul 25 19:55:40 2019 +0200
+++ b/eric6/MicroPython/CircuitPythonDevices.py	Fri Jul 26 20:05:49 2019 +0200
@@ -135,7 +135,7 @@
                     path = '{0}:\\'.format(disk)
                     if (os.path.exists(path) and
                             getVolumeName(path) == 'CIRCUITPY'):
-                        deviceDirectory =  path
+                        deviceDirectory = path
                         break
             finally:
                 ctypes.windll.kernel32.SetErrorMode(oldMode)
--- a/eric6/MicroPython/MicroPythonFileManagerWidget.py	Thu Jul 25 19:55:40 2019 +0200
+++ b/eric6/MicroPython/MicroPythonFileManagerWidget.py	Fri Jul 26 20:05:49 2019 +0200
@@ -10,10 +10,13 @@
 from __future__ import unicode_literals
 
 import os
+import shutil
+import time
 
 from PyQt5.QtCore import pyqtSlot, Qt, QPoint
 from PyQt5.QtWidgets import (
-    QWidget, QTreeWidgetItem, QHeaderView, QMenu, QInputDialog, QLineEdit
+    QWidget, QTreeWidgetItem, QHeaderView, QMenu, QInputDialog, QLineEdit,
+    QDialog
 )
 
 from E5Gui import E5MessageBox, E5PathPickerDialog
@@ -28,6 +31,8 @@
     mtime2string, mode2string, decoratedName, listdirStat
 )
 
+from UI.DeleteFilesConfirmationDialog import DeleteFilesConfirmationDialog
+
 import UI.PixmapCache
 import Preferences
 import Utilities
@@ -53,7 +58,9 @@
         self.putButton.setIcon(UI.PixmapCache.getIcon("1rightarrow"))
         self.getButton.setIcon(UI.PixmapCache.getIcon("1leftarrow"))
         self.localUpButton.setIcon(UI.PixmapCache.getIcon("1uparrow"))
+        self.localReloadButton.setIcon(UI.PixmapCache.getIcon("reload"))
         self.deviceUpButton.setIcon(UI.PixmapCache.getIcon("1uparrow"))
+        self.deviceReloadButton.setIcon(UI.PixmapCache.getIcon("reload"))
         
         self.putButton.setEnabled(False)
         self.getButton.setEnabled(False)
@@ -72,7 +79,6 @@
         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.rsyncProgressMessage.connect(
             self.__handleRsyncProgressMessage)
         self.__fileManager.removeDirectoryDone.connect(self.__newDeviceList)
@@ -93,8 +99,16 @@
         self.__localMenu = QMenu(self)
         self.__localMenu.addAction(self.tr("Change Directory"),
                                    self.__changeLocalDirectory)
-        # TODO: add some more local entries
-        # TODO: add entry to reload
+        self.__localMenu.addAction(
+            self.tr("Create Directory"), self.__createLocalDirectory)
+        self.__localDelDirTreeAct = self.__localMenu.addAction(
+            self.tr("Delete Directory Tree"), self.__deleteLocalDirectoryTree)
+        self.__localMenu.addSeparator()
+        self.__localDelFileAct = self.__localMenu.addAction(
+            self.tr("Delete File"), self.__deleteLocalFile)
+        self.__localMenu.addSeparator()
+        self.__localMenu.addAction(
+            self.tr("Show Time"), self.__showLocalTime)
         
         self.__deviceMenu = QMenu(self)
         self.__deviceMenu.addAction(
@@ -109,8 +123,6 @@
         self.__devDelFileAct = self.__deviceMenu.addAction(
             self.tr("Delete File"), self.__deleteDeviceFile)
         self.__deviceMenu.addSeparator()
-        # TODO: add entry to reload
-        self.__deviceMenu.addSeparator()
         self.__deviceMenu.addAction(
             self.tr("Synchronize Time"), self.__synchronizeTime)
         self.__deviceMenu.addAction(
@@ -181,9 +193,9 @@
         @type tuple of (str, str, str, str)
         """
         self.deviceFileTreeWidget.clear()
-        for name, mode, size, time in filesList:
+        for name, mode, size, dateTime in filesList:
             itm = QTreeWidgetItem(self.deviceFileTreeWidget,
-                                  [name, mode, size, time])
+                                  [name, mode, size, dateTime])
             itm.setTextAlignment(1, Qt.AlignHCenter)
             itm.setTextAlignment(2, Qt.AlignRight)
         self.deviceFileTreeWidget.header().resizeSections(
@@ -258,6 +270,14 @@
         dirname = os.path.dirname(cwd)
         self.__listLocalFiles(dirname)
     
+    @pyqtSlot()
+    def on_localReloadButton_clicked(self):
+        """
+        Private slot to reload the local list.
+        """
+        dirname = self.localCwd.text()
+        self.__listLocalFiles(dirname)
+    
     @pyqtSlot(QTreeWidgetItem, int)
     def on_deviceFileTreeWidget_itemActivated(self, item, column):
         """
@@ -297,6 +317,17 @@
         dirname = os.path.dirname(cwd)
         self.__fileManager.cd(dirname)
     
+    @pyqtSlot()
+    def on_deviceReloadButton_clicked(self):
+        """
+        Private slot to reload the device list.
+        """
+        dirname = self.deviceCwd.text()
+        if dirname:
+            self.__fileManager.lls(dirname)
+        else:
+            self.__fileManager.pwd()
+    
     def __isFileInList(self, filename, treeWidget):
         """
         Private method to check, if a file name is contained in a tree widget.
@@ -327,7 +358,6 @@
                 # it is really a file
                 if self.__isFileInList(filename, self.deviceFileTreeWidget):
                     # ask for overwrite permission
-                    # TODO: test this
                     action, resultFilename = confirmOverwrite(
                         filename, self.tr("Copy File to Device"),
                         self.tr("The given file exists already"
@@ -359,7 +389,6 @@
                 # it is really a file
                 if self.__isFileInList(filename, self.localFileTreeWidget):
                     # ask for overwrite permission
-                    # TODO: test this
                     action, resultFilename = confirmOverwrite(
                         filename, self.tr("Copy File from Device"),
                         self.tr("The given file exists already."),
@@ -393,7 +422,6 @@
         """
         self.__listLocalFiles(self.localCwd.text())
     
-    # TODO: test this
     @pyqtSlot()
     def on_syncButton_clicked(self):
         """
@@ -418,32 +446,31 @@
         self.__listLocalFiles(self.localCwd.text())
         self.__fileManager.lls(self.deviceCwd.text())
     
-    @pyqtSlot(list)
-    def __handleRsyncMessages(self, messages):
-        """
-        Private slot to handle messages from the rsync operation.
-        
-        @param messages list of message generated by the rsync operation
-        @type list
-        """
-        E5MessageBox.information(
-            self,
-            self.tr("rsync Messages"),
-            self.tr("""<p>rsync gave the following messages</p>"""
-                    """<ul><li>{0}</li></ul>""").format(
-                "</li><li>".join(messages)
-            )
-        )
-    
     @pyqtSlot(str)
     def __handleRsyncProgressMessage(self, message):
         """
         Private slot handling progress messages sent by the file manager.
+        
+        @param message message to be shown
+        @type str
         """
-        # TODO: not implemented yet
-        #   create and open the info dialog, if it is None
-        #   connect to the dialog finished(int) signal to set the memeber variable to None
-        #   add messages to dialog
+        if self.__progressInfoDialog is None:
+            from .MicroPythonProgressInfoDialog import (
+                MicroPythonProgressInfoDialog
+            )
+            self.__progressInfoDialog = MicroPythonProgressInfoDialog(self)
+            self.__progressInfoDialog.finished.connect(
+                self.__progressInfoDialogFinished)
+        self.__progressInfoDialog.show()
+        self.__progressInfoDialog.addMessage(message)
+    
+    @pyqtSlot()
+    def __progressInfoDialogFinished(self):
+        """
+        Private slot handling the closing of the progress info dialog.
+        """
+        self.__progressInfoDialog.deleteLater()
+        self.__progressInfoDialog = None
     
     @pyqtSlot()
     def __newDeviceList(self):
@@ -464,6 +491,17 @@
         @param pos position to show the menu at
         @type QPoint
         """
+        hasSelection = bool(len(self.localFileTreeWidget.selectedItems()))
+        if hasSelection:
+            name = self.localFileTreeWidget.selectedItems()[0].text(0)
+            isDir = name.endswith("/")
+            isFile = not isDir
+        else:
+            isDir = False
+            isFile = False
+        self.__localDelDirTreeAct.setEnabled(isDir)
+        self.__localDelFileAct.setEnabled(isFile)
+        
         self.__localMenu.exec_(self.localFileTreeWidget.mapToGlobal(pos))
     
     @pyqtSlot()
@@ -484,6 +522,104 @@
             self.localCwd.setText(dirPath)
             self.__listLocalFiles(dirPath)
     
+    # TODO: test this
+    @pyqtSlot()
+    def __createLocalDirectory(self):
+        """
+        Private slot to create a local directory.
+        """
+        dirPath, ok = QInputDialog.getText(
+            self,
+            self.tr("Create Directory"),
+            self.tr("Enter directory name:"),
+            QLineEdit.Normal)
+        if ok and dirPath:
+            dirPath = os.path.join(self.localCwd.text(), dirPath)
+            try:
+                os.mkdir(dirPath)
+            except (OSError, IOError) as exc:
+                E5MessageBox.critical(
+                    self,
+                    self.tr("Create Directory"),
+                    self.tr("""<p>The directory <b>{0}</b> could not be"""
+                            """ created.</p><p>Reason: {1}</p>""").format(
+                        dirPath, str(exc))
+                )
+    
+    # TODO: test this
+    @pyqtSlot()
+    def __deleteLocalDirectoryTree(self):
+        """
+        Private slot to delete a local directory tree.
+        """
+        if bool(len(self.localFileTreeWidget.selectedItems())):
+            name = self.localFileTreeWidget.selectedItems()[0].text(0)
+            dirname = os.path.join(self.localCwd.text(), name[:-1])
+            dlg = DeleteFilesConfirmationDialog(
+                self,
+                self.tr("Delete Directory Tree"),
+                self.tr(
+                    "Do you really want to delete this directory tree?"),
+                [dirname])
+            if dlg.exec_() == QDialog.Accepted:
+                try:
+                    shutil.rmtree(dirname)
+                except Exception as exc:
+                    E5MessageBox.critical(
+                        self,
+                        self.tr("Delete Directory Tree"),
+                        self.tr("""<p>The directory <b>{0}</b> could not be"""
+                                """ deleted.</p><p>Reason: {1}</p>""").format(
+                            dirname, str(exc))
+                    )
+    
+    # TODO: test this
+    @pyqtSlot()
+    def __deleteLocalFile(self):
+        """
+        Private slot to delete a local file.
+        """
+        if bool(len(self.localFileTreeWidget.selectedItems())):
+            name = self.localFileTreeWidget.selectedItems()[0].text(0)
+            filename = os.path.join(self.localCwd.text(), name)
+            dlg = DeleteFilesConfirmationDialog(
+                self,
+                self.tr("Delete File"),
+                self.tr(
+                    "Do you really want to delete this file?"),
+                [filename])
+            if dlg.exec_() == QDialog.Accepted:
+                try:
+                    os.remove(filename)
+                except (OSError, IOError) as exc:
+                    E5MessageBox.critical(
+                        self,
+                        self.tr("Delete File"),
+                        self.tr("""<p>The file <b>{0}</b> could not be"""
+                                """ deleted.</p><p>Reason: {1}</p>""").format(
+                            filename, str(exc))
+                    )
+   
+    # TODO: test this
+    @pyqtSlot()
+    def __showLocalTime(self):
+        """
+        Private slot to show the local date and time.
+        """
+        localdatetime = time.localtime()
+        loacldate = time.strftime('%Y-%m-%d', localdatetime)
+        localtime = time.strftime('%H:%M:%S', localdatetime)
+        E5MessageBox.information(
+            self,
+            self.tr("Local Date and Time"),
+            self.tr("<h3>Local 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(loacldate, localtime)
+        )
+    
     ##################################################################
     ## Context menu methods for the device files below
     ##################################################################
@@ -552,8 +688,14 @@
         if bool(len(self.deviceFileTreeWidget.selectedItems())):
             name = self.deviceFileTreeWidget.selectedItems()[0].text(0)
             dirname = self.deviceCwd.text() + "/" + name[:-1]
-            # TODO: add confirmation
-            self.__fileManager.rmdir(dirname)
+            dlg = DeleteFilesConfirmationDialog(
+                self,
+                self.tr("Delete Directory"),
+                self.tr(
+                    "Do you really want to delete this directory?"),
+                [dirname])
+            if dlg.exec_() == QDialog.Accepted:
+                self.__fileManager.rmdir(dirname)
     
     @pyqtSlot()
     def __deleteDeviceDirectoryTree(self):
@@ -564,19 +706,31 @@
         if bool(len(self.deviceFileTreeWidget.selectedItems())):
             name = self.deviceFileTreeWidget.selectedItems()[0].text(0)
             dirname = self.deviceCwd.text() + "/" + name[:-1]
-            # TODO: add confirmation
-            self.__fileManager.rmdir(dirname, recursive=True)
+            dlg = DeleteFilesConfirmationDialog(
+                self,
+                self.tr("Delete Directory Tree"),
+                self.tr(
+                    "Do you really want to delete this directory tree?"),
+                [dirname])
+            if dlg.exec_() == QDialog.Accepted:
+                self.__fileManager.rmdir(dirname, recursive=True)
     
     @pyqtSlot()
     def __deleteDeviceFile(self):
         """
-        Private slot to delete a file
+        Private slot to delete a file.
         """
         if bool(len(self.deviceFileTreeWidget.selectedItems())):
             name = self.deviceFileTreeWidget.selectedItems()[0].text(0)
             filename = self.deviceCwd.text() + "/" + name
-            # TODO: add confirmation
-            self.__fileManager.delete(filename)
+            dlg = DeleteFilesConfirmationDialog(
+                self,
+                self.tr("Delete File"),
+                self.tr(
+                    "Do you really want to delete this file?"),
+                [filename])
+            if dlg.exec_() == QDialog.Accepted:
+                self.__fileManager.delete(filename)
     
     @pyqtSlot()
     def __synchronizeTime(self):
--- a/eric6/MicroPython/MicroPythonFileManagerWidget.ui	Thu Jul 25 19:55:40 2019 +0200
+++ b/eric6/MicroPython/MicroPythonFileManagerWidget.ui	Fri Jul 26 20:05:49 2019 +0200
@@ -174,6 +174,9 @@
    </item>
    <item row="2" column="0">
     <layout class="QHBoxLayout" name="horizontalLayout">
+     <property name="spacing">
+      <number>1</number>
+     </property>
      <item>
       <widget class="QLabel" name="localCwd">
        <property name="sizePolicy">
@@ -191,10 +194,20 @@
        </property>
       </widget>
      </item>
+     <item>
+      <widget class="QToolButton" name="localReloadButton">
+       <property name="toolTip">
+        <string>Press to reload the list</string>
+       </property>
+      </widget>
+     </item>
     </layout>
    </item>
    <item row="2" column="2">
     <layout class="QHBoxLayout" name="horizontalLayout_2">
+     <property name="spacing">
+      <number>1</number>
+     </property>
      <item>
       <widget class="QLabel" name="deviceCwd">
        <property name="sizePolicy">
@@ -212,6 +225,13 @@
        </property>
       </widget>
      </item>
+     <item>
+      <widget class="QToolButton" name="deviceReloadButton">
+       <property name="toolTip">
+        <string>Press to reload the list</string>
+       </property>
+      </widget>
+     </item>
     </layout>
    </item>
   </layout>
@@ -223,7 +243,9 @@
   <tabstop>putButton</tabstop>
   <tabstop>getButton</tabstop>
   <tabstop>localUpButton</tabstop>
+  <tabstop>localReloadButton</tabstop>
   <tabstop>deviceUpButton</tabstop>
+  <tabstop>deviceReloadButton</tabstop>
  </tabstops>
  <resources/>
  <connections/>
--- a/eric6/MicroPython/MicroPythonFileSystem.py	Thu Jul 25 19:55:40 2019 +0200
+++ b/eric6/MicroPython/MicroPythonFileSystem.py	Fri Jul 26 20:05:49 2019 +0200
@@ -607,7 +607,6 @@
         on the connected device
     @signal rsyncDone(localName, deviceName) emitted after the rsync operation
         has been completed
-    @signal rsyncMessages(list) emitted with a list of messages
     @signal rsyncProgressMessage(msg) emitted to send a message about what
         rsync is doing
     @signal removeDirectoryDone() emitted after a directory has been deleted
@@ -629,7 +628,6 @@
     putFileDone = pyqtSignal(str, str)
     deleteFileDone = pyqtSignal(str)
     rsyncDone = pyqtSignal(str, str)
-    rsyncMessages = pyqtSignal(list)
     rsyncProgressMessage = pyqtSignal(str)
     removeDirectoryDone = pyqtSignal()
     createDirectoryDone = pyqtSignal()
@@ -776,18 +774,20 @@
         @param mirror flag indicating to mirror the local directory to
             the device directory
         @type bool
-        @return tuple containing a list of messages and list of errors
-        @rtype tuple of (list of str, list of str)
+        @return list of errors
+        @rtype list of str
         """
-        # TODO: get rid of messages and replace by rsyncProgressMessage signal
-        messages = []
         errors = []
         
         if not os.path.isdir(hostDirectory):
-            return ([], [self.tr(
+            return [self.tr(
                 "The given name '{0}' is not a directory or does not exist.")
                 .format(hostDirectory)
-            ])
+            ]
+        
+        self.rsyncProgressMessage.emit(
+            self.tr("Synchronizing <b>{0}</b>.").format(deviceDirectory)
+        )
         
         sourceDict = {}
         sourceFiles = listdirStat(hostDirectory)
@@ -798,13 +798,13 @@
         try:
             destinationFiles = self.__fs.lls(deviceDirectory, fullstat=True)
         except Exception as exc:
-            return ([], [str(exc)])
+            return [str(exc)]
         if destinationFiles is None:
             # the destination directory does not exist
             try:
                 self.__fs.mkdir(deviceDirectory)
             except Exception as exc:
-                return ([], [str(exc)])
+                return [str(exc)]
         else:
             for name, nstat in destinationFiles:
                 destinationDict[name] = nstat
@@ -819,27 +819,32 @@
             # name exists in source but not in device
             sourceFilename = os.path.join(hostDirectory, sourceBasename)
             destFilename = deviceDirectory + "/" + sourceBasename
+            self.rsyncProgressMessage.emit(
+                self.tr("Adding <b>{0}</b>...").format(destFilename))
             if os.path.isfile(sourceFilename):
                 try:
                     self.__fs.put(sourceFilename, destFilename)
                 except Exception as exc:
-                    messages.append(str(exc))
+                    # just note issues but ignore them otherwise
+                    errors.append(str(exc))
             if os.path.isdir(sourceFilename):
                 # recurse
-                msg, err = self.__rsync(sourceFilename, destFilename,
-                                        mirror=mirror)
-                messages.extend(msg)
-                errors.extend(err)
+                errs = self.__rsync(sourceFilename, destFilename,
+                                    mirror=mirror)
+                # just note issues but ignore them otherwise
+                errors.extend(errs)
         
         if mirror:
             for destBasename in toDelete:
                 # name exists in device but not local, delete
                 destFilename = deviceDirectory + "/" + destBasename
+                self.rsyncProgressMessage.emit(
+                    self.tr("Removing <b>{0}</b>...").format(destFilename))
                 try:
                     self.__fs.rmrf(destFilename, recursive=True, force=True)
                 except Exception as exc:
-                    # ignore errors here
-                    messages.append(str(exc))
+                    # just note issues but ignore them otherwise
+                    errors.append(str(exc))
         
         for sourceBasename in toUpdate:
             # names exist in both; do an update
@@ -850,33 +855,41 @@
             destMode = destStat[0]
             if os.path.isdir(sourceFilename):
                 if stat.S_ISDIR(destMode):
-                    # both are directories => recurse
-                    msg, err = self.__rsync(sourceFilename, destFilename,
-                                            mirror=mirror)
-                    messages.extend(msg)
-                    errors.extend(err)
+                    # both are directories => recurs
+                    errs = self.__rsync(sourceFilename, destFilename,
+                                        mirror=mirror)
+                    # just note issues but ignore them otherwise
+                    errors.extend(errs)
                 else:
-                    messages.append(self.tr(
-                        "Source '{0}' is a directory and destination '{1}'"
-                        " is a file. Ignoring it."
-                    ).format(sourceFilename, destFilename))
+                    self.rsyncProgressMessage.emit(
+                        self.tr("Source <b>{0}</b> is a directory and"
+                                " destination <b>{1}</b> is a file. Ignoring"
+                                " it.")
+                        .format(sourceFilename, destFilename)
+                    )
             else:
                 if stat.S_ISDIR(destMode):
-                    messages.append(self.tr(
-                        "Source '{0}' is a file and destination '{1}' is"
-                        " a directory. Ignoring it."
-                    ).format(sourceFilename, destFilename))
+                    self.rsyncProgressMessage.emit(
+                        self.tr("Source <b>{0}</b> is a file and destination"
+                                " <b>{1}</b> is a directory. Ignoring it.")
+                        .format(sourceFilename, destFilename)
+                    )
                 else:
                     if sourceStat[8] > destStat[8]:     # mtime
-                        messages.append(self.tr(
-                            "'{0}' is newer than '{1}' - copying"
-                        ).format(sourceFilename, destFilename))
+                        self.rsyncProgressMessage.emit(
+                            self.tr("Updating <b>{0}</b>...")
+                            .format(destFilename)
+                        )
                         try:
                             self.__fs.put(sourceFilename, destFilename)
                         except Exception as exc:
-                            messages.append(str(exc))
+                            errors.append(str(exc))
         
-        return messages, errors
+        self.rsyncProgressMessage.emit(
+            self.tr("Done synchronizing <b>{0}</b>.").format(deviceDirectory)
+        )
+        
+        return errors
     
     @pyqtSlot(str, str)
     @pyqtSlot(str, str, bool)
@@ -892,14 +905,10 @@
             the device directory
         @type bool
         """
-        messages, errors = self.__rsync(hostDirectory, deviceDirectory,
-                                        mirror=mirror)
+        errors = self.__rsync(hostDirectory, deviceDirectory, mirror=mirror)
         if errors:
             self.error.emit("rsync", "\n".join(errors))
         
-        if messages:
-            self.rsyncMessages.emit(messages)
-        
         self.rsyncDone.emit(hostDirectory, deviceDirectory)
     
     @pyqtSlot(str)
--- a/eric6/MicroPython/MicroPythonFileSystemUtilities.py	Thu Jul 25 19:55:40 2019 +0200
+++ b/eric6/MicroPython/MicroPythonFileSystemUtilities.py	Fri Jul 26 20:05:49 2019 +0200
@@ -54,6 +54,9 @@
     if stat.S_ISDIR(mode) or isDir:
         # append a '/' for directories
         return name + "/"
+    elif stat.S_ISLNK(mode):
+        # append a '@' for links
+        return name + "@"
     else:
         # no change
         return name
--- a/eric6/MicroPython/MicroPythonProgressInfoDialog.py	Thu Jul 25 19:55:40 2019 +0200
+++ b/eric6/MicroPython/MicroPythonProgressInfoDialog.py	Fri Jul 26 20:05:49 2019 +0200
@@ -7,7 +7,10 @@
 Module implementing a dialog to show progress messages.
 """
 
+from __future__ import unicode_literals
+
 from PyQt5.QtCore import pyqtSlot
+from PyQt5.QtGui import QTextCursor
 from PyQt5.QtWidgets import QDialog
 
 from .Ui_MicroPythonProgressInfoDialog import Ui_MicroPythonProgressInfoDialog
@@ -35,4 +38,8 @@
         @param message progress information to be shown
         @type str
         """
-        # TODO: not implemented yet
+        tc = self.progressEdit.textCursor()
+        tc.movePosition(QTextCursor.End)
+        self.progressEdit.setTextCursor(tc)
+        self.progressEdit.appendHtml(message)
+        self.progressEdit.ensureCursorVisible()
--- a/eric6/MicroPython/MicroPythonProgressInfoDialog.ui	Thu Jul 25 19:55:40 2019 +0200
+++ b/eric6/MicroPython/MicroPythonProgressInfoDialog.ui	Fri Jul 26 20:05:49 2019 +0200
@@ -22,6 +22,9 @@
      <property name="tabChangesFocus">
       <bool>true</bool>
      </property>
+     <property name="lineWrapMode">
+      <enum>QPlainTextEdit::NoWrap</enum>
+     </property>
      <property name="readOnly">
       <bool>true</bool>
      </property>
--- a/eric6/MicroPython/MicroPythonSerialPort.py	Thu Jul 25 19:55:40 2019 +0200
+++ b/eric6/MicroPython/MicroPythonSerialPort.py	Fri Jul 26 20:05:49 2019 +0200
@@ -119,8 +119,6 @@
                     break
                 if size is not None and len(data) >= size:
                     break
-#            else:
-#                break
             if t.elapsed() > self.__timeout:
                 self.__timedOut = True
                 break

eric ide

mercurial