eric6/MicroPython/MicroPythonReplWidget.py

branch
micropython
changeset 7059
a8fad276cbd5
parent 7058
bdd583f96e96
child 7062
ac12da95958b
diff -r bdd583f96e96 -r a8fad276cbd5 eric6/MicroPython/MicroPythonReplWidget.py
--- a/eric6/MicroPython/MicroPythonReplWidget.py	Tue Jul 09 19:49:41 2019 +0200
+++ b/eric6/MicroPython/MicroPythonReplWidget.py	Wed Jul 10 20:21:57 2019 +0200
@@ -11,7 +11,9 @@
 
 import re
 
-from PyQt5.QtCore import pyqtSlot, pyqtSignal, Qt, QPoint, QEvent, QIODevice
+from PyQt5.QtCore import (
+    pyqtSlot, pyqtSignal, Qt, QPoint, QEvent, QIODevice, QTimer
+)
 from PyQt5.QtGui import QColor, QKeySequence, QTextCursor
 from PyQt5.QtWidgets import (
     QWidget, QMenu, QApplication, QHBoxLayout, QSpacerItem, QSizePolicy)
@@ -20,9 +22,15 @@
     HAS_QTSERIALPORT = True
 except ImportError:
     HAS_QTSERIALPORT = False
+try:
+    from PyQt5.QtChart import QChart    # __IGNORE_WARNING__
+    HAS_QTCHART = True
+except ImportError:
+    HAS_QTCHART = False
 
 from E5Gui.E5ZoomWidget import E5ZoomWidget
-from E5Gui import E5MessageBox
+from E5Gui import E5MessageBox, E5FileDialog
+from E5Gui.E5Application import e5App
 
 from .Ui_MicroPythonReplWidget import Ui_MicroPythonReplWidget
 
@@ -59,6 +67,10 @@
         
         self.deviceIconLabel.setPixmap(MicroPythonDevices.getDeviceIcon(
             "", False))
+        
+        self.openButton.setIcon(UI.PixmapCache.getIcon("open"))
+        self.saveButton.setIcon(UI.PixmapCache.getIcon("fileSaveAs"))
+        
         self.checkButton.setIcon(UI.PixmapCache.getIcon("question"))
         self.runButton.setIcon(UI.PixmapCache.getIcon("start"))
         self.replButton.setIcon(UI.PixmapCache.getIcon("terminal"))
@@ -171,9 +183,13 @@
         Public method to set the enabled state of the various action buttons.
         
         @param kwargs keyword arguments containg the enabled states (keys are
-            'run', 'repl', 'files', 'chart'
+            'run', 'repl', 'files', 'chart', 'open', 'save'
         @type dict
         """
+        if "open" in kwargs:
+            self.openButton.setEnabled(kwargs["open"])
+        if "save" in kwargs:
+            self.saveButton.setEnabled(kwargs["save"])
         if "run" in kwargs:
             self.runButton.setEnabled(kwargs["run"])
         if "repl" in kwargs:
@@ -218,21 +234,27 @@
         
         self.disconnectButton.setEnabled(connected)
     
+    def __showNoDeviceMessage(self):
+        """
+        Private method to show a message dialog indicating a missing device.
+        """
+        E5MessageBox.critical(
+            self,
+            self.tr("No device attached"),
+            self.tr("""Please ensure the device is plugged into your"""
+                    """ computer and selected.\n\nIt must have a version"""
+                    """ of MicroPython (or CircuitPython) flashed onto"""
+                    """ it before anything will work.\n\nFinally press"""
+                    """ the device's reset button and wait a few seconds"""
+                    """ before trying again."""))
+    
     @pyqtSlot()
     def on_replButton_clicked(self):
         """
         Private slot to connect to the selected device and start a REPL.
         """
         if not self.__device:
-            E5MessageBox.critical(
-                self,
-                self.tr("No device attached"),
-                self.tr("""Please ensure the device is plugged inti your"""
-                        """ computer.\n\nIt must have a version of"""
-                        """ MicroPython (or CircuitPython) flashed onto it"""
-                        """ before the REPL will work.\n\nFinally press the"""
-                        """ device's reset button and wait a few seconds"""
-                        """ before trying again."""))
+            self.__showNoDeviceMessage()
             return
         
         if self.__replRunning:
@@ -260,6 +282,9 @@
                         self.__serial.write(b'\x02')
                         # send Ctrl-C (keyboard interrupt)
                         self.__serial.write(b'\x03')
+            
+            self.__replRunning = True
+            self.__device.setRepl(True)
     
     @pyqtSlot()
     def on_disconnectButton_clicked(self):
@@ -283,7 +308,6 @@
         Private method to activate a data plotter widget.
         """
         # TODO: not implemented yet
-        raise NotImplementedError
     
     def __deactivatePlotter(self):
         """
@@ -368,7 +392,7 @@
         while tc.movePosition(QTextCursor.Down):
             pass
         
-        index = 1
+        index = 0
         while index < len(data):
             if data[index] == 8:        # \b
                 tc.movePosition(QTextCursor.Left)
@@ -380,7 +404,7 @@
                   data[index + 1] == 91):
                 # VT100 cursor command detected: <Esc>[
                 index += 2      # move index to after the [
-                match = self.__vt100Re.search(data[index:].decaode("utf-8"))
+                match = self.__vt100Re.search(data[index:].decode("utf-8"))
                 if match:
                     # move to last position in control sequence
                     # ++ will be done at end of loop
@@ -494,3 +518,89 @@
         """
         data = bytes(self.__serial.readAll())
         self.dataReceived.emit(data)
+    
+    def execute(self, commandsList):
+        """
+        Public method to execute a series of commands over a period of time.
+        
+        @param commandsList list of commands to be execute on the device
+        @type list of bytes
+        """
+        if commandsList:
+            command = commandsList[0]
+            self.__serial.write(command)
+            remainder = commandsList[1:]
+            remainingTask = lambda commands=remainder: self.execute(commands)
+            QTimer.singleShot(2, remainingTask)
+    
+    @pyqtSlot()
+    def on_runButton_clicked(self):
+        """
+        Private slot to execute the script of the active editor on the
+        selected device.
+        """
+        if not self.__device:
+            self.__showNoDeviceMessage()
+            return
+        
+        aw = e5App().getObject("ViewManager").activeWindow()
+        if aw is None:
+            E5MessageBox.critical(
+                self,
+                self.tr("Run Script"),
+                self.tr("""There is no editor open. Abort..."""))
+            return
+        
+        script = aw.text()
+        if not script:
+            E5MessageBox.critical(
+                self,
+                self.tr("Run Script"),
+                self.tr("""The current editor does not contain a script."""
+                        """ Abort..."""))
+            return
+        
+        ok, reason = self.__device.canRunScript()
+        if not ok:
+            E5MessageBox.warning(
+                self,
+                self.tr("Run Script"),
+                self.tr("""<p>Cannot run script.</p><p>Reason:"""
+                        """ {0}</p>""").format(reason))
+            return
+        
+        if not self.__replRunning:
+            self.on_replButton_clicked()
+        if self.__replRunning:
+            self.__device.runScript(script)
+    
+    @pyqtSlot()
+    def on_openButton_clicked(self):
+        """
+        Private slot to open a file of the connected device.
+        """
+        if not self.__device:
+            self.__showNoDeviceMessage()
+            return
+        
+        workspace = self.__device.getWorkspace()
+        fileName = E5FileDialog.getOpenFileName(
+            self,
+            self.tr("Open Python File"),
+            workspace,
+            self.tr("Python3 Files (*.py)"))
+        if fileName:
+            e5App().getObject("ViewManager").openSourceFile(fileName)
+    
+    @pyqtSlot()
+    def on_saveButton_clicked(self):
+        """
+        Private slot to save the current editor to the connected device.
+        """
+        if not self.__device:
+            self.__showNoDeviceMessage()
+            return
+        
+        workspace = self.__device.getWorkspace()
+        aw = e5App().getObject("ViewManager").activeWindow()
+        aw.saveFileAs(workspace)

eric ide

mercurial