Esempio n. 1
0
class PyConsoleTextEdit(ConsoleTextEdit):
    _color_stdin = Qt.darkGreen
    _multi_line_char = ':'
    _multi_line_indent = '    '
    _prompt = ('>>> ', '... ')  # prompt for single and multi line
    exit = Signal()

    def __init__(self, parent=None):
        super(PyConsoleTextEdit, self).__init__(parent)

        self._interpreter_locals = {}
        self._interpreter = InteractiveInterpreter(self._interpreter_locals)

        self._comment_writer.write(
            'Python %s on %s\n' %
            (sys.version.replace('\n', ''), sys.platform))
        self._comment_writer.write('Qt bindings: %s version %s\n' %
                                   (QT_BINDING, QT_BINDING_VERSION))

        self._add_prompt()

    def update_interpreter_locals(self, newLocals):
        self._interpreter_locals.update(newLocals)

    def _exec_code(self, code):
        try:
            self._interpreter.runsource(code)
        except SystemExit:  # catch sys.exit() calls, so they don't close the whole gui
            self.exit.emit()
class PyConsoleTextEdit(ConsoleTextEdit):
    _color_stdin = Qt.darkGreen
    _multi_line_char = ':'
    _multi_line_indent = '    '
    _prompt = ('>>> ', '... ')  # prompt for single and multi line
    exit = Signal()

    def __init__(self, parent=None):
        super(PyConsoleTextEdit, self).__init__(parent)

        self._interpreter_locals = {}
        self._interpreter = InteractiveInterpreter(self._interpreter_locals)

        self._comment_writer.write('Python %s on %s\n' % (sys.version.replace('\n', ''), sys.platform))
        self._comment_writer.write('Qt bindings: %s version %s\n' % (QT_BINDING, QT_BINDING_VERSION))

        self._add_prompt()

    def update_interpreter_locals(self, newLocals):
        self._interpreter_locals.update(newLocals)

    def _exec_code(self, code):
        try:
            self._interpreter.runsource(code)
        except SystemExit:  # catch sys.exit() calls, so they don't close the whole gui
            self.exit.emit()
Esempio n. 3
0
class MyWindow(QtGui.QWidget):
    def __init__(self, parent=None):
        super(MyWindow, self).__init__(parent=parent)
        self.newshell = True
        self.stmt = True
        self.construct = False
        self.initUI()
        self.index = 0
        self.interpreter = InteractiveInterpreter()

    def initUI(self):
        self.sh = QtGui.QTextEdit(
            '''
Python 2.7.6 on linux2
** DO NOT DELETE SHELL PROMPT! **
>>> ''', self)
        self.sh.textChanged.connect(self.shellop)
        self.sh.setReadOnly(True)
        self.sh.setReadOnly(False)

    def shellop(self):
        self.index += 1
        if self.sh.toPlainText()[self.index] == "\n" and self.sh.toPlainText()[
                self.index - 1] == ":":
            self.stmt = False
            self.construct = True
        elif self.sh.toPlainText()[self.index] == "\n" and not self.construct:
            self.stmt = not self.stmt

            class stdoutProxy:
                def write(self, s):
                    self.sh.insertPlainText(s)

            stdout = sys.stdout
            sys.stdout = stdoutProxy()
            self.interpreter.runsource(self.sh.toPlainText())
            self.sh.insertPlainText("\n")
            self.index += 1
            while self.interpreter.showtraceback():
                print self.interpreter.showtraceback()
            sys.stdout = stdout
        if self.sh.toPlainText()[
                self.index] == "\n" and not self.construct and not self.stmt:
            self.stmt = not self.stmt
            self.sh.insertPlainText(">>> ")
            self.index += 4
        if self.construct and self.sh.toPlainText(
        )[self.index] == "\n" and self.sh.toPlainText()[self.index - 1] == " ":
            self.construct = False
            self.sh.insertPlainText(">>> ")
            self.index += 4
        if self.construct:
            self.sh.insertPlainText("... ")
            index += 4
Esempio n. 4
0
class MyWindow(QtGui.QWidget):
    def __init__(self, parent=None):
        super(MyWindow, self).__init__(parent=parent)
        self.newshell = True
        self.stmt = True
        self.construct = False
        self.initUI()
        self.index = 0
        self.interpreter = InteractiveInterpreter()

    def initUI(self):
        self.sh = QtGui.QTextEdit('''
Python 2.7.6 on linux2
** DO NOT DELETE SHELL PROMPT! **
>>> ''', self)
        self.sh.textChanged.connect(self.shellop)
        self.sh.setReadOnly(True)
        self.sh.setReadOnly(False)

    def shellop(self):
        self.index += 1
        if self.sh.toPlainText()[self.index] == "\n" and self.sh.toPlainText()[self.index-1] == ":":
            self.stmt = False
            self.construct = True
        elif self.sh.toPlainText()[self.index] == "\n" and not self.construct:
            self.stmt = not self.stmt
            class stdoutProxy:
                def write(self, s):
                    self.sh.insertPlainText(s)
            stdout = sys.stdout
            sys.stdout = stdoutProxy()
            self.interpreter.runsource(self.sh.toPlainText())
            self.sh.insertPlainText("\n")
            self.index += 1
            while self.interpreter.showtraceback():
                print self.interpreter.showtraceback()
            sys.stdout = stdout
        if self.sh.toPlainText()[self.index] == "\n" and not self.construct and not self.stmt:
            self.stmt = not self.stmt
            self.sh.insertPlainText(">>> ")
            self.index += 4
        if self.construct and self.sh.toPlainText()[self.index] == "\n" and self.sh.toPlainText()[self.index-1] == " ":
            self.construct = False
            self.sh.insertPlainText(">>> ")
            self.index += 4
        if self.construct:
            self.sh.insertPlainText("... ")
            index += 4
Esempio n. 5
0
    def runsource(self, source):
        """Compile and run source code in the interpreter."""
        stdin, stdout, stderr = sys.stdin, sys.stdout, sys.stderr
        sys.stdin, sys.stdout, sys.stderr = \
                   self.stdin, self.stdout, self.stderr
        # more = InteractiveInterpreter.runsource(self, source)
        # this was a cute idea, but didn't work...
        #more = self.runcode(compile(source,'',
        #               ('exec' if self.useExecMode else 'single')))
        
        more = False
        if not self.socket:
            if not source.startswith("connect"):
                print("Type \"connect(ip, port)\" to connect the game client")
            else:
                more = InteractiveInterpreter.runsource(self, source)
        else:
            more = self.rmt_run(source)

        # If sys.std* is still what we set it to, then restore it.
        # But, if the executed source changed sys.std*, assume it was
        # meant to be changed and leave it. Power to the people.
        if sys.stdin == self.stdin:
            sys.stdin = stdin
        else:
            self.stdin = sys.stdin
        if sys.stdout == self.stdout:
            sys.stdout = stdout
        else:
            self.stdout = sys.stdout
        if sys.stderr == self.stderr:
            sys.stderr = stderr
        else:
            self.stderr = sys.stderr
        return more
Esempio n. 6
0
def Interpreter_runsource(self, source):
    from code import InteractiveInterpreter

    # Horrible hack - if there are newlines
    # in the source, compile it as 'exec',
    # otherwise compile it as 'single'
    if source.find('\n') > -1: symbol = 'exec'
    else:                      symbol = 'single'

    stdin, stdout, stderr = sys.stdin, sys.stdout, sys.stderr
    sys.stdin, sys.stdout, sys.stderr = \
               self.stdin, self.stdout, self.stderr

    more = InteractiveInterpreter.runsource(self, source, symbol=symbol)

    # this was a cute idea, but didn't work...
    # more = self.runcode(compile(source,'',
    #               ('exec' if self.useExecMode else 'single')))

    # If sys.std* is still what we set it to, then restore it.
    # But, if the executed source changed sys.std*, assume it was
    # meant to be changed and leave it. Power to the people.
    if sys.stdin == self.stdin:
        sys.stdin = stdin
    else:
        self.stdin = sys.stdin
    if sys.stdout == self.stdout:
        sys.stdout = stdout
    else:
        self.stdout = sys.stdout
    if sys.stderr == self.stderr:
        sys.stderr = stderr
    else:
        self.stderr = sys.stderr
    return more
Esempio n. 7
0
    def runsource(self, source):
        """Compile and run source code in the interpreter."""
        stdin, stdout, stderr = sys.stdin, sys.stdout, sys.stderr
        sys.stdin, sys.stdout, sys.stderr = \
                   self.stdin, self.stdout, self.stderr
        # more = InteractiveInterpreter.runsource(self, source)
        # this was a cute idea, but didn't work...
        #more = self.runcode(compile(source,'',
        #               ('exec' if self.useExecMode else 'single')))

        more = False
        if not self.socket:
            if not source.startswith("connect"):
                print("Type \"connect(ip, port)\" to connect the game client")
            else:
                more = InteractiveInterpreter.runsource(self, source)
        else:
            more = self.rmt_run(source)

        # If sys.std* is still what we set it to, then restore it.
        # But, if the executed source changed sys.std*, assume it was
        # meant to be changed and leave it. Power to the people.
        if sys.stdin == self.stdin:
            sys.stdin = stdin
        else:
            self.stdin = sys.stdin
        if sys.stdout == self.stdout:
            sys.stdout = stdout
        else:
            self.stdout = sys.stdout
        if sys.stderr == self.stderr:
            sys.stderr = stderr
        else:
            self.stderr = sys.stderr
        return more
Esempio n. 8
0
    def push(self, line, filename='<input>'):
        '''
Execute a command string in the child shell.
Returns STDOUT/STDERR tuple.
        '''
        # Redirect STDOUT/STDERR to our custom cache.
        sys.stdout = self.stdout_cache
        sys.stderr = self.stderr_cache
        
        # Filter input here (if required).
        
        # Execute line.
        r = InteractiveInterpreter.runsource(self, line, filename)

        # Custom cache will have taken all STDOUT/STDERR so now put it back to
        #   allow other stuff to use STDOUT/STDERR.
        sys.stdout = self.stdout
        sys.stderr = self.stderr

        # Take all the output snarffed from STDOUT/STDERR.
        output = self.stdout_cache.flush()
        error = self.stderr_cache.flush()
        
        # Filter output here (if required).
        
        return output, error
Esempio n. 9
0
 def runsource(self,source):
     self.get_output()
     more = InteractiveInterpreter.runsource(self,source)
     self.return_output()
     output = self.out_cache.flush()
     errors = self.err_cache.flush()
     return more,errors,output
Esempio n. 10
0
    def runsource(self, source):
        """Compile and run source code in the interpreter."""
        stdin, stdout, stderr = sys.stdin, sys.stdout, sys.stderr
        sys.stdin, sys.stdout, sys.stderr = \
                   self.stdin, self.stdout, self.stderr
        more = InteractiveInterpreter.runsource(self, source)
        # this was a cute idea, but didn't work...
        #more = self.runcode(compile(source,'',
        #               ('exec' if self.useExecMode else 'single')))


        # If sys.std* is still what we set it to, then restore it.
        # But, if the executed source changed sys.std*, assume it was
        # meant to be changed and leave it. Power to the people.
        if sys.stdin == self.stdin:
            sys.stdin = stdin
        else:
            self.stdin = sys.stdin
        if sys.stdout == self.stdout:
            sys.stdout = stdout
        else:
            self.stdout = sys.stdout
        if sys.stderr == self.stderr:
            sys.stderr = stderr
        else:
            self.stderr = sys.stderr
        return more
Esempio n. 11
0
 def runsource(self, source):
     """Compile and run source code in the interpreter."""
     stdin, stdout, stderr = sys.stdin, sys.stdout, sys.stderr
     sys.stdin, sys.stdout, sys.stderr = \
                self.stdin, self.stdout, self.stderr
     more = InteractiveInterpreter.runsource(self, source)
     # this was a cute idea, but didn't work...
     #more = self.runcode(compile(source,'',
     #               ('exec' if self.useExecMode else 'single')))
     
     
     # If sys.std* is still what we set it to, then restore it.
     # But, if the executed source changed sys.std*, assume it was
     # meant to be changed and leave it. Power to the people.
     if sys.stdin == self.stdin:
         sys.stdin = stdin
     else:
         self.stdin = sys.stdin
     if sys.stdout == self.stdout:
         sys.stdout = stdout
     else:
         self.stdout = sys.stdout
     if sys.stderr == self.stderr:
         sys.stderr = stderr
     else:
         self.stderr = sys.stderr
     return more
Esempio n. 12
0
 def runsource(self, source):
     # Extend base class to stuff the source in the line cache
     filename = "<pyshell#%d>" % self.gid
     self.gid = self.gid + 1
     lines = string.split(source, "\n")
     linecache.cache[filename] = len(source)+1, 0, lines, filename
     self.more = 0
     return InteractiveInterpreter.runsource(self, source, filename)
Esempio n. 13
0
    def runsource(self, source):
        stdout, stderr = sys.stdout, sys.stderr
        sys.stdout = FauxFile(self, _stdout_style)
        sys.stderr = FauxFile(self, _stderr_style)

        more = InteractiveInterpreter.runsource(self, source)

        sys.stdout, sys.stderr = stdout, stderr
        return more
Esempio n. 14
0
 def runsource(self, source):
     # Extend base class to stuff the source in the line cache first
     filename = self.stuffsource(source)
     self.more = 0
     self.save_warnings_filters = warnings.filters[:]
     warnings.filterwarnings(action="error", category=SyntaxWarning)
     try:
         return InteractiveInterpreter.runsource(self, source, filename)
     finally:
         if self.save_warnings_filters is not None:
             warnings.filters[:] = self.save_warnings_filters
             self.save_warnings_filters = None
Esempio n. 15
0
def main():
    """
    Print lines of input along with output.
    """
    source_lines = (line.rstrip() for line in sys.stdin)
    console = InteractiveInterpreter()
    source = ''
    try:
        while True:
            source = source_lines.next()
            print '>>>', source
            more = console.runsource(source)
            while more:
                next_line = source_lines.next()
                print '...', next_line
                source += '\n' + next_line 
                more = console.runsource(source)
    except StopIteration:
        if more:
            print '... '
            more = console.runsource(source + '\n')
Esempio n. 16
0
 def runsource(self, source):
     # Extend base class to stuff the source in the line cache first
     filename = self.stuffsource(source)
     self.more = 0
     self.save_warnings_filters = warnings.filters[:]
     warnings.filterwarnings(action="error", category=SyntaxWarning)
     try:
         return InteractiveInterpreter.runsource(self, source, filename)
     finally:
         if self.save_warnings_filters is not None:
             warnings.filters[:] = self.save_warnings_filters
             self.save_warnings_filters = None
Esempio n. 17
0
def main():
    """
    Print lines of input along with output.
    """
    source_lines = (line.rstrip() for line in sys.stdin)
    console = InteractiveInterpreter()
    console.runsource("import turicreate")
    source = ""
    try:
        while True:
            source = source_lines.next()
            more = console.runsource(source)
            while more:
                next_line = source_lines.next()
                print "...", next_line
                source += "\n" + next_line
                more = console.runsource(source)
    except StopIteration:
        if more:
            print "... "
            more = console.runsource(source + "\n")
Esempio n. 18
0
def main():
    """
    Print lines of input along with output.
    """
    source_lines = (line.rstrip() for line in sys.stdin)
    console = InteractiveInterpreter()
    console.runsource('import graphlab')
    source = ''
    try:
        while True:
            source = source_lines.next()
            more = console.runsource(source)
            while more:
                next_line = source_lines.next()
                print '...', next_line
                source += '\n' + next_line
                more = console.runsource(source)
    except StopIteration:
        if more:
            print '... '
            more = console.runsource(source + '\n')
Esempio n. 19
0
def main():
    """
    Print lines of input along with output.
    """
    source_lines = (line.rstrip() for line in sys.stdin)
    console = InteractiveInterpreter()
    source = ''
    try:
        while True:
            source = next(source_lines)
            print('>>>', source)
            more = console.runsource(source)
            while more:
                next_line = next(source_lines)
                print('...', next_line)
                source += '\n' + next_line
                more = console.runsource(source)
    except StopIteration:
        if more:
            print('... ')
            more = console.runsource(source + '\n')
Esempio n. 20
0
 def runsource(self, source):
     """Extend base class method: Stuff the source in the line cache first"""
     filename = self.stuffsource(source)
     self.more = 0
     self.save_warnings_filters = warnings.filters[:]
     warnings.filterwarnings(action='error', category=SyntaxWarning)
     assert isinstance(source, str)
     try:
         return InteractiveInterpreter.runsource(self, source, filename)
     finally:
         if self.save_warnings_filters is not None:
             warnings.filters[:] = self.save_warnings_filters
             self.save_warnings_filters = None
Esempio n. 21
0
class DebugInterpreter:
    def __init__(self, shell_locals: List[ShellVariable]):
        self._shell_locals = shell_locals
        self._interpreter = InteractiveInterpreter()

    def eval(self, msg):
        old_stdout = sys.stdout
        old_stderr = sys.stderr

        sys.stdout = StringIO()
        sys.stderr = StringIO()
        if msg.endswith(";"):
            msg = msg.replace(";", "\n")
        handler = logging.StreamHandler(sys.stdout)
        logging.getLogger().addHandler(handler)
        self._interpreter.runsource(msg)
        logging.getLogger().removeHandler(handler)

        sys.stdout.seek(0)
        out = sys.stdout.read()
        sys.stderr.seek(0)
        err = sys.stderr.read()
        sys.stdout = old_stdout
        sys.stderr = old_stderr
        return out.strip("\n"), err.strip("\n")

    def set_locals(self):
        initial_code = []

        variables_description = []
        for shellLocal in self._shell_locals:
            initial_code.extend(shellLocal.get_evaluation_command())
            result = shellLocal.name, shellLocal.description
            variables_description.append(result)
        for line in initial_code:
            self.eval(line)

        return variables_description
Esempio n. 22
0
 def runsource(self, source, symbol="single"):
     "Extend base class method: encode the source"
     filename = '<diyrpc shell>'
     if isinstance(source, types.UnicodeType):
         from idlelib import IOBinding
         try:
             source = source.encode(IOBinding.encoding)
         except UnicodeError:
             self.write("Unsupported characters in input\n")
             return
     try:
         return InteractiveInterpreter.runsource(self, source, filename,
                                                 symbol)
     finally:
         pass
Esempio n. 23
0
 def runsource(self, source):
     """Compile and run source code in the interpreter."""
     stdin, stdout, stderr = sys.stdin, sys.stdout, sys.stderr
     sys.stdin, sys.stdout, sys.stderr = self.stdin, self.stdout, self.stderr
     more = InteractiveInterpreter.runsource(self, source)
     # If sys.std* is still what we set it to, then restore it.
     # But, if the executed source changed sys.std*, assume it was
     # meant to be changed and leave it. Power to the people.
     if sys.stdin == self.stdin:
         sys.stdin = stdin
     if sys.stdout == self.stdout:
         sys.stdout = stdout
     if sys.stderr == self.stderr:
         sys.stderr = stderr
     return more
 def runsource(self, source):
     """Compile and run source code in the interpreter."""
     stdin, stdout, stderr = sys.stdin, sys.stdout, sys.stderr
     sys.stdin, sys.stdout, sys.stderr = \
                self.stdin, self.stdout, self.stderr
     more = InteractiveInterpreter.runsource(self, source)
     # If sys.std* is still what we set it to, then restore it.
     # But, if the executed source changed sys.std*, assume it was
     # meant to be changed and leave it. Power to the people.
     if sys.stdin == self.stdin:
         sys.stdin = stdin
     if sys.stdout == self.stdout:
         sys.stdout = stdout
     if sys.stderr == self.stderr:
         sys.stderr = stderr
     return more
Esempio n. 25
0
 def runsource(self, source):
     "Extend base class method: Stuff the source in the line cache first"
     filename = self.stuffsource(source)
     self.more = 0
     self.save_warnings_filters = warnings.filters[:]
     warnings.filterwarnings(action="error", category=SyntaxWarning)
     if isinstance(source, types.UnicodeType):
         import IOBinding
         try:
             source = source.encode(IOBinding.encoding)
         except UnicodeError:
             self.tkconsole.resetoutput()
             self.write("Unsupported characters in input")
             return
     try:
         return InteractiveInterpreter.runsource(self, source, filename)
     finally:
         if self.save_warnings_filters is not None:
             warnings.filters[:] = self.save_warnings_filters
             self.save_warnings_filters = None
Esempio n. 26
0
 def runsource(self, source):
     "Extend base class method: Stuff the source in the line cache first"
     filename = self.stuffsource(source)
     self.more = 0
     self.save_warnings_filters = warnings.filters[:]
     warnings.filterwarnings(action="error", category=SyntaxWarning)
     if isinstance(source, types.UnicodeType):
         import IOBinding
         try:
             source = source.encode(IOBinding.encoding)
         except UnicodeError:
             self.tkconsole.resetoutput()
             self.write("Unsupported characters in input")
             return
     try:
         return InteractiveInterpreter.runsource(self, source, filename)
     finally:
         if self.save_warnings_filters is not None:
             warnings.filters[:] = self.save_warnings_filters
             self.save_warnings_filters = None
Esempio n. 27
0
 def runsource(self, source):
     "Extend base class method: Stuff the source in the line cache first"
     filename = self.stuffsource(source)
     self.more = 0
     self.save_warnings_filters = warnings.filters[:]
     warnings.filterwarnings(action="error", category=SyntaxWarning)
     # at the moment, InteractiveInterpreter expects str
     assert isinstance(source, str)
     #if isinstance(source, str):
     #    from idlelib import IOBinding
     #    try:
     #        source = source.encode(IOBinding.encoding)
     #    except UnicodeError:
     #        self.tkconsole.resetoutput()
     #        self.write("Unsupported characters in input\n")
     #        return
     try:
         # InteractiveInterpreter.runsource() calls its runcode() method,
         # which is overridden (see below)
         return InteractiveInterpreter.runsource(self, source, filename)
     finally:
         if self.save_warnings_filters is not None:
             warnings.filters[:] = self.save_warnings_filters
             self.save_warnings_filters = None
Esempio n. 28
0
 def runsource(self, source):
     "Extend base class method: Stuff the source in the line cache first"
     filename = self.stuffsource(source)
     self.more = 0
     self.save_warnings_filters = warnings.filters[:]
     warnings.filterwarnings(action="error", category=SyntaxWarning)
     # at the moment, InteractiveInterpreter expects str
     assert isinstance(source, str)
     #if isinstance(source, str):
     #    from idlelib import IOBinding
     #    try:
     #        source = source.encode(IOBinding.encoding)
     #    except UnicodeError:
     #        self.tkconsole.resetoutput()
     #        self.write("Unsupported characters in input\n")
     #        return
     try:
         # InteractiveInterpreter.runsource() calls its runcode() method,
         # which is overridden (see below)
         return InteractiveInterpreter.runsource(self, source, filename)
     finally:
         if self.save_warnings_filters is not None:
             warnings.filters[:] = self.save_warnings_filters
             self.save_warnings_filters = None
Esempio n. 29
0
class PyCute(QMultiLineEdit):
    """
    PyCute is a Python shell for PyQt.

    Creating, displaying and controlling PyQt widgets from the Python command
    line interpreter is very hard, if not, impossible.  PyCute solves this
    problem by interfacing the Python interpreter to a PyQt widget.

    My use is interpreter driven plotting to QwtPlot instances. Why?

    Other popular scientific software packages like SciPy, SciLab, Octave,
    Maple, Mathematica, GnuPlot, ..., also have interpreter driven plotting.
    It is well adapted to quick & dirty exploration.

    Of course, PyQt's debugger -- eric -- gives you similar facilities, but
    PyCute is smaller and easier to integrate in applications.
    Eric requires Qt-3.x

    PyCute is based on ideas and code from:
    - Python*/Tools/idle/PyShell.py (Python Software Foundation License)
    - PyQt*/eric/Shell.py (Gnu Public License)
    """
    def __init__(self, locals=None, log='', parent=None):
        """Constructor.

        The optional 'locals' argument specifies the dictionary in
        which code will be executed; it defaults to a newly created
        dictionary with key "__name__" set to "__console__" and key
        "__doc__" set to None.

        The optional 'log' argument specifies the file in which the
        interpreter session is to be logged.

        The optional 'parent' argument specifies the parent widget.
        If no parent widget has been specified, it is possible to
        exit the interpreter by Ctrl-D.
        """

        QMultiLineEdit.__init__(self, parent)
        self.interpreter = Interpreter(locals)

        # session log
        self.log = log or ''

        # to exit the main interpreter by a Ctrl-D if PyCute has no parent
        if parent is None:
            self.eofKey = Qt.Key_D
        else:
            self.eofKey = None

        # capture all interactive input/output
        sys.stdout = self
        sys.stderr = self
        sys.stdin = self
        # last line + last incomplete lines
        self.line = QString()
        self.lines = []
        # the cursor position in the last line
        self.point = 0
        # flag: the interpreter needs more input to run the last lines.
        self.more = 0
        # flag: readline() is being used for e.g. raw_input() and input()
        self.reading = 0
        # history
        self.history = []
        self.pointer = 0
        self.xLast = 0
        self.yLast = 0

        # user interface setup
        # no word wrapping simplifies cursor <-> numLines() mapping
        self.setWordWrap(QMultiLineEdit.NoWrap)
        self.setCaption('PyCute -- a Python Shell for PyQt --'
                        'http://gerard.vermeulen.free.fr')
        # font
        if os.name == 'posix':
            font = QFont("Fixed", 12)
        elif os.name == 'nt' or os.name == 'dos':
            font = QFont("Courier New", 8)
        else:
            raise SystemExit, "FIXME for 'os2', 'mac', 'ce' or 'riscos'"
        font.setFixedPitch(1)
        self.setFont(font)

        # geometry
        height = 40 * QFontMetrics(font).lineSpacing()
        request = QSize(600, height)
        if parent is not None:
            request = request.boundedTo(parent.size())
        self.resize(request)

        # interpreter prompt.
        try:
            sys.ps1
        except AttributeError:
            sys.ps1 = ">>> "
        try:
            sys.ps2
        except AttributeError:
            sys.ps2 = "... "

        # interpreter banner
        self.write('The PyCute shell running Python %s on %s.\n' %
                   (sys.version, sys.platform))
        self.write('Type "copyright", "credits" or "license"'
                   ' for more information on Python.\n')
        self.write(sys.ps1)

    def flush(self):
        """
        Simulate stdin, stdout, and stderr.
        """
        pass

    def isatty(self):
        """
        Simulate stdin, stdout, and stderr.
        """
        return 1

    def readline(self):
        """
        Simulate stdin, stdout, and stderr.
        """
        self.reading = 1
        self.__clearLine()
        self.__moveCursorToEnd()
        while self.reading:
            qApp.processOneEvent()
        if self.line.length() == 0:
            return '\n'
        else:
            return str(self.line)

    def write(self, text):
        """
        Simulate stdin, stdout, and stderr.
        """
        # The output of self.append(text) contains to many newline characters,
        # so work around QTextEdit's policy for handling newline characters.
        hack = self.text()
        hack.append(text)
        self.setText(hack)
        #self.setText(self.text().append(text)) # segmentation fault
        self.yLast, self.xLast = self.__moveCursorToEnd()

    def writelines(self, text):
        """
        Simulate stdin, stdout, and stderr.
        """
        map(self.write, text)
        print "DO WE EVER GET HERE? IF YES, OPTIMIZATION POSSIBLE"

    def fakeUser(self, lines):
        """
        Simulate a user: lines is a sequence of strings (Python statements).
        """
        for line in lines:
            self.line = QString(line.rstrip())
            self.write(self.line)
            self.write('\n')
            self.__run()

    def __run(self):
        """
        Append the last line to the history list, let the interpreter execute
        the last line(s), and clean up accounting for the interpreter results:
        (1) the interpreter succeeds
        (2) the interpreter fails, finds no errors and wants more line(s)
        (3) the interpreter fails, finds errors and writes them to sys.stderr
        """
        self.pointer = 0
        self.history.append(QString(self.line))
        self.lines.append(str(self.line))
        source = '\n'.join(self.lines)
        self.more = self.interpreter.runsource(source)
        if self.more:
            self.write(sys.ps2)
        else:
            self.write(sys.ps1)
            self.lines = []
        self.__clearLine()

    def __clearLine(self):
        """
        Clear input line buffer
        """
        self.line.truncate(0)
        self.point = 0

    def __insertText(self, text):
        """
        Insert text at the current cursor position.
        """
        y, x = self.getCursorPosition()
        self.insertAt(text, y, x)
        self.line.insert(self.point, text)
        self.point += text.length()
        self.setCursorPosition(y, x + text.length())

    def __moveCursorToEnd(self):
        y = self.numLines() - 1
        x = self.lineLength(y)
        self.setCursorPosition(y, x)
        return y, x

    def keyPressEvent(self, e):
        """
        Handle user input a key at a time.
        """
        text = e.text()
        key = e.key()
        ascii = e.ascii()

        if text.length() and ascii >= 32 and ascii < 127:
            self.__insertText(text)
            return

        if e.state() & Qt.ControlButton and key == self.eofKey:
            try:
                file = open(self.log, "w")
                file.write(str(self.text()))
                file.close()
            except:
                pass
            sys.exit()
            return

        if e.state() & Qt.ControlButton or e.state() & Qt.ShiftButton:
            e.ignore()
            return

        if key == Qt.Key_Backspace:
            if self.point:
                self.backspace()
                self.point -= 1
                self.line.remove(self.point, 1)
        elif key == Qt.Key_Delete:
            self.delChar()
            self.line.remove(self.point, 1)
        elif key == Qt.Key_Return or key == Qt.Key_Enter:
            self.write('\n')
            if self.reading:
                self.reading = 0
            else:
                self.__run()
        elif key == Qt.Key_Tab:
            self.__insertText(text)
        elif key == Qt.Key_Left:
            if self.point:
                self.cursorLeft()
                self.point -= 1
        elif key == Qt.Key_Right:
            if self.point < self.line.length():
                self.cursorRight()
                self.point += 1
        elif key == Qt.Key_Home:
            self.setCursorPosition(self.yLast, self.xLast)
            self.point = 0
        elif key == Qt.Key_End:
            self.end()
            self.point = self.line.length()
        elif key == Qt.Key_Up:
            if len(self.history):
                if self.pointer == 0:
                    self.pointer = len(self.history)
                self.pointer -= 1
                self.__recall()
        elif key == Qt.Key_Down:
            if len(self.history):
                self.pointer += 1
                if self.pointer == len(self.history):
                    self.pointer = 0
                self.__recall()
        else:
            e.ignore()

    def __recall(self):
        """
        Display the current item from the command history.
        """
        self.setCursorPosition(self.yLast, self.xLast)
        self.killLine()  # QMultiLineEdit
        self.__clearLine()  # self.line
        self.__insertText(self.history[self.pointer])

    def focusNextPrevChild(self, next):
        """
        Suppress tabbing to the next window in multi-line commands. 
        """
        if next and self.more:
            return 0
        return QMultiLineEdit.focusNextPrevChild(self, next)

    def mousePressEvent(self, e):
        """
        Keep the cursor after the last prompt.
        """
        if e.button() == Qt.LeftButton:
            self.__moveCursorToEnd()
        return

    def contentsContextMenuEvent(self, ev):
        """
        Suppress the right button context menu.
        """
        return
Esempio n. 30
0
class DigitalWatchStatechart(StateMachine):

    # Constants for this model
    StateNum = 4
    EventNames = ["__INTERNAL_0_TIME_0", "start", "stop", "topRightPressed"]
    StateNames = ["New", "Running", "Setup", "Stopped"]
    ParentTable = [
        -1,  # New -- parent (None)
        -1,  # Running -- parent (None)
        -1,  # Setup -- parent (None)
        -1  # Stopped -- parent (None)
    ]
    HistoryStateTable = [0, 0, 0, 0]
    LeafStateTable = ["New", "Running", "Setup", "Stopped"]
    OrthogonalInBetween = [[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0],
                           [0, 0, 0, 0], [0, 0, 0, 0]]
    OrthogonalTable = [[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]]
    IntervalTable = ["3", None, None, None]
    RescheduleTable = [1, -1, -1, -1]
    Hierarchy = [
        [0, 0, 0, 0],  # substates of state New
        [0, 0, 0, 0],  # substates of state Running
        [0, 0, 0, 0],  # substates of state Setup
        [0, 0, 0, 0]  # substates of state Stopped
    ]
    CommonStateTable = [[-1, -1, -1, -1], [-1, -1, -1, -1], [-1, -1, -1, -1],
                        [-1, -1, -1, -1]]
    Description = None

    Lock = thread.allocate_lock()
    CurrentModel = None

    def __init__(self, Interpreter=None, Parent=None, OldInstance=None):

        # Variables
        self.Parent = Parent
        self.HistoryCount = 0
        self.state = None
        self.BackState = None
        if OldInstance != None:
            self.Submodels = OldInstance.Submodels
        else:
            self.Submodels = []
            for i in range(DigitalWatchStatechart.StateNum):
                self.Submodels.append(None)
        self.history = []
        for i in range(DigitalWatchStatechart.StateNum):
            self.history.append(None)

        # Constructor
        for i in range(DigitalWatchStatechart.StateNum):
            self.history[i] = History()
            self.history[i].States = []
            self.history[i].Times = []
            for j in range(DigitalWatchStatechart.StateNum):
                self.history[i].States.append(-1)
                self.history[i].Times.append(-1)

        self.TimedTransitions = []  # used only when --ext is set
        for i in range(DigitalWatchStatechart.StateNum):
            self.TimedTransitions.append(None)

        self.clearEnteredStates()
        self.HasInteractor = 0

        # Interpreter of action code
        if self.Parent == None:  # Top-level model
            if Interpreter:
                self.DefaultInterpreter = Interpreter
            else:
                self.DefaultInterpreter = InteractiveInterpreter()
            self.setupInterpreter()

            self.EventsCond = threading.Condition()
            self.SchedulerCond = threading.Condition()
            self.Schedules = []
            self.PendingEvents = None
            self.PendingEventsTail = None
        else:
            self.DefaultInterpreter = Interpreter
        self.Started = 0
        self.Stopped = 0

        self.description = DigitalWatchStatechart.Description

    # Methods
    def isParent(self, sp, sc):

        return sc >= 0 and (sp < 0 or DigitalWatchStatechart.Hierarchy[sp][sc])

    def isInState(self, s, check_substate=1, use_backup=1):

        if isinstance(s, int):
            if use_backup:
                st = self.BackState
            else:
                st = self.state
            while st != None:
                if st.StateID == s or (check_substate
                                       and self.isParent(s, st.StateID)):
                    return 1
                else:
                    st = st.Next
            return 0

        elif isinstance(s, str):
            i = 0
            while i < DigitalWatchStatechart.StateNum:
                if s == DigitalWatchStatechart.StateNames[i]:
                    return self.isInState(i, check_substate, use_backup)
                i = i + 1
            i = 0
            while i < DigitalWatchStatechart.StateNum:
                stname = DigitalWatchStatechart.StateNames[i]
                if self.Submodels[i] != None and startsWith(s, stname + "."):
                    pos = len(stname) + 1
                    SubmodelState = s[pos:]
                    return self.isInState(
                        i, 0, use_backup) and self.Submodels[i].isInState(
                            SubmodelState, check_substate, use_backup)
                i = i + 1
            return 0

        else:
            return 0

    class main_callable:
        def __call__(self, argv):
            model = DigitalWatchStatechart()
            cmd = ""
            model.initModel()
            if model.HasInteractor:
                model.runInteractor()
            else:
                cond = thread.allocate_lock()
                while cmd != "exit":
                    sys.__stdout__.write(model.getCurrentState() + " > ")
                    cmd = string.strip(sys.__stdin__.readline())
                    if cmd == "exit":
                        break
                    if not model.Stopped:
                        cond.acquire()
                        model.event(cmd, [], cond)
                        cond.acquire()
                        cond.release()
            model.runFinalizer()

    main = main_callable()

    def initModel(self, run_initializer=1, run_enter_actions=1):

        self.clearEnteredStates()
        if self.Parent == None and DigitalWatchStatechart.Description != None:
            sys.__stdout__.write(DigitalWatchStatechart.Description + "\n")
        self.addInState(2)  # init state "Setup"
        self.recordEnteredState(2)
        if run_initializer:
            self.runInitializer()
        if not self.HasInteractor:
            self.start(None, run_enter_actions)

    def applyMask(self, mask, dest):

        i = 0
        while i < DigitalWatchStatechart.StateNum:
            dest[i] = dest[i] and mask[i]
            i = i + 1

    def handleEvent(self, se, params=[], cond=None, scheduler=None):

        if not self.Started:
            if cond:
                cond.release()
            return 0
        self.params = params
        handled = 0
        table = []
        i = 0
        while i < DigitalWatchStatechart.StateNum:
            table.append(1)
            i = i + 1
        if self.state:
            self.BackState = self.state.copy()
        else:
            self.BackState = None
        e = self.eventStr2Int(se)
        if e == 0:  # event "__INTERNAL_0_TIME_0"
            if table[1] and self.isInState(1) and self.testCondition(0):
                if (scheduler == self or scheduler == None) and table[1]:
                    self.runActionCode(2)  # output action(s)
                    self.runExitActionsForStates(-1)
                    self.clearEnteredStates()
                    self.changeState(1, 1)
                    self.runEnterActionsForStates(self.StatesEntered, 1)
                    self.applyMask(DigitalWatchStatechart.OrthogonalTable[1],
                                   table)
                    handled = 1
        elif e == 1:  # event "start"
            if table[2] and self.isInState(2) and self.testCondition(1):
                if (scheduler == self or scheduler == None) and table[2]:
                    self.runActionCode(3)  # output action(s)
                    self.runExitActionsForStates(-1)
                    self.clearEnteredStates()
                    self.changeState(2, 1)
                    self.runEnterActionsForStates(self.StatesEntered, 1)
                    self.applyMask(DigitalWatchStatechart.OrthogonalTable[2],
                                   table)
                    handled = 1
        elif e == 2:  # event "stop"
            if table[0] and self.isInState(0) and self.testCondition(2):
                if (scheduler == self or scheduler == None) and table[0]:
                    self.runExitActionsForStates(-1)
                    self.clearEnteredStates()
                    self.changeState(0, 3)
                    self.runEnterActionsForStates(self.StatesEntered, 1)
                    self.applyMask(DigitalWatchStatechart.OrthogonalTable[0],
                                   table)
                    handled = 1
        elif e == 3:  # event "topRightPressed"
            if table[1] and self.isInState(1) and self.testCondition(3):
                if (scheduler == self or scheduler == None) and table[1]:
                    self.runActionCode(4)  # output action(s)
                    self.runExitActionsForStates(-1)
                    self.clearEnteredStates()
                    self.changeState(1, 0)
                    self.runEnterActionsForStates(self.StatesEntered, 1)
                    self.applyMask(DigitalWatchStatechart.OrthogonalTable[1],
                                   table)
                    handled = 1
            if table[0] and self.isInState(0) and self.testCondition(4):
                if (scheduler == self or scheduler == None) and table[0]:
                    self.runActionCode(5)  # output action(s)
                    self.runExitActionsForStates(-1)
                    self.clearEnteredStates()
                    self.changeState(0, 0)
                    self.runEnterActionsForStates(self.StatesEntered, 1)
                    self.applyMask(DigitalWatchStatechart.OrthogonalTable[0],
                                   table)
                    handled = 1
        if cond and self.Parent == None:  # Top-level model
            cond.release()
        if not handled and e >= 0 and (
                scheduler == self or scheduler
                == None) and DigitalWatchStatechart.RescheduleTable[e] >= 0:
            self.addSchedule(DigitalWatchStatechart.RescheduleTable[e],
                             DigitalWatchStatechart.IntervalTable[e],
                             DigitalWatchStatechart.EventNames[e], scheduler)
        return handled

    def forceIntoState(self, s):

        changed = 0
        s2 = self.state
        while s2 != None:
            HasCommonParent = 0
            for i in range(DigitalWatchStatechart.StateNum):
                if self.isParent(i, s2.StateID) and self.isParent(i, s):
                    HasCommonParent = 1
                    if not self.hasOrthogonalStateInBetween(i, s2.StateID):
                        self.changeState(s2.StateID, s)
                        changed = 1
            if not HasCommonParent:
                self.changeState(s2.StateID, s)
                changed = 1
            s2 = s2.Next
        if not changed:
            self.addInState(s)

    def changeState(self, s1, s2, check_history=0, top_level=0):

        # t1=common(s1, s2)
        t1 = DigitalWatchStatechart.CommonStateTable[s1][s2]
        self.recordHistory(t1)
        if t1 >= 0:
            self.removeOutStates(t1)
        else:
            self.state = None
        # t2=history(s2)
        t2 = DigitalWatchStatechart.HistoryStateTable[s2]
        if t2 == 0:  # no history
            self.generateStates(t1, s2)
        elif t2 == 1:  # normal history
            if not check_history:
                self.generateStates(t1, s2)
            elif self.hasHistoryRecorded(s2) and self.Submodels[s2] == None:
                self.generateStates(t1, self.history[s2].States[s2])
            else:
                self.generateStates(t1, s2, 1)
        elif t2 == 2:  # deep history
            if check_history and self.hasHistoryRecorded(s2):
                if self.Submodels[s2]:
                    self.recordEnteredState(s2, 1, 1, t1)
                    self.addInState(s2)
                else:
                    for i in range(DigitalWatchStatechart.StateNum):
                        hs = self.history[s2].States[i]
                        if hs >= 0 and self.isLeafState(hs):
                            self.recordEnteredState(hs, 1, 1, t1)
                            self.addInState(hs)
            else:
                self.generateStates(t1, s2)

    def addInState(self, s):

        if not self.isInState(s, 1, 0):
            st = State()
            st.StateID = s
            st.Next = self.state
            self.state = st
            return 1
        else:
            return 0

    def generateStates(self, common, dest, history_type=0):

        if common == -1:
            if dest == 0:
                if history_type != 2 or self.check_history(-1):
                    if history_type != 2 or self.check_history(0):
                        self.recordEnteredState(0)
                        self.addInState(0)  # move into leaf state "New"
            elif dest == 1:
                if history_type != 2 or self.check_history(-1):
                    if history_type != 2 or self.check_history(1):
                        self.recordEnteredState(1)
                        self.addInState(1)  # move into leaf state "Running"
            elif dest == 2:
                if history_type != 2 or self.check_history(-1):
                    if history_type != 2 or self.check_history(2):
                        self.recordEnteredState(2)
                        self.addInState(2)  # move into leaf state "Setup"
            elif dest == 3:
                if history_type != 2 or self.check_history(-1):
                    if history_type != 2 or self.check_history(3):
                        self.recordEnteredState(3)
                        self.addInState(3)  # move into leaf state "Stopped"
        elif common == 0:
            if dest == 0:
                if history_type != 2 or self.check_history(0):
                    self.addInState(0)  # move into leaf state "New"
        elif common == 1:
            if dest == 1:
                if history_type != 2 or self.check_history(1):
                    self.addInState(1)  # move into leaf state "Running"
        elif common == 2:
            if dest == 2:
                if history_type != 2 or self.check_history(2):
                    self.addInState(2)  # move into leaf state "Setup"
        elif common == 3:
            if dest == 3:
                if history_type != 2 or self.check_history(3):
                    self.addInState(3)  # move into leaf state "Stopped"

    def removeOutStates(self, common_state):

        s = self.state
        prev = None
        while s != None:
            if self.isParent(common_state, s.StateID):
                if prev == None:
                    self.state = self.state.Next
                else:
                    prev.Next = s.Next
            else:
                prev = s
            s = s.Next

    def eventStr2Int(self, event):

        for i in range(4):
            if event == DigitalWatchStatechart.EventNames[i]:
                return i
        return -1

    def stateInt2Str(self, state):

        if state == -1:
            return ""
        else:
            return DigitalWatchStatechart.StateNames[state]

    def getCurrentStateList(self):

        sl = StringList()
        slend = sl
        s = self.state
        while s != None:
            sm = self.Submodels[s.StateID]
            curstate = self.stateInt2Str(s.StateID)
            if sm != None:
                slend.Next = sm.getCurrentStateList()
                while slend.Next != None:
                    slend.Next.str = curstate + "." + slend.Next.str
                    slend = slend.Next
            else:
                slend.Next = StringList(curstate)
                slend = slend.Next
            s = s.Next
        return sl.Next

    def getCurrentState(self, states=None):

        if states == None:
            states = self.getCurrentStateList()
            if states != None:
                states = states.sort()
                strst = "['%s'%s]" % (states.str, self.getCurrentState(states))
            else:
                strst = "[]"
        else:
            if states.Next:
                strst = ", '%s'%s" % (states.Next.str,
                                      self.getCurrentState(states.Next))
            else:
                strst = ""
        return strst

    def getParentState(self, state):

        return DigitalWatchStatechart.ParentTable[state]

    def getSubstates(self, state):

        substates = None
        if state == -1:  # substates of ""
            # add substate "New"
            st = IntList()
            st.int = 0
            st.Next = substates
            substates = st
            # add substate "Running"
            st = IntList()
            st.int = 1
            st.Next = substates
            substates = st
            # add substate "Setup"
            st = IntList()
            st.int = 2
            st.Next = substates
            substates = st
            # add substate "Stopped"
            st = IntList()
            st.int = 3
            st.Next = substates
            substates = st
        elif state == 0:  # substates of "New"
            pass
        elif state == 1:  # substates of "Running"
            pass
        elif state == 2:  # substates of "Setup"
            pass
        elif state == 3:  # substates of "Stopped"
            pass
        return substates

    def isHistoryState(self, state):

        return DigitalWatchStatechart.HistoryStateTable[state] > 0

    def isLeafState(self, state):

        if isinstance(state, int):
            return DigitalWatchStatechart.LeafStateTable[state] != None

        elif isinstance(state, str):
            for i in range(DigitalWatchStatechart.StateNum):
                if DigitalWatchStatechart.LeafStateTable[i] == None:
                    continue
                if state == DigitalWatchStatechart.LeafStateTable[
                        i] and self.Submodels[i] == None:
                    return 1
                elif startsWith(state,
                                DigitalWatchStatechart.LeafStateTable[i] +
                                ".") and self.Submodels[i] != None:
                    SubmodelState = state[DigitalWatchStatechart.
                                          LeafStateTable[i].length() + 1:]
                    return self.Submodels[i].isLeafState(SubmodelState)
        return 0

    def isHistoryUp2Date(self, state, time):

        for i in range(DigitalWatchStatechart.StateNum):
            if self.history[state].Times[i] >= time:
                return 1
        return 0

    def mergeHistory(self, state, states, times):

        max = -1
        for i in range(DigitalWatchStatechart.StateNum):
            if times[i] > max:
                max = times[i]
        if self.isHistoryUp2Date(state, max):
            for i in range(DigitalWatchStatechart.StateNum):
                if times[i] > self.history[state].Times[i]:
                    self.history[state].States[i] = states[i]
                    self.history[state].Times[i] = times[i]
        else:
            self.history[state].States = copy.copy(states)
            self.history[state].Times = copy.copy(times)

    def recordHistory(self, top_state):

        curtime = self.HistoryCount
        self.HistoryCount = self.HistoryCount + 1
        s = self.state
        while s != None:
            child = s.StateID
            states = []
            times = []
            for i in range(DigitalWatchStatechart.StateNum):
                states.append(-1)
                times.append(-1)
            states[child] = child
            times[child] = curtime
            if top_state < 0 or self.isParent(top_state, child):
                parent = self.getParentState(child)
                if self.isHistoryState(child):
                    self.history[child].Submodel = self.Submodels[child]
                while parent >= 0 and times[parent] != curtime:
                    states[parent] = child
                    times[parent] = curtime
                    if self.isHistoryState(parent):
                        self.mergeHistory(parent, states, times)
                    if parent == top_state:
                        break
                    child = parent
                    parent = self.getParentState(child)
            s = s.Next

    def hasHistoryRecorded(self, state):

        for i in range(DigitalWatchStatechart.StateNum):
            if self.history[state].States[i] != -1:
                return 1
            if self.Submodels[state] != None:
                return 1
        return 0

    def hasOrthogonalStateInBetween(self, parent, leaf):

        return DigitalWatchStatechart.OrthogonalInBetween[parent + 1][leaf]

    def check_history(self, dest):

        s = self.state
        while s != None:
            if self.isParent(
                    dest, s.StateID) and not self.hasOrthogonalStateInBetween(
                        dest, s.StateID):
                return 0
            s = s.Next
        return 1

    def getEnabledEvents(self):

        events = EventList()
        if self.isInState(1):
            events.Append("__INTERNAL_0_TIME_0")
        if self.isInState(2):
            events.Append("start")
        if self.isInState(0):
            events.Append("stop")
        if self.isInState(1):
            events.Append("topRightPressed")
        if self.isInState(0):
            events.Append("topRightPressed")
        return events.Next

    def getHierarchy(self, start_level, state_prefix):

        h = Hierarchy()
        lasth = h
        # Generate state "New" in the hierarchy table
        lasth.Next = Hierarchy()
        lasth.Next.StateName = "New"
        if state_prefix == None:
            lasth.Next.PathName = "New"
        else:
            lasth.Next.PathName = state_prefix + ".New"
        lasth.Next.StateNum = 0
        lasth.Next.Level = start_level + 0
        lasth = lasth.Next
        # Generate state "Running" in the hierarchy table
        lasth.Next = Hierarchy()
        lasth.Next.StateName = "Running"
        if state_prefix == None:
            lasth.Next.PathName = "Running"
        else:
            lasth.Next.PathName = state_prefix + ".Running"
        lasth.Next.StateNum = 1
        lasth.Next.Level = start_level + 0
        lasth = lasth.Next
        # Generate state "Setup" in the hierarchy table
        lasth.Next = Hierarchy()
        lasth.Next.StateName = "Setup"
        if state_prefix == None:
            lasth.Next.PathName = "Setup"
        else:
            lasth.Next.PathName = state_prefix + ".Setup"
        lasth.Next.StateNum = 2
        lasth.Next.Level = start_level + 0
        lasth = lasth.Next
        # Generate state "Stopped" in the hierarchy table
        lasth.Next = Hierarchy()
        lasth.Next.StateName = "Stopped"
        if state_prefix == None:
            lasth.Next.PathName = "Stopped"
        else:
            lasth.Next.PathName = state_prefix + ".Stopped"
        lasth.Next.StateNum = 3
        lasth.Next.Level = start_level + 0
        lasth = lasth.Next
        return h.Next

    def topLevelHistory(self):

        s = self.state.StateID
        t = self.getParentState(s)
        while t != -1:
            s = t
            t = self.getParentState(s)
        self.changeState(s, s)

    def runActionCode(self, code_num):

        if code_num == 0:  # model finalizer
            pass
        elif code_num == 1:  # model initializer
            pass
        elif code_num == 2:  # output action(s) of a transition
            self.runCode("dump_message(\"transition after 3 seconds\")")
            # repeated timed transition
            self.addSchedule(1, DigitalWatchStatechart.IntervalTable[0],
                             DigitalWatchStatechart.EventNames[0], self)
        elif code_num == 3:  # output action(s) of a transition
            self.runCode("dump_message(\"Starting the Digital Watch\")")
            self.runCode("controller=eventhandler.get_event_params()")
        elif code_num == 4:  # output action(s) of a transition
            self.runCode("controller.refreshTimeDisplay()")
            self.runCode("dump_message(\"refreshing time display\")")
        elif code_num == 5:  # output action(s) of a transition
            self.runCode("controller.refreshTimeDisplay()")
            self.runCode("dump_message(\"refreshing time display\")")
        elif code_num == 6:  # enter actions for state "Running"
            # a timed transition
            self.addSchedule(1, DigitalWatchStatechart.IntervalTable[0],
                             DigitalWatchStatechart.EventNames[0], self)
        elif code_num == 7:  # enter actions for state "Stopped"
            # run finalizer for a final state
            self.runFinalizer()
        elif code_num == 8:  # exit actions for state "Running"
            # clean up timed transitions
            self.removeSchedule(1, self)

    def testCondition(self, cond_num):

        if cond_num==0 and \
           eval("(1)", self.DefaultInterpreter.locals):
            return 1
        elif cond_num==1 and \
           eval("(1)", self.DefaultInterpreter.locals):
            return 1
        elif cond_num==2 and \
           eval("(1)", self.DefaultInterpreter.locals):
            return 1
        elif cond_num==3 and \
           eval("(1)", self.DefaultInterpreter.locals):
            return 1
        elif cond_num==4 and \
           eval("(1)", self.DefaultInterpreter.locals):
            return 1
        return 0

    def runEnterActions(self, state):

        if state == 1:  # enter action(s) for state "Running"
            self.runActionCode(6)
        elif state == 3:  # enter action(s) for state "Stopped"
            self.runActionCode(7)

    def runExitActions(self, state):

        if state == 1:  # exit action(s) for state "Running"
            self.runActionCode(8)

    def compareSchedule(self, sched_a, sched_b):

        return cmp(sched_a[1], sched_b[1])

    def addSchedule(self, id, interval, event, scheduler):

        if self.Parent != None:  # Non-top-level model
            self.Parent.addSchedule(id, interval, event, scheduler)
            return
        f = eval(interval, self.DefaultInterpreter.locals)
        self.SchedulerCond.acquire()
        t = time.time() + f
        s = [id, t, interval, event, scheduler]
        self.Schedules.append(s)
        self.Schedules.sort(self.compareSchedule)
        self.SchedulerCond.notify()
        self.SchedulerCond.release()

    def removeSchedule(self, id, scheduler):

        if self.Parent != None:  # Non-top-level model
            self.Parent.removeSchedule(id, scheduler)
            return
        self.SchedulerCond.acquire()
        i = 0
        while i < len(self.Schedules):
            if self.Schedules[i][0] == id and self.Schedules[i][4] == scheduler:
                del self.Schedules[i]
            else:
                i = i + 1
        self.SchedulerCond.release()

    def scheduler(self):

        self.SchedulerCond.acquire()
        wait_cond = thread.allocate_lock()
        while 1:
            while not self.Schedules:
                self.SchedulerCond.wait()
                if self.Stopped:
                    self.SchedulerCond.release()
                    return
            while self.Schedules and self.Schedules[0][1] <= time.time():
                this_sched = self.Schedules[0]
                del self.Schedules[0]
                self.SchedulerCond.release()
                wait_cond.acquire()
                self.event(this_sched[3], [], wait_cond, this_sched[4])
                wait_cond.acquire()
                wait_cond.release()
                self.SchedulerCond.acquire()
            if self.Schedules:
                t = self.Schedules[0][1] - time.time()
                if t > 0:
                    self.SchedulerCond.wait(t)
                    if self.Stopped:
                        self.SchedulerCond.release()
                        return

    def recordAllEnteredStates(self):

        st = self.state
        while st != None:
            self.recordEnteredState(st.StateID, 1, 1)
            st = st.Next

    def recordEnteredState(self, s, superstates=0, submodel=0, commonstate=-1):

        # test if s is already recorded
        se = self.StatesEntered
        found = 0
        while se != None:
            if se.int == s:
                found = 1
                break
            se = se.Next

        if not found:
            if superstates:
                parent = self.getParentState(s)
                if parent >= 0 and parent != commonstate:
                    self.recordEnteredState(parent, 1, 0, commonstate)
            st = IntList()
            st.Next = self.StatesEntered
            st.int = s
            self.StatesEntered = st
            if submodel and self.Submodels[s]:
                self.Submodels[s].recordAllEnteredStates()

    def runAllEnterActions(self):

        self.runEnterActionsForStates(self.StatesEntered, 1)

    def runEnterActionsForStates(self, states, recursive=0):

        if states:
            self.runEnterActionsForStates(states.Next, 0)
            self.runEnterActions(states.int)
        if recursive:
            for s in self.Submodels:
                if s:
                    s.runAllEnterActions()

    def runExitActionsForStates(self, common_state):

        substates = self.getSubstates(common_state)
        if substates == None:
            s = self.state
            while s != None and s.StateID != common_state:
                s = s.Next
            if s != None and self.Submodels[s.StateID]:
                self.Submodels[s.StateID].runExitActionsForStates(-1)
            return s != None
        else:
            has_current_substate = 0
            while substates != None:
                res = self.runExitActionsForStates(substates.int)
                has_current_substate = has_current_substate or res
                if res:
                    self.runExitActions(substates.int)
                substates = substates.Next
            return has_current_substate

    def runInitializer(self):

        self.runActionCode(1)
        for s in self.Submodels:
            if s:
                s.runInitializer()

    def runFinalizer(self):

        if self.Started:
            self.Started = 0
            for s in self.Submodels:
                if s:
                    s.runFinalizer()
            self.runActionCode(0)
            if self.Parent == None:  # Top-level model
                self.EventsCond.acquire()
                self.SchedulerCond.acquire()
                self.Stopped = 1
                self.EventsCond.notify()
                self.SchedulerCond.notify()
                self.SchedulerCond.release()
                self.EventsCond.release()
            else:
                self.Stopped = 1

    def clearEnteredStates(self):

        self.StatesEntered = None
        for s in self.Submodels:
            if s:
                s.clearEnteredStates()

    def get_current_state(self):

        return self.getCurrentState()

    def runCode(self, c):

        self.DefaultInterpreter.runsource(c + "\n", "<input>", "exec")

    def setupInterpreter(self):

        self.DefaultInterpreter.locals["eventhandler"] = self
        self.DefaultInterpreter.locals["dump_message"] = self.dump_message

    def get_event_params(self):

        return self.params

    def dump_message(self, msg):

        print msg

    def is_in_state(self, s, check_substate=1):

        return self.isInState(s, check_substate)

    def start(self, lock=None, run_enter_actions=1):

        if self.Parent == None:  # Top-level model
            if run_enter_actions:
                self.runEnterActionsForStates(self.StatesEntered, 1)
            self.Started = 1
            thread.start_new_thread(self.handleEvent_wrapper, ())
            thread.start_new_thread(self.scheduler, ())
            if lock:
                lock.release()
        else:
            self.Started = 1
        for submodel in self.Submodels:
            if submodel != None:
                submodel.start()

    def shutdown(self):

        pass

    def handleEvent_wrapper(self):

        self.EventsCond.acquire()
        while 1:
            if self.PendingEvents == None:
                self.EventsCond.wait()
                if self.Stopped:
                    self.EventsCond.release()
                    return
            event = self.PendingEvents
            self.PendingEvents = self.PendingEvents.Next
            if self.PendingEvents == None:
                self.PendingEventsTail = None
            event.next = None
            self.EventsCond.release()
            self.handleEvent(event.Event[0], event.Event[1], event.Event[2],
                             event.Event[3])
            self.EventsCond.acquire()
            if self.Stopped:
                self.EventsCond.release()
                return

    def event(self, e, params=[], cond=None, scheduler=None):

        self.EventsCond.acquire()
        ev = EventList()
        ev.Event = [e, params, cond, scheduler]
        if self.PendingEventsTail != None:
            self.PendingEventsTail.Next = ev
        else:
            self.PendingEvents = ev
        self.PendingEventsTail = ev
        self.EventsCond.notify()
        self.EventsCond.release()
Esempio n. 31
0
#! /usr/bin/env python
Esempio n. 32
0
class QShell(QtGui.QTextEdit):
    """This class embeds a python interperter in a QTextEdit Widget
    It is based on PyCute developed by Gerard Vermeulen.
    
    """
    def __init__(self, locals=None, parent=None):
        """Constructor.

        The optional 'locals' argument specifies the dictionary in which code
        will be executed; it defaults to a newly created dictionary with key 
        "__name__" set to "__console__" and key "__doc__" set to None.

        The optional 'log' argument specifies the file in which the interpreter
        session is to be logged.
        
        The optional 'parent' argument specifies the parent widget. If no parent
        widget has been specified, it is possible to exit the interpreter 
        by Ctrl-D.

        """

        QtGui.QTextEdit.__init__(self, parent)
        self.setReadOnly(False)
        self.setWindowTitle("Console")
        # to exit the main interpreter by a Ctrl-D if QShell has no parent
        if parent is None:
            self.eofKey = QtCore.Qt.Key_D
        else:
            self.eofKey = None

        # flag for knowing when selecting text
        self.selectMode = False
        self.interpreter = None
        self.controller = None
        # storing current state
        #this is not working on mac
        #self.prev_stdout = sys.stdout
        #self.prev_stdin = sys.stdin
        #self.prev_stderr = sys.stderr
        # capture all interactive input/output
        #sys.stdout   = self
        #sys.stderr   = self
        #sys.stdin    = self

        # user interface setup

        self.setAcceptRichText(False)
        self.setWordWrapMode(QtGui.QTextOption.WrapAnywhere)

        conf = get_vistrails_configuration()
        shell_conf = conf.shell
        # font
        font = QtGui.QFont(shell_conf.font_face, shell_conf.font_size)
        font.setFixedPitch(1)
        self.setFont(font)
        self.reset(locals)

    def load_package(self, pkg_name):
        reg = core.modules.module_registry.get_module_registry()
        package = reg.get_package_by_name(pkg_name)

        def create_dict(modules, ns, m, mdesc):
            md = {}
            if len(ns) == 0:
                d = {
                    '_module_desc': mdesc,
                    '_package': pkg,
                }
                modules[m] = type('module', (vistrails_module, ), d)
            else:
                if ns[0] in modules:
                    md = create_dict(modules[ns[0]], ns[1:], m, mdesc)
                else:
                    md = create_dict(md, ns[1:], m, mdesc)
                    modules[ns[0]] = md
            return modules

        def create_namespace_path(root, modules):
            for k, v in modules.iteritems():
                if type(v) == type({}):
                    d = create_namespace_path(k, v)
                    modules[k] = d

            if root is not None:
                modules['_package'] = pkg
                return type(root, (object, ), modules)()
            else:
                return modules

        def get_module_init(module_desc):
            def init(self, *args, **kwargs):
                self.__dict__['module'] = \
                    api.add_module_from_descriptor(module_desc)

            return init

        def get_module(package):
            def getter(self, attr_name):
                desc_tuple = (attr_name, '')
                if desc_tuple in package.descriptors:
                    module_desc = package.descriptors[desc_tuple]
                    d = {
                        '_module_desc': module_desc,
                        '_package': self,
                    }
                    return type('module', (vistrails_module, ), d)
                else:
                    raise AttributeError("type object '%s' has no attribute "
                                         "'%s'" %
                                         (self.__class__.__name__, attr_name))

            return getter

        d = {
            '__getattr__': get_module(package),
        }
        pkg = type(package.name, (object, ), d)()

        modules = {}
        for (m, ns) in package.descriptors:
            module_desc = package.descriptors[(m, ns)]
            modules = create_dict(modules, ns.split('|'), m, module_desc)

        modules = create_namespace_path(None, modules)

        for (k, v) in modules.iteritems():
            setattr(pkg, k, v)
        return pkg

    def selected_modules(self):
        shell_modules = []
        modules = api.get_selected_modules()
        for module in modules:
            d = {'_module': module}
            shell_modules.append(type('module', (vistrails_module, ), d)())
        return shell_modules

    def reset(self, locals):
        """reset(locals) -> None
        Reset shell preparing it for a new session.
        
        """
        locals['load_package'] = self.load_package
        locals['selected_modules'] = self.selected_modules
        if self.interpreter:
            del self.interpreter
        self.interpreter = InteractiveInterpreter(locals)

        # last line + last incomplete lines
        self.line = QtCore.QString()
        self.lines = []
        # the cursor position in the last line
        self.point = 0
        # flag: the interpreter needs more input to run the last lines.
        self.more = 0
        # flag: readline() is being used for e.g. raw_input() and input()
        self.reading = 0
        # history
        self.history = []
        self.pointer = 0
        self.last = 0
        # interpreter prompt.
        if hasattr(sys, "ps1"):
            sys.ps1
        else:
            sys.ps1 = ">>> "
        if hasattr(sys, "ps2"):
            sys.ps2
        else:
            sys.ps2 = "... "

        # interpreter banner

        self.write('VisTrails shell running Python %s on %s.\n' %
                   (sys.version, sys.platform))
        self.write('Type "copyright", "credits" or "license"'
                   ' for more information on Python.\n')
        self.write(sys.ps1)

    def flush(self):
        """flush() -> None. 
        Simulate stdin, stdout, and stderr.
        
        """
        pass

    def isatty(self):
        """isatty() -> int
        Simulate stdin, stdout, and stderr.
        
        """
        return 1

    def readline(self):
        """readline() -> str
        
        Simulate stdin, stdout, and stderr.
        
        """
        self.reading = 1
        self.__clearLine()
        cursor = self.textCursor()
        cursor.movePosition(QtGui.QTextCursor.End)
        self.setTextCursor(cursor)
        app = QtGui.QApplication.instance()

        while self.reading:
            app.processOneEvent()
        if self.line.length() == 0:
            return '\n'
        else:
            return str(self.line)

    def write(self, text):
        """write(text: str) -> None
        Simulate stdin, stdout, and stderr.
        
        """

        cursor = self.textCursor()
        cursor.movePosition(QtGui.QTextCursor.End)
        cursor.clearSelection()
        self.setTextCursor(cursor)
        self.insertPlainText(text)
        cursor = self.textCursor()
        self.last = cursor.position()

    def write_input(self, text):
        cursor = self.textCursor()
        cursor.movePosition(QtGui.QTextCursor.End)
        cursor.clearSelection()
        self.setTextCursor(cursor)
        self.__insertText(text)

    def write_and_exec(self, commandlist):
        for command in commandlist:
            self.write_input(command)
            self.__run()

    def insertFromMimeData(self, source):
        if source.hasText():
            cmds = source.text().split(QtCore.QString('\n'))
            self.write_and_exec(cmds)

    def scroll_bar_at_bottom(self):
        """Returns true if vertical bar exists and is at bottom, or if
        vertical bar does not exist."""
        bar = self.verticalScrollBar()
        if not bar:
            return True
        return bar.value() == bar.maximum()

    def __run(self):
        """__run() -> None
        Append the last line to the history list, let the interpreter execute
        the last line(s), and clean up accounting for the interpreter results:
        (1) the interpreter succeeds
        (2) the interpreter fails, finds no errors and wants more line(s)
        (3) the interpreter fails, finds errors and writes them to sys.stderr
        
        """
        cursor = self.textCursor()
        cursor.movePosition(QtGui.QTextCursor.End)
        self.setTextCursor(cursor)
        # self.set_controller()
        should_scroll = self.scroll_bar_at_bottom()
        self.pointer = 0
        self.history.append(QtCore.QString(self.line))
        self.lines.append(str(self.line))
        source = '\n'.join(self.lines)
        self.write('\n')
        self.more = self.interpreter.runsource(source)
        if self.more:
            self.write(sys.ps2)
        else:
            self.write(sys.ps1)
            self.lines = []
        self.__clearLine()
        if should_scroll:
            bar = self.verticalScrollBar()
            if bar:
                bar.setValue(bar.maximum())

    def __clearLine(self):
        """__clearLine() -> None
        Clear input line buffer.
        
        """
        self.line.truncate(0)
        self.point = 0

    def __insertText(self, text):
        """__insertText(text) -> None
        Insert text at the current cursor position.
        
        """
        self.insertPlainText(text)
        self.line.insert(self.point, text)
        self.point += text.length()

    # def add_pipeline(self, p):
    #     """
    #     add_pipeline(p) -> None
    #     Set the active pipeline in the command shell.  This replaces the modules
    #     variable with the list of current active modules of the selected pipeline.
    #     """
    #     if self.controller:
    #         self.interpreter.active_pipeline = self.controller.current_pipeline
    #     else:
    #         self.interpreter.active_pipeline = p
    #     cmd = 'active_pipeline = self.shell.interpreter.active_pipeline'
    #     self.interpreter.runcode(cmd)
    #     cmd = 'modules = self.vistrails_interpreter.find_persistent_entities(active_pipeline)[0]'
    #     self.interpreter.runcode(cmd)

    def set_controller(self, controller=None):
        """set_controller(controller: VistrailController) -> None
        Set the current VistrailController on the shell.
        """
        self.controller = controller
        if controller and self.controller.current_pipeline:
            self.interpreter.active_pipeline = self.controller.current_pipeline
            cmd = 'run_pipeline = self.shell.run_pipeline'
            self.interpreter.runcode(cmd)
            cmd = 'active_pipeline = self.shell.interpreter.active_pipeline'
            self.interpreter.runcode(cmd)
            cmd = 'modules = self.vistrails_interpreter.' \
                'find_persistent_entities(active_pipeline)[0]'
            self.interpreter.runcode(cmd)

    # def set_pipeline(self):
    #     """set_active_pipeline() -> None
    #     Makes sure that the pipeline being displayed is present in the shell for
    #     direct inspection and manipulation
    #     """
    #     self.add_pipeline(None)

    def run_pipeline(self):
        if self.controller:
            if self.interpreter.active_pipeline:
                self.controller.execute_current_workflow()

    def keyPressEvent(self, e):
        """keyPressEvent(e) -> None
        Handle user input a key at a time.

        Notice that text might come more than one keypress at a time
        if user is a fast enough typist!
        
        """
        text = e.text()
        key = e.key()

        # NB: Sometimes len(str(text)) > 1!
        if text.length() and all(
                ord(x) >= 32 and ord(x) < 127 for x in str(text)):
            # exit select mode and jump to end of text
            cursor = self.textCursor()
            if self.selectMode or cursor.hasSelection():
                self.selectMode = False
                cursor.movePosition(QtGui.QTextCursor.End)
                cursor.clearSelection()
                self.setTextCursor(cursor)
            self.__insertText(text)
            return

        if e.modifiers() & QtCore.Qt.MetaModifier and key == self.eofKey:
            self.parent().closeSession()

        if e.modifiers() & QtCore.Qt.ControlModifier:
            if key == QtCore.Qt.Key_C or key == QtCore.Qt.Key_Insert:
                self.copy()
            elif key == QtCore.Qt.Key_V:
                cursor = self.textCursor()
                cursor.movePosition(QtGui.QTextCursor.End)
                cursor.clearSelection()
                self.setTextCursor(cursor)
                self.paste()
            elif key == QtCore.Qt.Key_A:
                self.selectAll()
                self.selectMode = True
            else:
                e.ignore()
            return

        if e.modifiers() & QtCore.Qt.ShiftModifier:
            if key == QtCore.Qt.Key_Insert:
                cursor = self.textCursor()
                cursor.movePosition(QtGui.QTextCursor.End)
                cursor.clearSelection()
                self.setTextCursor(cursor)
                self.paste()
            else:
                e.ignore()
            return

        # exit select mode and jump to end of text
        cursor = self.textCursor()
        if self.selectMode or cursor.hasSelection():
            self.selectMode = False
            cursor.movePosition(QtGui.QTextCursor.End)
            cursor.clearSelection()
            self.setTextCursor(cursor)

        if key == QtCore.Qt.Key_Backspace:
            if self.point:
                QtGui.QTextEdit.keyPressEvent(self, e)
                self.point -= 1
                self.line.remove(self.point, 1)
        elif key == QtCore.Qt.Key_Delete:
            QtGui.QTextEdit.keyPressEvent(self, e)
            self.line.remove(self.point, 1)
        elif key == QtCore.Qt.Key_Return or key == QtCore.Qt.Key_Enter:
            if self.reading:
                self.reading = 0
            else:
                self.__run()
        elif key == QtCore.Qt.Key_Tab:
            self.__insertText(text)
        elif key == QtCore.Qt.Key_Left:
            if self.point:
                QtGui.QTextEdit.keyPressEvent(self, e)
                self.point -= 1
        elif key == QtCore.Qt.Key_Right:
            if self.point < self.line.length():
                QtGui.QTextEdit.keyPressEvent(self, e)
                self.point += 1
        elif key == QtCore.Qt.Key_Home:
            cursor = self.textCursor()
            cursor.movePosition(QtGui.QTextCursor.StartOfLine)
            cursor.setPosition(cursor.position() + 4)
            self.setTextCursor(cursor)
            self.point = 0
        elif key == QtCore.Qt.Key_End:
            QtGui.QTextEdit.keyPressEvent(self, e)
            self.point = self.line.length()
        elif key == QtCore.Qt.Key_Up:
            if len(self.history):
                if self.pointer == 0:
                    self.pointer = len(self.history)
                self.pointer -= 1
                self.__recall()
        elif key == QtCore.Qt.Key_Down:
            if len(self.history):
                self.pointer += 1
                if self.pointer == len(self.history):
                    self.pointer = 0
                self.__recall()
        else:
            e.ignore()

    def __recall(self):
        """__recall() -> None
        Display the current item from the command history.
        
        """
        cursor = self.textCursor()
        cursor.setPosition(self.last)

        cursor.select(QtGui.QTextCursor.LineUnderCursor)

        cursor.removeSelectedText()
        self.setTextCursor(cursor)
        self.insertPlainText(sys.ps1)
        self.__clearLine()
        self.__insertText(self.history[self.pointer])

    def focusNextPrevChild(self, next):
        """focusNextPrevChild(next) -> None
        Suppress tabbing to the next window in multi-line commands. 
        
        """
        if next and self.more:
            return 0
        return QtGui.QTextEdit.focusNextPrevChild(self, next)

    def mousePressEvent(self, e):
        """mousePressEvent(e) -> None
        Keep the cursor after the last prompt.
        """
        if e.button() == QtCore.Qt.LeftButton:
            self.selectMode = True
            QtGui.QTextEdit.mousePressEvent(self, e)
#            cursor = self.textCursor()
#            cursor.movePosition(QtGui.QTextCursor.End)
#            self.setTextCursor(cursor)
        return

    def hide(self):
        """suspend() -> None
        Called when hiding the parent window in order to recover the previous
        state.

        """
        #recovering the state
        sys.stdout = sys.__stdout__
        sys.stderr = sys.__stderr__
        sys.stdin = sys.__stdin__

    def show(self):
        """show() -> None
        Store previous state and starts capturing all interactive input and 
        output.
        
        """
        # capture all interactive input/output
        sys.stdout = self
        sys.stderr = self
        sys.stdin = self
        self.setFocus()

    def saveSession(self, fileName):
        """saveSession(fileName: str) -> None 
        Write its contents to a file """
        output = open(str(fileName), 'w')
        output.write(self.toPlainText())
        output.close()

    def restart(self, locals=None):
        """restart(locals=None) -> None 
        Restart a new session 

        """
        self.clear()
        self.reset(locals)

    def contentsContextMenuEvent(self, ev):
        """
        contentsContextMenuEvent(ev) -> None
        Suppress the right button context menu.
        
        """
        return
Esempio n. 33
0
class ButtonBehaviour_MDL(StateMachine):

    # Constants for this model
    StateNum = 3
    EventNames = [
        "(create)*", "<Any-ButtonRelease-1>", "<ButtonPress-1>", "[Done]"
    ]
    StateNames = ["Activate Button*", "Default", "Idle"]
    ParentTable = [
        -1,  # Activate Button* -- parent (None)
        -1,  # Default -- parent (None)
        -1  # Idle -- parent (None)
    ]
    HistoryStateTable = [0, 0, 0]
    LeafStateTable = ["Activate Button*", "Default", "Idle"]
    OrthogonalInBetween = [[0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0]]
    OrthogonalTable = [[0, 0, 0], [0, 0, 0], [0, 0, 0]]
    IntervalTable = [None, None, None, None]
    RescheduleTable = [-1, -1, -1, -1]
    Hierarchy = [
        [0, 0, 0],  # substates of state Activate Button*
        [0, 0, 0],  # substates of state Default
        [0, 0, 0]  # substates of state Idle
    ]
    CommonStateTable = [[-1, -1, -1], [-1, -1, -1], [-1, -1, -1]]
    Description = None

    ##Lock=thread.allocate_lock()
    CurrentModel = None

    def __init__(self, Interpreter=None, Parent=None, OldInstance=None):

        # Variables
        self.Parent = Parent
        self.HistoryCount = 0
        self.state = None
        self.BackState = None
        if OldInstance != None:
            self.Submodels = OldInstance.Submodels
        else:
            self.Submodels = []
            for i in range(ButtonBehaviour_MDL.StateNum):
                self.Submodels.append(None)
        self.history = []
        for i in range(ButtonBehaviour_MDL.StateNum):
            self.history.append(None)

        # Constructor
        for i in range(ButtonBehaviour_MDL.StateNum):
            self.history[i] = History()
            self.history[i].States = []
            self.history[i].Times = []
            for j in range(ButtonBehaviour_MDL.StateNum):
                self.history[i].States.append(-1)
                self.history[i].Times.append(-1)

        self.TimedTransitions = []  # used only when --ext is set
        for i in range(ButtonBehaviour_MDL.StateNum):
            self.TimedTransitions.append(None)

        self.clearEnteredStates()
        self.HasInteractor = 0

        # Interpreter of action code
        if self.Parent == None:  # Top-level model
            if Interpreter:
                self.DefaultInterpreter = Interpreter
            else:
                self.DefaultInterpreter = InteractiveInterpreter()
            self.setupInterpreter()

            ##self.EventsCond=threading.Condition()
            ##self.SchedulerCond=threading.Condition()
            self.Schedules = []
            self.PendingEvents = None
            self.PendingEventsTail = None
        else:
            self.DefaultInterpreter = Interpreter
        self.Started = 0
        self.Stopped = 0

        self.description = ButtonBehaviour_MDL.Description

    # Methods
    def isParent(self, sp, sc):

        return sc >= 0 and (sp < 0 or ButtonBehaviour_MDL.Hierarchy[sp][sc])

    def isInState(self, s, check_substate=1, use_backup=1):

        if isinstance(s, int):
            if use_backup:
                st = self.BackState
            else:
                st = self.state
            while st != None:
                if st.StateID == s or (check_substate
                                       and self.isParent(s, st.StateID)):
                    return 1
                else:
                    st = st.Next
            return 0

        elif isinstance(s, str):
            i = 0
            while i < ButtonBehaviour_MDL.StateNum:
                if s == ButtonBehaviour_MDL.StateNames[i]:
                    return self.isInState(i, check_substate, use_backup)
                i = i + 1
            i = 0
            while i < ButtonBehaviour_MDL.StateNum:
                stname = ButtonBehaviour_MDL.StateNames[i]
                if self.Submodels[i] != None and startsWith(s, stname + "."):
                    pos = len(stname) + 1
                    SubmodelState = s[pos:]
                    return self.isInState(
                        i, 0, use_backup) and self.Submodels[i].isInState(
                            SubmodelState, check_substate, use_backup)
                i = i + 1
            return 0

        else:
            return 0

    class main_callable:
        def __call__(self, argv):
            model = ButtonBehaviour_MDL()
            cmd = ""
            model.initModel()
            if model.HasInteractor:
                model.runInteractor()
            else:
                ##cond=thread.allocate_lock()
                while cmd != "exit":
                    sys.__stdout__.write(model.getCurrentState() + " > ")
                    cmd = string.strip(sys.__stdin__.readline())
                    if cmd == "exit":
                        break
                    if not model.Stopped:
                        ##cond.acquire()
                        ##model.event(cmd, [], cond)
                        model.event(cmd, [])
                        ##cond.acquire()
                        ##cond.release()
            model.runFinalizer()

    main = main_callable()

    def initModel(self,
                  run_initializer=1,
                  run_enter_actions=1,
                  TkInstance=None):

        self.clearEnteredStates()
        if self.Parent == None and ButtonBehaviour_MDL.Description != None:
            sys.__stdout__.write(ButtonBehaviour_MDL.Description + "\n")
        self.addInState(1)  # init state "Default"
        self.recordEnteredState(1)
        if run_initializer:
            self.runInitializer()
        if not self.HasInteractor:
            self.start(None, run_enter_actions, TkInstance)

    def applyMask(self, mask, dest):

        i = 0
        while i < ButtonBehaviour_MDL.StateNum:
            dest[i] = dest[i] and mask[i]
            i = i + 1

    def handleEvent(self, se, params=[], cond=None, scheduler=None):

        if not self.Started:
            if cond:
                cond.release()
            return 0
        self.params = params
        handled = 0
        table = []
        i = 0
        while i < ButtonBehaviour_MDL.StateNum:
            table.append(1)
            i = i + 1
        if self.state:
            self.BackState = self.state.copy()
        else:
            self.BackState = None
        e = self.eventStr2Int(se)
        if e == 0:  # event "(create)*"
            if table[1] and self.isInState(1) and self.testCondition(0):
                if (scheduler == self or scheduler == None) and table[1]:
                    self.runActionCode(2)  # output action(s)
                    self.runExitActionsForStates(-1)
                    self.clearEnteredStates()
                    self.changeState(1, 2)
                    self.runEnterActionsForStates(self.StatesEntered, 1)
                    self.applyMask(ButtonBehaviour_MDL.OrthogonalTable[1],
                                   table)
                    handled = 1
        elif e == 1:  # event "<Any-ButtonRelease-1>"
            if table[2] and self.isInState(2) and self.testCondition(1):
                if (scheduler == self or scheduler == None) and table[2]:
                    self.runActionCode(3)  # output action(s)
                    self.runExitActionsForStates(-1)
                    self.clearEnteredStates()
                    self.changeState(2, 0)
                    self.runEnterActionsForStates(self.StatesEntered, 1)
                    self.applyMask(ButtonBehaviour_MDL.OrthogonalTable[2],
                                   table)
                    handled = 1
        elif e == 2:  # event "<ButtonPress-1>"
            if table[2] and self.isInState(2) and self.testCondition(2):
                if (scheduler == self or scheduler == None) and table[2]:
                    self.runActionCode(4)  # output action(s)
                    self.runExitActionsForStates(-1)
                    self.clearEnteredStates()
                    self.changeState(2, 2)
                    self.runEnterActionsForStates(self.StatesEntered, 1)
                    self.applyMask(ButtonBehaviour_MDL.OrthogonalTable[2],
                                   table)
                    handled = 1
        elif e == 3:  # event "[Done]"
            if table[0] and self.isInState(0) and self.testCondition(3):
                if (scheduler == self or scheduler == None) and table[0]:
                    self.runExitActionsForStates(-1)
                    self.clearEnteredStates()
                    self.changeState(0, 2)
                    self.runEnterActionsForStates(self.StatesEntered, 1)
                    self.applyMask(ButtonBehaviour_MDL.OrthogonalTable[0],
                                   table)
                    handled = 1
        if cond and self.Parent == None:  # Top-level model
            cond.release()
        if not handled and e >= 0 and (
                scheduler == self or scheduler
                == None) and ButtonBehaviour_MDL.RescheduleTable[e] >= 0:
            self.addSchedule(ButtonBehaviour_MDL.RescheduleTable[e],
                             ButtonBehaviour_MDL.IntervalTable[e],
                             ButtonBehaviour_MDL.EventNames[e], scheduler)
        return handled

    def forceIntoState(self, s):

        changed = 0
        s2 = self.state
        while s2 != None:
            HasCommonParent = 0
            for i in range(ButtonBehaviour_MDL.StateNum):
                if self.isParent(i, s2.StateID) and self.isParent(i, s):
                    HasCommonParent = 1
                    if not self.hasOrthogonalStateInBetween(i, s2.StateID):
                        self.changeState(s2.StateID, s)
                        changed = 1
            if not HasCommonParent:
                self.changeState(s2.StateID, s)
                changed = 1
            s2 = s2.Next
        if not changed:
            self.addInState(s)

    def changeState(self, s1, s2, check_history=0, top_level=0):

        # t1=common(s1, s2)
        t1 = ButtonBehaviour_MDL.CommonStateTable[s1][s2]
        self.recordHistory(t1)
        if t1 >= 0:
            self.removeOutStates(t1)
        else:
            self.state = None
        # t2=history(s2)
        t2 = ButtonBehaviour_MDL.HistoryStateTable[s2]
        if t2 == 0:  # no history
            self.generateStates(t1, s2)
        elif t2 == 1:  # normal history
            if not check_history:
                self.generateStates(t1, s2)
            elif self.hasHistoryRecorded(s2) and self.Submodels[s2] == None:
                self.generateStates(t1, self.history[s2].States[s2])
            else:
                self.generateStates(t1, s2, 1)
        elif t2 == 2:  # deep history
            if check_history and self.hasHistoryRecorded(s2):
                if self.Submodels[s2]:
                    self.recordEnteredState(s2, 1, 1, t1)
                    self.addInState(s2)
                else:
                    for i in range(ButtonBehaviour_MDL.StateNum):
                        hs = self.history[s2].States[i]
                        if hs >= 0 and self.isLeafState(hs):
                            self.recordEnteredState(hs, 1, 1, t1)
                            self.addInState(hs)
            else:
                self.generateStates(t1, s2)

    def addInState(self, s):

        if not self.isInState(s, 1, 0):
            st = State()
            st.StateID = s
            st.Next = self.state
            self.state = st
            return 1
        else:
            return 0

    def generateStates(self, common, dest, history_type=0):

        if common == -1:
            if dest == 0:
                if history_type != 2 or self.check_history(-1):
                    if history_type != 2 or self.check_history(0):
                        self.recordEnteredState(0)
                        self.addInState(
                            0)  # move into leaf state "Activate Button*"
            elif dest == 1:
                if history_type != 2 or self.check_history(-1):
                    if history_type != 2 or self.check_history(1):
                        self.recordEnteredState(1)
                        self.addInState(1)  # move into leaf state "Default"
            elif dest == 2:
                if history_type != 2 or self.check_history(-1):
                    if history_type != 2 or self.check_history(2):
                        self.recordEnteredState(2)
                        self.addInState(2)  # move into leaf state "Idle"
        elif common == 0:
            if dest == 0:
                if history_type != 2 or self.check_history(0):
                    self.addInState(
                        0)  # move into leaf state "Activate Button*"
        elif common == 1:
            if dest == 1:
                if history_type != 2 or self.check_history(1):
                    self.addInState(1)  # move into leaf state "Default"
        elif common == 2:
            if dest == 2:
                if history_type != 2 or self.check_history(2):
                    self.addInState(2)  # move into leaf state "Idle"

    def removeOutStates(self, common_state):

        s = self.state
        prev = None
        while s != None:
            if self.isParent(common_state, s.StateID):
                if prev == None:
                    self.state = self.state.Next
                else:
                    prev.Next = s.Next
            else:
                prev = s
            s = s.Next

    def eventStr2Int(self, event):

        for i in range(4):
            if event == ButtonBehaviour_MDL.EventNames[i]:
                return i
        return -1

    def stateInt2Str(self, state):

        if state == -1:
            return ""
        else:
            return ButtonBehaviour_MDL.StateNames[state]

    def getCurrentStateList(self):

        sl = StringList()
        slend = sl
        s = self.state
        while s != None:
            sm = self.Submodels[s.StateID]
            curstate = self.stateInt2Str(s.StateID)
            if sm != None:
                slend.Next = sm.getCurrentStateList()
                while slend.Next != None:
                    slend.Next.str = curstate + "." + slend.Next.str
                    slend = slend.Next
            else:
                slend.Next = StringList(curstate)
                slend = slend.Next
            s = s.Next
        return sl.Next

    def getCurrentState(self, states=None):

        if states == None:
            states = self.getCurrentStateList()
            if states != None:
                states = states.sort()
                strst = "['%s'%s]" % (states.str, self.getCurrentState(states))
            else:
                strst = "[]"
        else:
            if states.Next:
                strst = ", '%s'%s" % (states.Next.str,
                                      self.getCurrentState(states.Next))
            else:
                strst = ""
        return strst

    def getParentState(self, state):

        return ButtonBehaviour_MDL.ParentTable[state]

    def getSubstates(self, state):

        substates = None
        if state == -1:  # substates of ""
            # add substate "Activate Button*"
            st = IntList()
            st.int = 0
            st.Next = substates
            substates = st
            # add substate "Default"
            st = IntList()
            st.int = 1
            st.Next = substates
            substates = st
            # add substate "Idle"
            st = IntList()
            st.int = 2
            st.Next = substates
            substates = st
        elif state == 0:  # substates of "Activate Button*"
            pass
        elif state == 1:  # substates of "Default"
            pass
        elif state == 2:  # substates of "Idle"
            pass
        return substates

    def isHistoryState(self, state):

        return ButtonBehaviour_MDL.HistoryStateTable[state] > 0

    def isLeafState(self, state):

        if isinstance(state, int):
            return ButtonBehaviour_MDL.LeafStateTable[state] != None

        elif isinstance(state, str):
            for i in range(ButtonBehaviour_MDL.StateNum):
                if ButtonBehaviour_MDL.LeafStateTable[i] == None:
                    continue
                if state == ButtonBehaviour_MDL.LeafStateTable[
                        i] and self.Submodels[i] == None:
                    return 1
                elif startsWith(state, ButtonBehaviour_MDL.LeafStateTable[i] +
                                ".") and self.Submodels[i] != None:
                    SubmodelState = state[ButtonBehaviour_MDL.
                                          LeafStateTable[i].length() + 1:]
                    return self.Submodels[i].isLeafState(SubmodelState)
        return 0

    def isHistoryUp2Date(self, state, time):

        for i in range(ButtonBehaviour_MDL.StateNum):
            if self.history[state].Times[i] >= time:
                return 1
        return 0

    def mergeHistory(self, state, states, times):

        max = -1
        for i in range(ButtonBehaviour_MDL.StateNum):
            if times[i] > max:
                max = times[i]
        if self.isHistoryUp2Date(state, max):
            for i in range(ButtonBehaviour_MDL.StateNum):
                if times[i] > self.history[state].Times[i]:
                    self.history[state].States[i] = states[i]
                    self.history[state].Times[i] = times[i]
        else:
            self.history[state].States = copy.copy(states)
            self.history[state].Times = copy.copy(times)

    def recordHistory(self, top_state):

        curtime = self.HistoryCount
        self.HistoryCount = self.HistoryCount + 1
        s = self.state
        while s != None:
            child = s.StateID
            states = []
            times = []
            for i in range(ButtonBehaviour_MDL.StateNum):
                states.append(-1)
                times.append(-1)
            states[child] = child
            times[child] = curtime
            if top_state < 0 or self.isParent(top_state, child):
                parent = self.getParentState(child)
                if self.isHistoryState(child):
                    self.history[child].Submodel = self.Submodels[child]
                while parent >= 0 and times[parent] != curtime:
                    states[parent] = child
                    times[parent] = curtime
                    if self.isHistoryState(parent):
                        self.mergeHistory(parent, states, times)
                    if parent == top_state:
                        break
                    child = parent
                    parent = self.getParentState(child)
            s = s.Next

    def hasHistoryRecorded(self, state):

        for i in range(ButtonBehaviour_MDL.StateNum):
            if self.history[state].States[i] != -1:
                return 1
            if self.Submodels[state] != None:
                return 1
        return 0

    def hasOrthogonalStateInBetween(self, parent, leaf):

        return ButtonBehaviour_MDL.OrthogonalInBetween[parent + 1][leaf]

    def check_history(self, dest):

        s = self.state
        while s != None:
            if self.isParent(
                    dest, s.StateID) and not self.hasOrthogonalStateInBetween(
                        dest, s.StateID):
                return 0
            s = s.Next
        return 1

    def getEnabledEvents(self):

        events = EventList()
        if self.isInState(1):
            events.Append("(create)*")
        if self.isInState(2):
            events.Append("<Any-ButtonRelease-1>")
        if self.isInState(2):
            events.Append("<ButtonPress-1>")
        if self.isInState(0):
            events.Append("[Done]")
        return events.Next

    def getHierarchy(self, start_level, state_prefix):

        h = Hierarchy()
        lasth = h
        # Generate state "Activate Button*" in the hierarchy table
        lasth.Next = Hierarchy()
        lasth.Next.StateName = "Activate Button*"
        if state_prefix == None:
            lasth.Next.PathName = "Activate Button*"
        else:
            lasth.Next.PathName = state_prefix + ".Activate Button*"
        lasth.Next.StateNum = 0
        lasth.Next.Level = start_level + 0
        lasth = lasth.Next
        # Generate state "Default" in the hierarchy table
        lasth.Next = Hierarchy()
        lasth.Next.StateName = "Default"
        if state_prefix == None:
            lasth.Next.PathName = "Default"
        else:
            lasth.Next.PathName = state_prefix + ".Default"
        lasth.Next.StateNum = 1
        lasth.Next.Level = start_level + 0
        lasth = lasth.Next
        # Generate state "Idle" in the hierarchy table
        lasth.Next = Hierarchy()
        lasth.Next.StateName = "Idle"
        if state_prefix == None:
            lasth.Next.PathName = "Idle"
        else:
            lasth.Next.PathName = state_prefix + ".Idle"
        lasth.Next.StateNum = 2
        lasth.Next.Level = start_level + 0
        lasth = lasth.Next
        return h.Next

    def topLevelHistory(self):

        s = self.state.StateID
        t = self.getParentState(s)
        while t != -1:
            s = t
            t = self.getParentState(s)
        self.changeState(s, s)

    def runActionCode(self, code_num):

        if code_num == 0:  # model finalizer
            pass
        elif code_num == 1:  # model initializer
            pass
        elif code_num == 2:  # output action(s) of a transition
            self.runCode("self = eventhandler.get_event_params()")
            self.runCode("atom3i = self.parent")
            self.runCode("cb = atom3i.cb")
        elif code_num == 3:  # output action(s) of a transition
            self.runCode("event = eventhandler.get_event_params()")
            self.runCode("event._isHandled = True")
        elif code_num == 4:  # output action(s) of a transition
            self.runCode("event = eventhandler.get_event_params()")
            self.runCode("event._isHandled = True")
        elif code_num == 5:  # enter actions for state "Activate Button*"
            self.runCode("event = eventhandler.get_event_params()")
            self.runCode("from FSB_Code.Constructor import buttonActivation")
            self.runCode("buttonActivation(self)")
            self.runCode("eventhandler.event(\'[Done]\')")

    def testCondition(self, cond_num):

        if cond_num==0 and \
           eval("(1)", self.DefaultInterpreter.locals):
            return 1
        elif cond_num==1 and \
           eval("(1)", self.DefaultInterpreter.locals):
            return 1
        elif cond_num==2 and \
           eval("(1)", self.DefaultInterpreter.locals):
            return 1
        elif cond_num==3 and \
           eval("(1)", self.DefaultInterpreter.locals):
            return 1
        return 0

    def runEnterActions(self, state):

        if state == 0:  # enter action(s) for state "Activate Button*"
            self.runActionCode(5)

    def runExitActions(self, state):

        pass

    def compareSchedule(self, sched_a, sched_b):

        return cmp(sched_a[1], sched_b[1])

    def addSchedule(self, id, interval, event, scheduler):

        if self.Parent != None:  # Non-top-level model
            self.Parent.addSchedule(id, interval, event, scheduler)
            return
        f = eval(interval, self.DefaultInterpreter.locals)
        ##self.SchedulerCond.acquire()
        t = time.time() + f
        s = [id, t, interval, event, scheduler]
        self.Schedules.append(s)
        self.Schedules.sort(self.compareSchedule)
        ##self.SchedulerCond.notify()
        ##self.SchedulerCond.release()

    def removeSchedule(self, id, scheduler):

        if self.Parent != None:  # Non-top-level model
            self.Parent.removeSchedule(id, scheduler)
            return
        ##self.SchedulerCond.acquire()
        i = 0
        while i < len(self.Schedules):
            if self.Schedules[i][0] == id and self.Schedules[i][4] == scheduler:
                del self.Schedules[i]
            else:
                i = i + 1
        ##self.SchedulerCond.release()

    def scheduler(self):

        if (not self.Schedules): return

        while (self.Schedules and self.Schedules[0][1] <= time.time()):
            this_sched = self.Schedules[0]
            del self.Schedules[0]
            self.event(this_sched[3], [], None, this_sched[4])

        if self.Schedules:
            t = self.Schedules[0][1] - time.time()

    def recordAllEnteredStates(self):

        st = self.state
        while st != None:
            self.recordEnteredState(st.StateID, 1, 1)
            st = st.Next

    def recordEnteredState(self, s, superstates=0, submodel=0, commonstate=-1):

        # test if s is already recorded
        se = self.StatesEntered
        found = 0
        while se != None:
            if se.int == s:
                found = 1
                break
            se = se.Next

        if not found:
            if superstates:
                parent = self.getParentState(s)
                if parent >= 0 and parent != commonstate:
                    self.recordEnteredState(parent, 1, 0, commonstate)
            st = IntList()
            st.Next = self.StatesEntered
            st.int = s
            self.StatesEntered = st
            if submodel and self.Submodels[s]:
                self.Submodels[s].recordAllEnteredStates()

    def runAllEnterActions(self):

        self.runEnterActionsForStates(self.StatesEntered, 1)

    def runEnterActionsForStates(self, states, recursive=0):

        if states:
            self.runEnterActionsForStates(states.Next, 0)
            self.runEnterActions(states.int)
        if recursive:
            for s in self.Submodels:
                if s:
                    s.runAllEnterActions()

    def runExitActionsForStates(self, common_state):

        substates = self.getSubstates(common_state)
        if substates == None:
            s = self.state
            while s != None and s.StateID != common_state:
                s = s.Next
            if s != None and self.Submodels[s.StateID]:
                self.Submodels[s.StateID].runExitActionsForStates(-1)
            return s != None
        else:
            has_current_substate = 0
            while substates != None:
                res = self.runExitActionsForStates(substates.int)
                has_current_substate = has_current_substate or res
                if res:
                    self.runExitActions(substates.int)
                substates = substates.Next
            return has_current_substate

    def runInitializer(self):

        self.runActionCode(1)
        for s in self.Submodels:
            if s:
                s.runInitializer()

    def runFinalizer(self):

        if self.Started:
            self.Started = 0
            for s in self.Submodels:
                if s:
                    s.runFinalizer()
            self.runActionCode(0)
            if self.Parent == None:  # Top-level model
                ##self.EventsCond.acquire()
                ##self.SchedulerCond.acquire()
                self.Stopped = 1
                ##self.EventsCond.notify()
                ##self.SchedulerCond.notify()
                ##self.SchedulerCond.release()
                ##self.EventsCond.release()
            else:
                self.Stopped = 1

    def clearEnteredStates(self):

        self.StatesEntered = None
        for s in self.Submodels:
            if s:
                s.clearEnteredStates()

    def get_current_state(self):

        return self.getCurrentState()

    def runCode(self, c):

        self.DefaultInterpreter.runsource(c + "\n", "<input>", "exec")

    def setupInterpreter(self):

        self.DefaultInterpreter.locals["eventhandler"] = self
        self.DefaultInterpreter.locals["dump_message"] = self.dump_message

    def get_event_params(self):

        return self.params

    def dump_message(self, msg):

        print msg

    def is_in_state(self, s, check_substate=1):

        return self.isInState(s, check_substate)

    def start(self, lock=None, run_enter_actions=1, TkInstance=None):

        if self.Parent == None:  # Top-level model
            if run_enter_actions:
                self.runEnterActionsForStates(self.StatesEntered, 1)
            self.Started = 1

            if (TkInstance):
                self.sleepMethod = TkInstance.after
                startTkMainloop = False
            else:
                import Tkinter
                TkInstance = Tkinter.Tk()
                self.sleepMethod = TkInstance.after
                startTkMainloop = True

            self.pollingStation()
            ##thread.start_new_thread(self.handleEvent_wrapper, ())
            ##thread.start_new_thread(self.scheduler, ())
            ## if lock:
            ## lock.release()
        else:
            self.Started = 1
        for submodel in self.Submodels:
            if submodel != None:
                submodel.start()

        if (self.Parent == None and startTkMainloop == None):
            TkInstance.mainloop()

    def pollingStation(self):

        self.sleepMethod(100, self.pollingStation)
        if self.Stopped: return
        #self.handleEvent_wrapper()
        self.scheduler()
        #todo: pollingStation\,
    def shutdown(self):

        pass

    def handleEvent_wrapper(self):

        if (self.PendingEvents == None): return
        event = self.PendingEvents
        self.PendingEvents = self.PendingEvents.Next
        if self.PendingEvents == None:
            self.PendingEventsTail = None
        event.next = None
        self.handleEvent(event.Event[0], event.Event[1], event.Event[2],
                         event.Event[3])
        self.handleEvent_wrapper()

    def event(self, e, params=[], cond=None, scheduler=None):

        ev = EventList()
        ev.Event = [e, params, cond, scheduler]
        if self.PendingEventsTail != None:
            self.PendingEventsTail.Next = ev
        else:
            self.PendingEvents = ev
        self.PendingEventsTail = ev
        self.handleEvent_wrapper()
Esempio n. 34
0
    statinfo = os.stat(PyAnswers)
    if not stat.S_ISFIFO(statinfo.st_mode):
        os.unlink(PyAnswers)
        os.mkfifo(PyAnswers)
    
    try:
        OUTPUT = open(PyAnswers, 'w')
    except IOError:
        print "Can't open " + PyAnswers
    else:
        # for simplicity, we redirect 
        # anything the script outputs
        sError = sys.stderr
        sOutput = sys.stdout
        sys.stderr = OUTPUT
        sys.stdout = OUTPUT
    
    # execute command line(s)
    if PyShell.runsource(str(commandLine)) :
        # the command is not complete
        print "... "
        commandLine += "\n"
    else:
        # the command was complete
        print ">>> "
        commandLine = ''

    OUTPUT.close()
    # restore the streams
    sys.stdout, sys.stderr = sOutput, sError
Esempio n. 35
0
 def runsource(self, source):
     # Extend base class to stuff the source in the line cache first
     filename = self.stuffsource(source)
     self.more = 0
     return InteractiveInterpreter.runsource(self, source, filename)
Esempio n. 36
0
class PyCute(QMultiLineEdit):

    """
    PyCute is a Python shell for PyQt.

    Creating, displaying and controlling PyQt widgets from the Python command
    line interpreter is very hard, if not, impossible.  PyCute solves this
    problem by interfacing the Python interpreter to a PyQt widget.

    My use is interpreter driven plotting to QwtPlot instances. Why?

    Other popular scientific software packages like SciPy, SciLab, Octave,
    Maple, Mathematica, GnuPlot, ..., also have interpreter driven plotting.
    It is well adapted to quick & dirty exploration.

    Of course, PyQt's debugger -- eric -- gives you similar facilities, but
    PyCute is smaller and easier to integrate in applications.
    Eric requires Qt-3.x

    PyCute is based on ideas and code from:
    - Python*/Tools/idle/PyShell.py (Python Software Foundation License)
    - PyQt*/eric/Shell.py (Gnu Public License)
    """

    def __init__(self, locals=None, log='', parent=None):
        """Constructor.

        The optional 'locals' argument specifies the dictionary in
        which code will be executed; it defaults to a newly created
        dictionary with key "__name__" set to "__console__" and key
        "__doc__" set to None.

        The optional 'log' argument specifies the file in which the
        interpreter session is to be logged.

        The optional 'parent' argument specifies the parent widget.
        If no parent widget has been specified, it is possible to
        exit the interpreter by Ctrl-D.
        """

        QMultiLineEdit.__init__(self, parent)
        self.interpreter = Interpreter(locals)

        # session log
        self.log = log or ''
        
        # to exit the main interpreter by a Ctrl-D if PyCute has no parent
        if parent is None:
            self.eofKey = Qt.Key_D
        else:
            self.eofKey = None

        # capture all interactive input/output 
        sys.stdout   = self
        sys.stderr   = self
        sys.stdin    = self
        # last line + last incomplete lines
        self.line    = QString()
        self.lines   = []
        # the cursor position in the last line
        self.point   = 0
        # flag: the interpreter needs more input to run the last lines. 
        self.more    = 0
        # flag: readline() is being used for e.g. raw_input() and input()
        self.reading = 0
        # history
        self.history = []
        self.pointer = 0
        self.xLast   = 0
        self.yLast   = 0

        # user interface setup
        # no word wrapping simplifies cursor <-> numLines() mapping
        self.setWordWrap(QMultiLineEdit.NoWrap)
        self.setCaption('PyCute -- a Python Shell for PyQt --'
                        'http://gerard.vermeulen.free.fr')
        # font
        if os.name == 'posix':
            font = QFont("Fixed", 12)
        elif os.name == 'nt' or os.name == 'dos':
            font = QFont("Courier New", 8)
        else:
            raise SystemExit, "FIXME for 'os2', 'mac', 'ce' or 'riscos'"
        font.setFixedPitch(1)
        self.setFont(font)

        # geometry
        height = 40*QFontMetrics(font).lineSpacing()
        request = QSize(600, height)
        if parent is not None:
            request = request.boundedTo(parent.size())
        self.resize(request)

        # interpreter prompt.
        try:
            sys.ps1
        except AttributeError:
            sys.ps1 = ">>> "
        try:
            sys.ps2
        except AttributeError:
            sys.ps2 = "... "

        # interpreter banner
        self.write('The PyCute shell running Python %s on %s.\n' %
                   (sys.version, sys.platform))
        self.write('Type "copyright", "credits" or "license"'
                   ' for more information on Python.\n')
        self.write(sys.ps1)
        
    def flush(self):
        """
        Simulate stdin, stdout, and stderr.
        """
        pass

    def isatty(self):
        """
        Simulate stdin, stdout, and stderr.
        """
        return 1

    def readline(self):
        """
        Simulate stdin, stdout, and stderr.
        """
        self.reading = 1
        self.__clearLine()
        self.__moveCursorToEnd()
        while self.reading:
            qApp.processOneEvent()
        if self.line.length() == 0:
            return '\n'
        else:
            return str(self.line) 
    
    def write(self, text):
        """
        Simulate stdin, stdout, and stderr.
        """
        # The output of self.append(text) contains to many newline characters,
        # so work around QTextEdit's policy for handling newline characters.
        hack = self.text()
        hack.append(text)
        self.setText(hack)
        #self.setText(self.text().append(text)) # segmentation fault
        self.yLast, self.xLast = self.__moveCursorToEnd()

    def writelines(self, text):
        """
        Simulate stdin, stdout, and stderr.
        """
        map(self.write, text)
        print "DO WE EVER GET HERE? IF YES, OPTIMIZATION POSSIBLE"

    def fakeUser(self, lines):
        """
        Simulate a user: lines is a sequence of strings (Python statements).
        """
        for line in lines:
            self.line = QString(line.rstrip())
            self.write(self.line)
            self.write('\n')
            self.__run()
            
    def __run(self):
        """
        Append the last line to the history list, let the interpreter execute
        the last line(s), and clean up accounting for the interpreter results:
        (1) the interpreter succeeds
        (2) the interpreter fails, finds no errors and wants more line(s)
        (3) the interpreter fails, finds errors and writes them to sys.stderr
        """
        self.pointer = 0
        self.history.append(QString(self.line))
        self.lines.append(str(self.line))
        source = '\n'.join(self.lines)
        self.more = self.interpreter.runsource(source)
        if self.more:
            self.write(sys.ps2)
        else:
            self.write(sys.ps1)
            self.lines = []
        self.__clearLine()
        
    def __clearLine(self):
        """
        Clear input line buffer
        """
        self.line.truncate(0)
        self.point = 0
        
    def __insertText(self, text):
        """
        Insert text at the current cursor position.
        """
        y, x = self.getCursorPosition()
        self.insertAt(text, y, x)
        self.line.insert(self.point, text)
        self.point += text.length()
        self.setCursorPosition(y, x + text.length())

    def __moveCursorToEnd(self):
        y = self.numLines()-1
        x = self.lineLength(y)
        self.setCursorPosition(y, x)
        return y, x

    def keyPressEvent(self, e):
        """
        Handle user input a key at a time.
        """
        text  = e.text()
        key   = e.key()
        ascii = e.ascii()

        if text.length() and ascii>=32 and ascii<127:
            self.__insertText(text)
            return

        if e.state() & Qt.ControlButton and key == self.eofKey:
            try:
                file = open(self.log, "w")
                file.write(str(self.text()))
                file.close()
            except:
                pass
            sys.exit()
            return
        
        if e.state() & Qt.ControlButton or e.state() & Qt.ShiftButton:
            e.ignore()
            return

        if key == Qt.Key_Backspace:
            if self.point:
                self.backspace()
                self.point -= 1
                self.line.remove(self.point, 1)
        elif key == Qt.Key_Delete:
            self.delChar()
            self.line.remove(self.point, 1)
        elif key == Qt.Key_Return or key == Qt.Key_Enter:
            self.write('\n')
            if self.reading:
                self.reading = 0
            else:
                self.__run()
        elif key == Qt.Key_Tab:
            self.__insertText(text)
        elif key == Qt.Key_Left:
            if self.point:
                self.cursorLeft()
                self.point -= 1
        elif key == Qt.Key_Right:
            if self.point < self.line.length():
                self.cursorRight()
                self.point += 1
        elif key == Qt.Key_Home:
            self.setCursorPosition(self.yLast, self.xLast)
            self.point = 0
        elif key == Qt.Key_End:
            self.end()
            self.point = self.line.length()
        elif key == Qt.Key_Up:
            if len(self.history):
                if self.pointer == 0:
                    self.pointer = len(self.history)
                self.pointer -= 1
                self.__recall()
        elif key == Qt.Key_Down:
            if len(self.history):
                self.pointer += 1
                if self.pointer == len(self.history):
                    self.pointer = 0
                self.__recall()
        else:
            e.ignore()

    def __recall(self):
        """
        Display the current item from the command history.
        """
        self.setCursorPosition(self.yLast, self.xLast)
        self.killLine()     # QMultiLineEdit
        self.__clearLine()  # self.line
        self.__insertText(self.history[self.pointer])

        
    def focusNextPrevChild(self, next):
        """
        Suppress tabbing to the next window in multi-line commands. 
        """
        if next and self.more:
            return 0
        return QMultiLineEdit.focusNextPrevChild(self, next)

    def mousePressEvent(self, e):
        """
        Keep the cursor after the last prompt.
        """
        if e.button() == Qt.LeftButton:
            self.__moveCursorToEnd()
        return

    def contentsContextMenuEvent(self,ev):
        """
        Suppress the right button context menu.
        """
        return
Esempio n. 37
0
 def runStartupCommands(self, locals):
     interp = InteractiveInterpreter(locals)
     """Execute the startup commands that import default modules"""
     interp.runsource("import os")
     interp.runsource("import sys")
     interp.runsource("import wx")
     interp.runsource("import vtk")
     interp.runsource("import numpy")
     interp.runsource("np = numpy")
     interp.runsource("import coda")
     interp.runsource("import harp")
     interp.runsource("import visan")
     interp.runsource("import visan.math")
     interp.runsource("from visan.commands import *")
     self.version = interp.locals['visan'].VERSION
     self.component_versions = [
         "Python %d.%d.%d" %
         (sys.version_info[0], sys.version_info[1], sys.version_info[2]),
         "wxPython %s" % interp.locals['wx'].VERSION_STRING,
         "VTK %s" % interp.locals['vtk'].VTK_VERSION,
         "NumPy %s" % interp.locals['numpy'].__version__,
         "CODA %s" % interp.locals['coda'].version(),
         "HARP %s" % interp.locals['harp'].version(),
     ]
Esempio n. 38
0
class QPyShell(QWidget):
    """QPyShell - a Qt based python command shell based on code.InteractiveInterpreter.
    Because it catches stdout and stderr there can be only one active instance of this
    class. Make sure initInterpreter() and exitInterpreter() is called!
    """

    activeInstance = None

    def __init__(self, parent=None):
        QWidget.__init__(self, parent)
        if parent:
            self.standalone = False
        else:
            self.standalone = True

        self.setWindowTitle(QCoreApplication.translate("QPyShell", "QPyShell - a simple python shell widget for Qt"))

        self.mainLayout = QVBoxLayout(self)

        self.outputBrowser = QTextEdit(self)
        self.outputBrowser.setMinimumSize(QSize(100,100))
        self.outputBrowser.setReadOnly(True)
        self.mainLayout.addWidget(self.outputBrowser)

        self.clLayout = QHBoxLayout()
        self.mainLayout.addLayout(self.clLayout)

        self.promptLabel = QLabel()
        self.promptLabel.setText(">>>")
        self.clLayout.addWidget(self.promptLabel)

        self.lineInput = QLineEdit()
        self.lineInput.setToolTip(QCoreApplication.translate('QPyShell', 'The python commandline: enter code her'))
        self.clLayout.addWidget(self.lineInput)

        self.enterButton = QToolButton(self)
        self.enterButton.setText(QCoreApplication.translate("QPyShell", "Enter"))
        self.enterButton.setToolTip(QCoreApplication.translate('QPyShell', 'This button or [Enter] executes the command'))
        self.enterButton.setIcon(QIcon(QPixmap(enterXPM)))
        self.clLayout.addWidget(self.enterButton)

        self.clLayout.addSpacing(8)

        self.clearButton = QToolButton(self)
        self.clearButton.setText(QCoreApplication.translate("QPyShell", "Clear"))
        self.clearButton.setToolTip(QCoreApplication.translate('QPyShell', 'Clear the output window'))
        self.clearButton.setIcon(QIcon(QPixmap(clearXPM)))
        self.clLayout.addWidget(self.clearButton)

        self.saveButton = QToolButton(self)
        self.saveButton.setText(QCoreApplication.translate("QPyShell", "Save ..."))
        self.saveButton.setToolTip(QCoreApplication.translate('QPyShell', 'Save the contents of the output window'))
        self.saveButton.setIcon(QIcon(QPixmap(saveXPM)))
        self.clLayout.addWidget(self.saveButton)

        self.printButton = QToolButton(self)
        self.printButton.setText(QCoreApplication.translate("QPyShell", "Print"))
        self.printButton.setToolTip(QCoreApplication.translate('QPyShell', 'Print the contents of the output window'))
        self.printButton.setIcon(QIcon(QPixmap(printXPM)))
        self.clLayout.addWidget(self.printButton)

        self.history = []
        self.historyFile = None
        self.history_i = -1
        self.cmdBuffer = []
        self.showCompletionLimit = 100
        self.interpreter = None
        self.old_displayhook = None
        self.cursor = QTextCursor(self.outputBrowser.document())
        self.outputBrowser.setTextCursor(self.cursor)
        self.outputBrowser.append(greeting)

        self.setTabOrder(self.lineInput, self.outputBrowser)
        self.setTabOrder(self.outputBrowser, self.enterButton)
        self.setTabOrder(self.enterButton, self.saveButton)
        self.setTabOrder(self.saveButton, self.clearButton)

        self.connect(self.enterButton, SIGNAL("pressed()"), self.run)
        self.connect(self.saveButton, SIGNAL("pressed()"), self.saveContents)
        self.connect(self.printButton, SIGNAL("pressed()"), self.printContents)
        self.connect(self.clearButton, SIGNAL("pressed()"), self.outputBrowser.clear)


    def initInterpreter(self, loc=None, greet=greeting, historyFile=None):
        if QPyShell.activeInstance:
            raise Exception(QCoreApplication.translate("QPyShell", "QPyShell: There can be only one highlander... sorry, I mean one active QPyShell widget!"))
        QPyShell.activeInstance = self
        self.loadHistoryFile(historyFile)
        self.interpreter = InteractiveInterpreter(loc)
        self.completer = Completer(loc)
        self.old_stdout = sys.stdout
        self.old_stderr = sys.stderr
        sys.stdout = DummyFileW(self.write)
        sys.stderr = sys.stdout
        # there's a strange problem with gettext and interactive interpreters
        # gettext's "_"" will be overwritten by the standard sys.displayhook...
        self.old_displayhook = sys.displayhook
        sys.displayhook = mydisplayhook


    def loadHistoryFile(self, historyFile):
        self.historyFile = historyFile
        if historyFile and os.path.exists(historyFile):
            lines = open(historyFile, 'r').read().split(os.linesep)
            self.history = [l for l in lines if not l.startswith('#')]


    def saveHistoryFile(self):
        if self.historyFile:
            h = self.history
            if len(h) > 100:
                h = h[:100]
            h.insert(0, unicode(QCoreApplication.translate('QPyShell', '# this is the command history of the QPyShell')))
            open(self.historyFile, 'w').write(os.linesep.join(h))


    def exitInterpreter(self, loc=None):
        sys.stdout = self.old_stdout
        sys.stderr = self.old_stderr
        self.saveHistoryFile()
        del self.interpreter
        self.interpreter = None
        sys.displayhook = self.old_displayhook
        QPyShell.ativeInstance = None


    def run(self):
        if not self.interpreter:
            raise Exception(QCoreApplication.translate("QPyShell", "No interpreter found! You need to call QPyShell.initInterpreter() first!"))
        line = unicode(self.lineInput.text())
        self.lineInput.clear()
        if line:
            if (not self.history) or line != self.history[0]:
                # no consecutive identical entries
                self.history.insert(0, line)
            self.history_i = -1
            self.cursor.movePosition(QTextCursor.End)
            if not self.cmdBuffer:
                self.cursor.insertHtml('<br><b>|&gt;&gt;&gt;&nbsp;%s</b><br>' % formatPyLine(line))
            else:
                self.cursor.insertHtml('<br><b>|.&nbsp;.&nbsp;.&nbsp;&nbsp;%s</b><br>' % formatPyLine(line))
            self.cursor.movePosition(QTextCursor.End)
            self.outputBrowser.ensureCursorVisible()
        self.cmdBuffer.append(line)
        more = self.interpreter.runsource('\n'.join(self.cmdBuffer))
        if more:
            self.promptLabel.setText('...')
        else:
            self.cmdBuffer = []
            self.promptLabel.setText('>>>')


    def appendHtml(self, txt):
        self.cursor.movePosition(QTextCursor.End)
        self.cursor.insertHtml(txt)
        self.cursor.movePosition(QTextCursor.End)
        self.outputBrowser.ensureCursorVisible()


    def appendText(self, txt):
        self.cursor.movePosition(QTextCursor.End)
        self.outputBrowser.insertPlainText(txt)
        self.cursor.movePosition(QTextCursor.End)
        self.outputBrowser.ensureCursorVisible()


    write = appendText


    def keyPressEvent(self, event):
        key = event.key()
        mod = event.modifiers()
        if key == Qt.Key_Up and self.history:
            self.history_i = min(self.history_i+1, len(self.history)-1)
            self.lineInput.setText(self.history[self.history_i])
        elif key == Qt.Key_Down and self.history:
            self.history_i = max(self.history_i-1, -1)
            if self.history_i >= 0:
                self.lineInput.setText(self.history[self.history_i])
            else:
                self.lineInput.setText('')
        elif key == Qt.Key_Enter or key == Qt.Key_Return:
            if mod & Qt.ShiftModifier:
                self.complete()
            else:
                self.run()
        elif key == Qt.Key_Escape:
            txt, r = QInputDialog.getItem(self, QCoreApplication.translate("QPyShell", "Command line history"),
                QCoreApplication.translate("QPyShell", "Please select a history item:"),
                self.history, 0, False)
            if r and txt:
                self.lineInput.setText(txt)
        elif self.standalone and key == Qt.Key_Print:
            self.printContents()
        elif self.standalone and key == Qt.Key_Q and (mod & Qt.ControlModifier):
            self.close()
        else:
            QWidget.keyPressEvent(self, event)


    def closeEvent(self, event):
        if self.standalone:
            self.exitInterpreter()
        QWidget.closeEvent(self, event)


    def printContents(self, printer=None):
        if not printer:
            printer = QPrinter()
        dialog = QPrintDialog(printer, self)
        dialog.setWindowTitle(QCoreApplication.translate("QPyShell", "Print Document"))
        if dialog.exec_() != QDialog.Accepted:
            return
        self.outputBrowser.document().print_(printer)


    def saveContents(self, fileName=None):
        if not fileName:
            fileTypes = {'Text':('txt',), 'HTML':('htm', 'html')}
            filters = ';;'.join(['%s (%s)' % (k, ' '.join(['*.'+e for e in v])) for k, v in fileTypes.items()])
            dlg = QFileDialog(self,
                QCoreApplication.translate('QPyShell', 'Select name of file to save'),
                os.getcwd(), filters)
            dlg.setFileMode(QFileDialog.AnyFile)
            dlg.setAcceptMode(QFileDialog.AcceptSave)
            if dlg.exec_() != QDialog.Accepted:
                return
            tmp = unicode(dlg.selectedFilter())
            fileType = tmp[:tmp.find('(')-1]
            dlg.setDefaultSuffix(fileTypes[fileType][0])
            files = dlg.selectedFiles()
            if not files:
                return
            fileName = unicode(files[0])
        if fileType == 'Text':
            txt = self.outputBrowser.toPlainText()
        elif fileType == 'HTML':
            txt = self.outputBrowser.toHtml()
        else:
            raise IOError('Unknown FileType: %s' % fileType)
        try:
            open(fileName, 'w').write(txt)
        except IOError:
            QMessageBox.critical(self,
                QCoreApplication.translate('QPyShell', 'Could not save file!'),
                QCoreApplication.translate('QPyShell', 'Writing failed! Make sure you have write permissions!'))


    def complete(self):
        """ a very simple, quick and dirty completion of identifiers in the namespace """
        # FIXME: fertig machen!
        txt = unicode(self.lineInput.text())
        cur = self.lineInput.cursorPosition()
        s = cur
        while s>0 and txt[s-1] in identChars:
            s -= 1
        try:
            completions = self.completer.matches(txt[s:cur])
        except:
            return
        if not completions:
            return
        n_comp = len(completions)
        if n_comp == 1:
            comp = completions.pop()
            self.lineInput.insert(comp[cur-s:])
        elif n_comp < self.showCompletionLimit:
            tmp = list(completions)
            tmp.sort()
            self.appendHtml('<font color="#0000ff">[%s]</font>' % ', '.join(tmp))
            # get common prefix ... stolen from the python cookbook
            pref = tmp[0][:([min([x[0]==elem for elem in x]) for x in zip(*tmp)]+[0]).index(0)]
            if len(pref) > (cur-s):
                self.lineInput.insert(pref[cur-s:])
        else:
            self.appendHtml(unicode(QCoreApplication.translate("QPyShell",
                '<font color="#0000ff">[Too many completions: %d]</font>')) % n_comp)
Esempio n. 39
0
class Module(MgrModule):
    """
    This module is for testing the ceph-mgr python interface from within
    a running ceph-mgr daemon.

    It implements a sychronous self-test command for calling the functions
    in the MgrModule interface one by one, and a background "workload"
    command for causing the module to perform some thrashing-type
    activities in its serve() thread.
    """

    # The test code in qa/ relies on these options existing -- they
    # are of course not really used for anything in the module
    MODULE_OPTIONS = [
        Option(name='testkey'),
        Option(name='testlkey'),
        Option(name='testnewline'),
        Option(name='roption1'),
        Option(name='roption2',
               type='str',
               default='xyz'),
        Option(name='rwoption1'),
        Option(name='rwoption2',
               type='int'),
        Option(name='rwoption3',
               type='float'),
        Option(name='rwoption4',
               type='str'),
        Option(name='rwoption5',
               type='bool'),
        Option(name='rwoption6',
               type='bool',
               default=True),
        Option(name='rwoption7',
               type='int',
               min=1,
               max=42),
    ]

    def __init__(self, *args: Any, **kwargs: Any) -> None:
        super(Module, self).__init__(*args, **kwargs)
        self._event = threading.Event()
        self._workload: Optional[Workload] = None
        self._health: Dict[str, Dict[str, Any]] = {}
        self._repl = InteractiveInterpreter(dict(mgr=self))

    @CLICommand('mgr self-test python-version', perm='r')
    def python_version(self) -> Tuple[int, str, str]:
        '''
        Query the version of the embedded Python runtime
        '''
        major = sys.version_info.major
        minor = sys.version_info.minor
        micro = sys.version_info.micro
        return 0, f'{major}.{minor}.{micro}', ''

    @CLICommand('mgr self-test run')
    def run(self) -> Tuple[int, str, str]:
        '''
        Run mgr python interface tests
        '''
        self._self_test()
        return 0, '', 'Self-test succeeded'

    @CLICommand('mgr self-test background start')
    def backgroun_start(self, workload: Workload) -> Tuple[int, str, str]:
        '''
        Activate a background workload (one of command_spam, throw_exception)
        '''
        self._workload = workload
        self._event.set()
        return 0, '', 'Running `{0}` in background'.format(self._workload)

    @CLICommand('mgr self-test background stop')
    def background_stop(self) -> Tuple[int, str, str]:
        '''
        Stop background workload if any is running
        '''
        if self._workload:
            was_running = self._workload
            self._workload = None
            self._event.set()
            return 0, '', 'Stopping background workload `{0}`'.format(
                was_running)
        else:
            return 0, '', 'No background workload was running'

    @CLICommand('mgr self-test config get')
    def config_get(self, key: str) -> Tuple[int, str, str]:
        '''
        Peek at a configuration value
        '''
        return 0, str(self.get_module_option(key)), ''

    @CLICommand('mgr self-test config get_localized')
    def config_get_localized(self, key: str) -> Tuple[int, str, str]:
        '''
        Peek at a configuration value (localized variant)
        '''
        return 0, str(self.get_localized_module_option(key)), ''

    @CLICommand('mgr self-test remote')
    def test_remote(self) -> Tuple[int, str, str]:
        '''
        Test inter-module calls
        '''
        self._test_remote_calls()
        return 0, '', 'Successfully called'

    @CLICommand('mgr self-test module')
    def module(self, module: str) -> Tuple[int, str, str]:
        '''
        Run another module's self_test() method
        '''
        try:
            r = self.remote(module, "self_test")
        except RuntimeError as e:
            return -1, '', "Test failed: {0}".format(e)
        else:
            return 0, str(r), "Self-test OK"

    @CLICommand('mgr self-test cluster-log')
    def do_cluster_log(self,
                       channel: str,
                       priority: str,
                       message: str) -> Tuple[int, str, str]:
        '''
        Create an audit log record.
        '''
        priority_map = {
            'info': self.ClusterLogPrio.INFO,
            'security': self.ClusterLogPrio.SEC,
            'warning': self.ClusterLogPrio.WARN,
            'error': self.ClusterLogPrio.ERROR
        }
        self.cluster_log(channel,
                         priority_map[priority],
                         message)
        return 0, '', 'Successfully called'

    @CLICommand('mgr self-test health set')
    def health_set(self, checks: str) -> Tuple[int, str, str]:
        '''
        Set a health check from a JSON-formatted description.
        '''
        try:
            health_check = json.loads(checks)
        except Exception as e:
            return -1, "", "Failed to decode JSON input: {}".format(e)

        try:
            for check, info in health_check.items():
                self._health[check] = {
                    "severity": str(info["severity"]),
                    "summary": str(info["summary"]),
                    "count": 123,
                    "detail": [str(m) for m in info["detail"]]
                }
        except Exception as e:
            return -1, "", "Invalid health check format: {}".format(e)

        self.set_health_checks(self._health)
        return 0, "", ""

    @CLICommand('mgr self-test health clear')
    def health_clear(self, checks: Optional[List[str]] = None) -> Tuple[int, str, str]:
        '''
        Clear health checks by name. If no names provided, clear all.
        '''
        if checks is not None:
            for check in checks:
                if check in self._health:
                    del self._health[check]
        else:
            self._health = dict()

        self.set_health_checks(self._health)
        return 0, "", ""

    @CLICommand('mgr self-test insights_set_now_offset')
    def insights_set_now_offset(self, hours: int) -> Tuple[int, str, str]:
        '''
        Set the now time for the insights module.
        '''
        self.remote("insights", "testing_set_now_time_offset", hours)
        return 0, "", ""

    def _self_test(self) -> None:
        self.log.info("Running self-test procedure...")

        self._self_test_osdmap()
        self._self_test_getters()
        self._self_test_config()
        self._self_test_store()
        self._self_test_misc()
        self._self_test_perf_counters()

    def _self_test_getters(self) -> None:
        self.version
        self.get_context()
        self.get_mgr_id()

        # In this function, we will assume that the system is in a steady
        # state, i.e. if a server/service appears in one call, it will
        # not have gone by the time we call another function referring to it

        objects = [
            "fs_map",
            "osdmap_crush_map_text",
            "osd_map",
            "config",
            "mon_map",
            "service_map",
            "osd_metadata",
            "pg_summary",
            "pg_status",
            "pg_dump",
            "pg_ready",
            "df",
            "pg_stats",
            "pool_stats",
            "osd_stats",
            "osd_ping_times",
            "health",
            "mon_status",
            "mgr_map"
        ]
        for obj in objects:
            assert self.get(obj) is not None

        assert self.get("__OBJ_DNE__") is None

        servers = self.list_servers()
        for server in servers:
            self.get_server(server['hostname'])  # type: ignore

        osdmap = self.get('osd_map')
        for o in osdmap['osds']:
            osd_id = o['osd']
            self.get_metadata("osd", str(osd_id))

        self.get_daemon_status("osd", "0")

    def _self_test_config(self) -> None:
        # This is not a strong test (can't tell if values really
        # persisted), it's just for the python interface bit.

        self.set_module_option("testkey", "testvalue")
        assert self.get_module_option("testkey") == "testvalue"

        self.set_localized_module_option("testkey", "foo")
        assert self.get_localized_module_option("testkey") == "foo"

        # Must return the default value defined in MODULE_OPTIONS.
        value = self.get_localized_module_option("rwoption6")
        assert isinstance(value, bool)
        assert value is True

        # Use default value.
        assert self.get_module_option("roption1") is None
        assert self.get_module_option("roption1", "foobar") == "foobar"
        assert self.get_module_option("roption2") == "xyz"
        assert self.get_module_option("roption2", "foobar") == "xyz"

        # Option type is not defined => return as string.
        self.set_module_option("rwoption1", 8080)
        value = self.get_module_option("rwoption1")
        assert isinstance(value, str)
        assert value == "8080"

        # Option type is defined => return as integer.
        self.set_module_option("rwoption2", 10)
        value = self.get_module_option("rwoption2")
        assert isinstance(value, int)
        assert value == 10

        # Option type is defined => return as float.
        self.set_module_option("rwoption3", 1.5)
        value = self.get_module_option("rwoption3")
        assert isinstance(value, float)
        assert value == 1.5

        # Option type is defined => return as string.
        self.set_module_option("rwoption4", "foo")
        value = self.get_module_option("rwoption4")
        assert isinstance(value, str)
        assert value == "foo"

        # Option type is defined => return as bool.
        self.set_module_option("rwoption5", False)
        value = self.get_module_option("rwoption5")
        assert isinstance(value, bool)
        assert value is False

        # Option value range is specified
        try:
            self.set_module_option("rwoption7", 43)
        except Exception as e:
            assert isinstance(e, ValueError)
        else:
            message = "should raise if value is not in specified range"
            assert False, message

        # Specified module does not exist => return None.
        assert self.get_module_option_ex("foo", "bar") is None

        # Specified key does not exist => return None.
        assert self.get_module_option_ex("dashboard", "bar") is None

        self.set_module_option_ex("telemetry", "contact", "*****@*****.**")
        assert self.get_module_option_ex("telemetry", "contact") == "*****@*****.**"

        # No option default value, so use the specified one.
        assert self.get_module_option_ex("dashboard", "password") is None
        assert self.get_module_option_ex("dashboard", "password", "foobar") == "foobar"

        # Option type is not defined => return as string.
        self.set_module_option_ex("selftest", "rwoption1", 1234)
        value = self.get_module_option_ex("selftest", "rwoption1")
        assert isinstance(value, str)
        assert value == "1234"

        # Option type is defined => return as integer.
        self.set_module_option_ex("telemetry", "interval", 60)
        value = self.get_module_option_ex("telemetry", "interval")
        assert isinstance(value, int)
        assert value == 60

        # Option type is defined => return as bool.
        self.set_module_option_ex("telemetry", "leaderboard", True)
        value = self.get_module_option_ex("telemetry", "leaderboard")
        assert isinstance(value, bool)
        assert value is True

    def _self_test_store(self) -> None:
        existing_keys = set(self.get_store_prefix("test").keys())
        self.set_store("testkey", "testvalue")
        assert self.get_store("testkey") == "testvalue"

        assert (set(self.get_store_prefix("test").keys())
                == {"testkey"} | existing_keys)

    def _self_test_perf_counters(self) -> None:
        self.get_perf_schema("osd", "0")
        self.get_counter("osd", "0", "osd.op")
        # get_counter
        # get_all_perf_coutners

    def _self_test_misc(self) -> None:
        self.set_uri("http://this.is.a.test.com")
        self.set_health_checks({})

    def _self_test_osdmap(self) -> None:
        osdmap = self.get_osdmap()
        osdmap.get_epoch()
        osdmap.get_crush_version()
        osdmap.dump()

        inc = osdmap.new_incremental()
        osdmap.apply_incremental(inc)
        inc.get_epoch()
        inc.dump()

        crush = osdmap.get_crush()
        crush.dump()
        crush.get_item_name(-1)
        crush.get_item_weight(-1)
        crush.find_takes()
        crush.get_take_weight_osd_map(-1)

        # osdmap.get_pools_by_take()
        # osdmap.calc_pg_upmaps()
        # osdmap.map_pools_pgs_up()

        # inc.set_osd_reweights
        # inc.set_crush_compat_weight_set_weights

        self.log.info("Finished self-test procedure.")

    def _test_remote_calls(self) -> None:
        # Test making valid call
        self.remote("influx", "self_test")

        # Test calling module that exists but isn't enabled
        # (arbitrarily pick a non-always-on module to use)
        disabled_module = "telegraf"
        mgr_map = self.get("mgr_map")
        assert disabled_module not in mgr_map['modules']

        # (This works until the Z release in about 2027)
        latest_release = sorted(mgr_map['always_on_modules'].keys())[-1]
        assert disabled_module not in mgr_map['always_on_modules'][latest_release]

        try:
            self.remote(disabled_module, "handle_command", {"prefix": "influx self-test"})
        except ImportError:
            pass
        else:
            raise RuntimeError("ImportError not raised for disabled module")

        # Test calling module that doesn't exist
        try:
            self.remote("idontexist", "self_test")
        except ImportError:
            pass
        else:
            raise RuntimeError("ImportError not raised for nonexistent module")

        # Test calling method that doesn't exist
        try:
            self.remote("influx", "idontexist")
        except NameError:
            pass
        else:
            raise RuntimeError("KeyError not raised")

    def remote_from_orchestrator_cli_self_test(self, what: str) -> Any:
        import orchestrator
        if what == 'OrchestratorError':
            return orchestrator.OrchResult(result=None, exception=orchestrator.OrchestratorError('hello, world'))
        elif what == "ZeroDivisionError":
            return orchestrator.OrchResult(result=None, exception=ZeroDivisionError('hello, world'))
        assert False, repr(what)

    def shutdown(self) -> None:
        self._workload = Workload.SHUTDOWN
        self._event.set()

    def _command_spam(self) -> None:
        self.log.info("Starting command_spam workload...")
        while not self._event.is_set():
            osdmap = self.get_osdmap()
            dump = osdmap.dump()
            count = len(dump['osds'])
            i = int(random.random() * count)
            w = random.random()

            result = CommandResult('')
            self.send_command(result, 'mon', '', json.dumps({
                'prefix': 'osd reweight',
                'id': i,
                'weight': w}), '')

            _ = osdmap.get_crush().dump()
            r, outb, outs = result.wait()

        self._event.clear()
        self.log.info("Ended command_spam workload...")

    @CLICommand('mgr self-test eval')
    def eval(self,
             s: Optional[str] = None,
             inbuf: Optional[str] = None) -> HandleCommandResult:
        '''
        eval given source
        '''
        source = s or inbuf
        if source is None:
            return HandleCommandResult(-1, '', 'source is not specified')

        err = StringIO()
        out = StringIO()
        with redirect_stderr(err), redirect_stdout(out):
            needs_more = self._repl.runsource(source)
            if needs_more:
                retval = 2
                stdout = ''
                stderr = ''
            else:
                retval = 0
                stdout = out.getvalue()
                stderr = err.getvalue()
            return HandleCommandResult(retval, stdout, stderr)

    def serve(self) -> None:
        while True:
            if self._workload == Workload.COMMAND_SPAM:
                self._command_spam()
            elif self._workload == Workload.SHUTDOWN:
                self.log.info("Shutting down...")
                break
            elif self._workload == Workload.THROW_EXCEPTION:
                raise RuntimeError("Synthetic exception in serve")
            else:
                self.log.info("Waiting for workload request...")
                self._event.wait()
                self._event.clear()
Esempio n. 40
0
class PyCute(QMultiLineEdit):

    """
    PyCute is a Python shell for PyQt.

    Creating, displaying and controlling PyQt widgets from the Python command
    line interpreter is very hard, if not, impossible.  PyCute solves this
    problem by interfacing the Python interpreter to a PyQt widget.

    My use is interpreter driven plotting to QwtPlot instances. Why?
    
    Other popular scientific software packages like SciPy, SciLab, Octave,
    Maple, Mathematica, GnuPlot, ..., also have interpreter driven plotting.  
    It is well adapted to quick & dirty exploration. 

    Of course, PyQt's debugger -- eric -- gives you similar facilities, but
    PyCute is smaller and easier to integrate in applications.
    Eric requires Qt-3.x.

    """
    
    reading = 0
    history = []
    pointer = 0

    def __init__(self, locals=None, log='', parent=None):
        """Constructor.

        The optional 'locals' argument specifies the dictionary in
        which code will be executed; it defaults to a newly created
        dictionary with key "__name__" set to "__console__" and key
        "__doc__" set to None.

        The optional 'log' argument specifies the file in which the
        interpreter session is to be logged.
        
        The optional 'parent' argument specifies the parent widget.
        If no parent widget has been specified, it is possible to
        exit the interpreter by Ctrl-D.
        """
        
        QMultiLineEdit.__init__(self, parent)
        self.interpreter = Interpreter(locals)
        self.connect(self, SIGNAL("returnPressed()"), self.onReturnPressed)

        # session log
        self.log = log or 'PyCute.log'
        
        # to exit the main interpreter by a Ctrl-D if PyCute has no parent
        if parent is None:
            self.eofKey = Qt.Key_D
        else:
            self.eofKey = None

        # capture all interactive input/output 
        #sys.stdout   = self
        sys.stderr   = self
        sys.stdin    = self

        # user interface setup
        # no word wrapping simplifies cursor <-> numLines() mapping
        self.setWordWrap(QMultiLineEdit.WidgetWidth)
        self.setCaption('PyCute -- a Python Shell for PyQt --'
                        'http://gerard.vermeulen.free.fr')
        # font
        if os.name == 'posix':
            font = QFont("Fixed", 12)
        elif os.name == 'nt' or os.name == 'dos':
            font = QFont("Courier New", 8)
        else:
            raise SystemExit, "FIXME for 'os2', 'mac', 'ce' or 'riscos'"
        font.setFixedPitch(1)
        self.setFont(font)

        # geometry
        height = 40*QFontMetrics(font).lineSpacing()
        request = QSize(600, height)
        if parent is not None:
            request = request.boundedTo(parent.size())
        self.resize(request)

        # interpreter prompt.
        try:
            sys.ps1
        except AttributeError:
            sys.ps1 = ">>> "
        try:
            sys.ps2
        except AttributeError:
            sys.ps2 = "... "

        # interpreter banner
        self.write('The PyCute shell running Python %s on %s.\n' %
                   (sys.version, sys.platform))
        self.write('Type "copyright", "credits" or "license"'
                   ' for more information on Python.\n')
        self.ps1()

    # __init__()
        
    def write(self, line):
        self.append(line.rstrip('\r\n'))
        self.moveCursorToEnd()

    # write()

    def ps1(self):
        self.append(sys.ps1)
        self.mark = self.moveCursorToEnd()

    # ps1()
    
    def ps2(self):
        self.append(sys.ps2)
        self.moveCursorToEnd()

    # ps2()

    def tab(self):
        self.insert('    ')
        self.moveCursorMoveToEnd()

    # tab()

    def getLines(self):
        #print self.mark, 'pipo'
        position = self.getCursorPosition()
        apply(self.setCursorPosition, self.mark + (1,))
        lines = self.markedText()
        apply(self.setCursorPosition, position)
        return str(lines)

    # getLines()
    
    def readline(self):
        """
        Simulate stdin, stdout, and stderr.
        """
        self.reading = 1
        self.__clearLine()
        self.__moveCursorToEnd()
        while self.reading:
            qApp.processOneEvent()
        if self.line.length() == 0:
            return '\n'
        else:
            return str(self.line) 
    
    def fakeUser(self, lines):
        """
        Simulate a user: lines is a sequence of strings (Python statements).
        """
        for line in lines:
            self.line = QString(line.rstrip())
            self.write(self.line)
            self.write('\n')
            self.__run()
            
    def __run(self):
        """
        Append the last line to the history list, let the interpreter execute
        the last line(s), and clean up accounting for the interpreter results:
        (1) the interpreter succeeds
        (2) the interpreter fails, finds no errors and wants more line(s)
        (3) the interpreter fails, finds errors and writes them to sys.stderr
        """
        if self.gnu:
            self.pointer = 0
        self.history.append(QString(self.line))
        self.lines.append(str(self.line))
        source = '\n'.join(self.lines)
        self.more = self.interpreter.runsource(source)
        if self.more:
            self.write(sys.ps2)
        else:
            self.write(sys.ps1)
            self.lines = []
        self.__clearLine()
        
    def __clearLine(self):
        """
        Clear input line buffer
        """
        self.line.truncate(0)
        self.point = 0
        
    def moveCursorToEnd(self):
        y = self.numLines()-1
        x = self.lineLength(y)
        self.setCursorPosition(y, x)
        return y, x

    def push(self):
        lines = self.getLines()
        if not self.interpreter.runsource(lines.replace(sys.ps2, '')):
            self.history.insert(0, (self.mark, lines))
            self.ps1()
        else:
            self.ps2()

    # push()

    def onReturnPressed(self):
        if self.reading:
            self.reading = 0
        else:
            self.push()

    # onReturnPressed()
    def keyPressEvent(self, e):
        ascii = e.ascii()
        key   = e.key()
        state = e.state()
        text  = e.text()

        if state & Qt.ControlButton and key == self.eofKey:
            try:
                file = open(self.log, "w")
                file.write(str(self.text()))
                file.close()
            except:
                pass
            sys.exit()
            return
        
        if state & Qt.ControlButton and key == Qt.Key_I:
            self.tab()
            return

        if key == Qt.Key_Tab:
            # completion
            return

        if key == Qt.Key_Return and not self.reading:
            position = self.getCursorPosition()
            if self.mark > position:
                for mark, lines in self.history:
                    if mark < position:
                        apply(self.setCursorPosition, self.mark)
                        self.insert(lines)
                        return
                else:
                    return

        QMultiLineEdit.keyPressEvent(self, e)
Esempio n. 41
0
class PythonWidget(HistoryConsoleWidget):
    """ A basic in-process Python interpreter.
    """

    # Emitted when a command has been executed in the interpeter.
    executed = QtCore.Signal()

    #--------------------------------------------------------------------------
    # 'object' interface
    #--------------------------------------------------------------------------

    def __init__(self, parent=None):
        super(PythonWidget, self).__init__(parent)

        # PythonWidget attributes.
        self.locals = dict(__name__='__console__', __doc__=None)
        self.interpreter = InteractiveInterpreter(self.locals)

        # PythonWidget protected attributes.
        self._buffer = StringIO()
        self._bracket_matcher = BracketMatcher(self._control)
        self._call_tip_widget = CallTipWidget(self._control)
        self._completion_lexer = CompletionLexer(PythonLexer())
        self._hidden = False
        self._highlighter = PythonWidgetHighlighter(self)
        self._last_refresh_time = 0

        # file-like object attributes.
        self.encoding = sys.stdin.encoding

        # Configure the ConsoleWidget.
        self.tab_width = 4
        self._set_continuation_prompt('... ')

        # Configure the CallTipWidget.
        self._call_tip_widget.setFont(self.font)
        self.font_changed.connect(self._call_tip_widget.setFont)

        # Connect signal handlers.
        document = self._control.document()
        document.contentsChange.connect(self._document_contents_change)

        # Display the banner and initial prompt.
        self.reset()

    #--------------------------------------------------------------------------
    # file-like object interface
    #--------------------------------------------------------------------------

    def flush(self):
        """ Flush the buffer by writing its contents to the screen.
        """
        self._buffer.seek(0)
        text = self._buffer.getvalue()
        self._buffer.close()
        self._buffer = StringIO()

        self._append_plain_text(text)
        self._control.moveCursor(QtGui.QTextCursor.End)

    def readline(self, prompt=None):
        """ Read and return one line of input from the user.
        """
        return self._readline(prompt)

    def write(self, text, refresh=True):
        """ Write text to the buffer, possibly flushing it if 'refresh' is set.
        """
        if not self._hidden:
            self._buffer.write(text)
            if refresh:
                current_time = time()
                if current_time - self._last_refresh_time > 0.05:
                    self.flush()
                    self._last_refresh_time = current_time

    def writelines(self, lines, refresh=True):
        """ Write a list of lines to the buffer.
        """
        for line in lines:
            self.write(line, refresh=refresh)

    #---------------------------------------------------------------------------
    # 'ConsoleWidget' abstract interface
    #---------------------------------------------------------------------------

    def _is_complete(self, source, interactive):
        """ Returns whether 'source' can be completely processed and a new
            prompt created. When triggered by an Enter/Return key press,
            'interactive' is True; otherwise, it is False.
        """
        if interactive:
            lines = source.splitlines()
            if len(lines) == 1:
                try:
                    return compile_command(source) is not None
                except:
                    # We'll let the interpeter handle the error.
                    return True
            else:
                return lines[-1].strip() == ''
        else:
            return True

    def _execute(self, source, hidden):
        """ Execute 'source'. If 'hidden', do not show any output.

        See parent class :meth:`execute` docstring for full details.
        """
        # Save the current std* and point them here
        old_stdin = sys.stdin
        old_stdout = sys.stdout
        old_stderr = sys.stderr
        sys.stdin = sys.stdout = sys.stderr = self

        # Run the source code in the interpeter
        self._hidden = hidden
        try:
            more = self.interpreter.runsource(source)
        finally:
            self._hidden = False

            # Restore std* unless the executed changed them
            if sys.stdin is self:
                sys.stdin = old_stdin
            if sys.stdout is self:
                sys.stdout = old_stdout
            if sys.stderr is self:
                sys.stderr = old_stderr

            self.executed.emit()
            self._show_interpreter_prompt()

    def _prompt_started_hook(self):
        """ Called immediately after a new prompt is displayed.
        """
        if not self._reading:
            self._highlighter.highlighting_on = True

    def _prompt_finished_hook(self):
        """ Called immediately after a prompt is finished, i.e. when some input
            will be processed and a new prompt displayed.
        """
        if not self._reading:
            self._highlighter.highlighting_on = False

    def _tab_pressed(self):
        """ Called when the tab key is pressed. Returns whether to continue
            processing the event.
        """
        # Perform tab completion if:
        # 1) The cursor is in the input buffer.
        # 2) There is a non-whitespace character before the cursor.
        text = self._get_input_buffer_cursor_line()
        if text is None:
            return False
        complete = bool(text[:self._get_input_buffer_cursor_column()].strip())
        if complete:
            self._complete()
        return not complete

    #---------------------------------------------------------------------------
    # 'ConsoleWidget' protected interface
    #---------------------------------------------------------------------------

    def _event_filter_console_keypress(self, event):
        """ Reimplemented for smart backspace.
        """
        if event.key() == QtCore.Qt.Key_Backspace and \
                not event.modifiers() & QtCore.Qt.AltModifier:
            # Smart backspace: remove four characters in one backspace if:
            # 1) everything left of the cursor is whitespace
            # 2) the four characters immediately left of the cursor are spaces
            col = self._get_input_buffer_cursor_column()
            cursor = self._control.textCursor()
            if col > 3 and not cursor.hasSelection():
                text = self._get_input_buffer_cursor_line()[:col]
                if text.endswith('    ') and not text.strip():
                    cursor.movePosition(QtGui.QTextCursor.Left,
                                        QtGui.QTextCursor.KeepAnchor, 4)
                    cursor.removeSelectedText()
                    return True

        return super(PythonWidget, self)._event_filter_console_keypress(event)

    def _insert_continuation_prompt(self, cursor):
        """ Reimplemented for auto-indentation.
        """
        super(PythonWidget, self)._insert_continuation_prompt(cursor)
        source = self.input_buffer
        space = 0
        for c in source.splitlines()[-1]:
            if c == '\t':
                space += 4
            elif c == ' ':
                space += 1
            else:
                break
        if source.rstrip().endswith(':'):
            space += 4
        cursor.insertText(' ' * space)

    #---------------------------------------------------------------------------
    # 'PythonWidget' public interface
    #---------------------------------------------------------------------------

    def execute_file(self, path, hidden=False):
        """ Attempts to execute file with 'path'. If 'hidden', no output is
            shown.
        """

        self.execute("exec(open(%s).read())" % repr(path), hidden=hidden)

    def reset(self):
        """ Resets the widget to its initial state. Similar to ``clear``, but
            also re-writes the banner.
        """
        self._reading = False
        self._highlighter.highlighting_on = False

        self._control.clear()
        self._append_plain_text(self._get_banner())
        self._show_interpreter_prompt()

    #---------------------------------------------------------------------------
    # 'PythonWidget' protected interface
    #---------------------------------------------------------------------------

    def _call_tip(self):
        """ Shows a call tip, if appropriate, at the current cursor location.
        """
        # Decide if it makes sense to show a call tip
        cursor = self._get_cursor()
        cursor.movePosition(QtGui.QTextCursor.Left)
        if cursor.document().characterAt(cursor.position()) != '(':
            return False
        context = self._get_context(cursor)
        if not context:
            return False

        # Look up the context and show a tip for it
        symbol, leftover = self._get_symbol_from_context(context)
        doc = getattr(symbol, '__doc__', None)
        if doc is not None and not leftover:
            self._call_tip_widget.show_call_info(doc=doc)
            return True
        return False

    def _complete(self):
        """ Performs completion at the current cursor location.
        """
        context = self._get_context()
        if context:
            symbol, leftover = self._get_symbol_from_context(context)
            if len(leftover) == 1:
                leftover = leftover[0]
                if symbol is None:
                    names = self.interpreter.locals.keys()
                    names += __builtin__.__dict__.keys()
                else:
                    names = dir(symbol)
                completions = [ n for n in names if n.startswith(leftover) ]
                if completions:
                    cursor = self._get_cursor()
                    cursor.movePosition(QtGui.QTextCursor.Left,
                                        n=len(context[-1]))
                    self._complete_with_items(cursor, completions)

    def _get_banner(self):
        """ Gets a banner to display at the beginning of a session.
        """
        banner = 'Python %s on %s\nType "help", "copyright", "credits" or ' \
            '"license" for more information.'
        return banner % (sys.version, sys.platform)

    def _get_context(self, cursor=None):
        """ Gets the context for the specified cursor (or the current cursor
            if none is specified).
        """
        if cursor is None:
            cursor = self._get_cursor()
        cursor.movePosition(QtGui.QTextCursor.StartOfBlock,
                            QtGui.QTextCursor.KeepAnchor)
        text = cursor.selection().toPlainText()
        return self._completion_lexer.get_context(text)

    def _get_symbol_from_context(self, context):
        """ Find a python object in the interpeter namespace from a context (a
            list of names).
        """
        context = map(str, context)
        if len(context) == 0:
            return None, context

        base_symbol_string = context[0]
        symbol = self.interpreter.locals.get(base_symbol_string, None)
        if symbol is None:
            symbol = __builtin__.__dict__.get(base_symbol_string, None)
        if symbol is None:
            return None, context

        context = context[1:]
        for i, name in enumerate(context):
            new_symbol = getattr(symbol, name, None)
            if new_symbol is None:
                return symbol, context[i:]
            else:
                symbol = new_symbol

        return symbol, []

    def _show_interpreter_prompt(self):
        """ Shows a prompt for the interpreter.
        """
        self.flush()
        self._show_prompt('>>> ')

    #------ Signal handlers ----------------------------------------------------

    def _document_contents_change(self, position, removed, added):
        """ Called whenever the document's content changes. Display a call tip
            if appropriate.
        """
        # Calculate where the cursor should be *after* the change:
        position += added

        document = self._control.document()
        if position == self._get_cursor().position():
            self._call_tip()
Esempio n. 42
0
class PyConsole(QtGui.QWidget):
    def __init__(self,parent=None,locals=None, log='', fontSize=10, commandWidget=None):
        QtGui.QWidget.__init__(self, parent)
        self.ui = Ui_Form()
        self.ui.setupUi(self)
        
        # Setup TextBrowser
        self.ui.tb_view.setWordWrapMode(QtGui.QTextOption.WrapAnywhere)
        self.ui.tb_view.keyPressEvent = self.tb_out_keypress

        # Setup Command 
        if not commandWidget:
            try:
                import scintilla_cmd
                commandWidget = scintilla_cmd.cmd_widget()
            except:
                commandWidget = None
        
        if commandWidget:
            # Scintilla Commandline
            self.ui.le_cmd = commandWidget
            
        else:
            # Line Edit
            self.ui.le_cmd = QtGui.QLineEdit()
            self.ui.le_cmd.widgetObject = QtGui.QLineEdit
            self.ui.le_cmd.type = 'qlineedit'
        
        self.ui.frame.layout().addWidget(self.ui.le_cmd,0,2,1,1)
        self.ui.le_cmd.keyPressEvent = self.cmdKeyPress
        
        # font
        if os.name == 'posix':
            font = QtGui.QFont("Monospace", fontSize)
        elif os.name == 'nt' or os.name == 'dos':
            font = QtGui.QFont("Courier New", fontSize)
        else:
            print(SystemExit, "FIXME for 'os2', 'mac', 'ce' or 'riscos'")
##            raise Exception(SystemExit, "FIXME for 'os2', 'mac', 'ce' or 'riscos'")
        font.setFixedPitch(1)
##        self.setFont(font)
        self.ui.tb_view.setFont(font)
        self.ui.le_cmd.setFont(font)
        self.ui.l_prompt.setFont(font)
        
        # geometry
        height = 40*QtGui.QFontMetrics(font).lineSpacing()
        
        self.ui.tb_view.setTabStopWidth(QtGui.QFontMetrics(font).width('    ')-1)

        # Setup Interpreter
        if locals==None:
            locals={'self':self,'scope':parent}
        self.interpreter = Interpreter(locals)
        
        # Exit with Ctrl+D
        if parent is None:
            self.eofKey = Qt.Key_D
        else:
            self.eofKey = None

##        self.viewers = []
        class SplitStdErr:
            def __init__(self,default_stderr,console_stderr):
##                self._targets=targets
                self.default_stderr = default_stderr
                self.console_stderr = console_stderr
            def write(self,line):
                self.default_stderr.write(line)
                self.console_stderr.write(line,mode=2)
##                for target in self._targets:
##                    target.write(line)
                    
        # capture all interactive input/output 
        sys.stdout   = self
        sys.stderr   = SplitStdErr(sys.stderr,self)
        sys.stdin    = self
        
        # last line + last incomplete lines
        self.lines   = []

        # the cursor position in the last line
        self.point   = 0
        # flag: the interpreter needs more input to run the last lines. 
        self.more    = 0
        # flag: readline() is being used for e.g. raw_input() and input()
        self.reading = 0
        # history
        self.history = []
        self.pointer = 0
        self.indent = ''
        self.prompt = '>>>'
        self.writecount = 0
        
        # interpreter prompt.
        try:
            sys.ps1
        except AttributeError:
            sys.ps1 = ">>> "
        try:
            sys.ps2
        except AttributeError:
            sys.ps2 = "... "
        
        self.write('# Python '+'('+str(sys.version_info.major)+'.'+str(sys.version_info.minor)+'.'+str(sys.version_info.micro)+')\n',mode=1)
        self.write('\n')
        # Focus to command prompt
        self.ui.le_cmd.setFocus()
    
    def cmdSizeHint(self):
        print 'size hint'
        return QtCore.QSize(20,20)
    
    def enter(self):
        line = unicode(self.ui.le_cmd.text())
        
        if line.strip():
            self.history.append(line)
            self.pointer = len(self.history)
##            self.write(line+'\n',mode=1,prefix=unicode(self.ui.l_prompt.text())+' ')
        else:
            line = ''
        
        # Clear if 2 blank lines in a row
        cmd_reset = 0
        if len(self.lines) > 0:
            if self.lines[-1].rstrip() =='' and line.rstrip()=='':
                self.lines = []
                cmd_reset = 1
        
        if not cmd_reset:
            self.write(line+'\n',mode=1,prefix=unicode(self.ui.l_prompt.text())+' ')
            self.lines.append(line)
            
            if line == 'clear':
                # Clear Text
                self.prompt = '>>>'
                self.ui.tb_view.setText('')
                self.ui.le_cmd.setText('')
                self.lines = []
            
            else:
                source = '\n'.join(self.lines)
                self.more = self.interpreter.runsource(source)

                self.indent=''
                if self.more:
                    self.prompt = sys.ps2
                    self.indent = line[0:len(line)-len(line.lstrip())]
                    if line.rstrip():
                        if line.rstrip()[-1]==':':
                            self.indent+='    '
                            
                else:
                    self.prompt = sys.ps1
                    self.lines = []
                    
                self.setCommandText(self.indent)
        self.ui.l_prompt.setText(self.prompt)
        

    def write(self, text,mode=0,prefix=None):
        # modes
        #  0 = output
        #  1 = input
        #  2 = error
##        hack = self.ui.tb_view.toPlainText()
##        hack.append(text+'\n')
##        self.ui.tb_view.setText(hack)
##        print len(text),len(text.rstrip())

        self.writecount += 1
##        if text.rstrip() or 1:
        self.ui.tb_view.moveCursor(QtGui.QTextCursor.End, 0)
        if mode == 2: # Error
            txt = '<font style="color:rgb(255,112,99);">' + str(QtCore.QString(text).toUtf8()).decode('utf-8').replace('<','&lt;').replace('>','&gt;').replace('  ','&nbsp;&nbsp;').replace('\n','<br>')+"</font>"
            txt = re_file.sub(r"<a style=""color:rgb(121,213,255);"" href='\g<2>'>\g<2></a>",txt)
            self.ui.tb_view.insertHtml(txt)
        elif mode == 1: # Input
            txt = '<div style="color:rgb(89,197,254);">'
            if prefix:
                txt += '<span style="color:rgb(38,90,150);">'+prefix.replace('>','&gt;')+'</span>'
            txt +=str(QtCore.QString(text).toUtf8()).decode('utf-8').replace('<','&lt;').replace('>','&gt;').replace('  ','&nbsp;&nbsp;').replace('\n','<br>')+"</div>"
            self.ui.tb_view.insertHtml(txt)
        else: # Write
            txt = '<div style="color:rgb(255,255,255);">'+str(QtCore.QString(text).toUtf8()).decode('utf-8').replace('<','&lt;').replace('>','&gt;').replace('  ','&nbsp;&nbsp;').replace('\n','<br>')+"</div>"
            self.ui.tb_view.insertHtml(txt)

        self.ui.tb_view.moveCursor(QtGui.QTextCursor.End, 0)
    
    def cmdKeyPress(self,e):
        key   = e.key()
        handled = 0

        if key == Qt.Key_Up:
            # Up
            if len(self.history):
                if self.pointer > 0:
                    self.pointer -= 1
                    self.setCommandText(self.history[self.pointer])
                    handled = 1
        elif key == Qt.Key_Down:
            # Down
            if len(self.history) and self.pointer<len(self.history):
                if self.pointer == len(self.history)-1:
                    self.setCommandText('')
                    self.pointer += 1
                    handled = 1
                else:
                    self.pointer += 1
                    self.setCommandText(self.history[self.pointer])
                    handled = 1
        elif key == Qt.Key_Enter or key == Qt.Key_Return:
            # Enter
            if self.reading:
                self.reading = 0
            else:
                self.enter()
            handled = 1
        elif key == Qt.Key_Tab:
            self.ui.le_cmd.insert('    ')
            handled=1
        
        # Ctrl
        if e.modifiers() & QtCore.Qt.ControlModifier:
            if key == QtCore.Qt.Key_V:  # paste
                # V
##                txt = QtGui.QApplication.clipboard().text('plain').split(QtCore.QRegExp("[\r\n]"),QtCore.QString.SkipEmptyParts)
                txt = str(QtGui.QApplication.clipboard().text('plain').toUtf8()).decode('utf-8').splitlines()
                if len(txt) > 0:
                    self.ui.le_cmd.insert(txt[0])
                    if len(txt) > 1:
                        self.enter()
                        for t in txt[1:-1]:
                            self.setCommandText(t)
                            self.enter()
                        self.setCommandText(txt[-1])
                    handled = 1
            elif key == QtCore.Qt.Key_L: # launch
                # L
                from subprocess import Popen
                try:
                    if os.name =='nt':
                        Popen(["pythonw",os.path.abspath(__file__)])
                    else:
                        Popen(["python",os.path.abspath(__file__)])
                except:
                    QtGui.QMessageBox.warning(self,'Error','The Python Shell could not open with your default Python install.  Please make sure you have Python 2.7 (or 2.6) installed and the Python executable is in your system path')

        if not handled:
##            QtGui.QLineEdit.keyPressEvent(self.ui.le_cmd,e)
            self.ui.le_cmd.widgetObject.keyPressEvent(self.ui.le_cmd,e)
    
    def setCommandText(self,text):
        self.ui.le_cmd.setText(text)
        if self.ui.le_cmd.type == 'qscintilla':
            self.ui.le_cmd.setCursorPosition(0,len(text))
    
    def readline(self):
        """
        Simulate stdin, stdout, and stderr.
        """
        self.reading = 1
        self.ui.le_cmd.setText('')
        self.ui.l_prompt.setText('?')
##        self.moveCursor(QtGui.QTextCursor.End, 0)
        while self.reading:
            QtGui.QApplication.processEvents()
        line = self.ui.le_cmd.text()
        
        if len(line) == 0:
            return_line = '\n'
        else:
            return_line = str(line)
        self.write('\n')
        return return_line

    def writelines(self, text):
        """
        Simulate stdin, stdout, and stderr.
        """
        map(self.write, text)

    def flush(self):
        """
        Simulate stdin, stdout, and stderr.
        """
        pass

    def isatty(self):
        """
        Simulate stdin, stdout, and stderr.
        """
        return 1

    #---Output Overrides
    def tb_out_keypress(self,e):
        key   = e.key()
        handled = 0
        
        # Copy ahead of disable
        if e.modifiers() & QtCore.Qt.ControlModifier:
            # Copy
            if key == Qt.Key_C:
                txt = str(self.ui.tb_view.textCursor().selectedText().toUtf8()).replace('\xc2\xa0',' ').decode('utf-8')
##                QtGui.QApplication.clipboard().clear()
                ntxt = []
                for ln in txt.splitlines():
                    t = ln
                    if ln.startswith('>>> ') or ln.startswith('... '):
                        t = ln[4:]
                    ntxt.append(t)
                txt = '\n'.join(ntxt)
                QtGui.QApplication.clipboard().setText(txt)
                handled = 1
        
        if not handled:
            QtGui.QTextEdit.keyPressEvent(self.ui.tb_view,e)
Esempio n. 43
0
class PyConsole(QtGui.QWidget):
    def __init__(self,
                 parent=None,
                 locals=None,
                 log='',
                 fontSize=10,
                 commandWidget=None):
        QtGui.QWidget.__init__(self, parent)
        self.ui = Ui_Form()
        self.ui.setupUi(self)

        # Setup TextBrowser
        self.ui.tb_view.setWordWrapMode(QtGui.QTextOption.WrapAnywhere)
        self.ui.tb_view.keyPressEvent = self.tb_out_keypress

        # Setup Command
        if not commandWidget:
            try:
                import scintilla_cmd
                commandWidget = scintilla_cmd.cmd_widget()
            except:
                commandWidget = None

        if commandWidget:
            # Scintilla Commandline
            self.ui.le_cmd = commandWidget

        else:
            # Line Edit
            self.ui.le_cmd = QtGui.QLineEdit()
            self.ui.le_cmd.widgetObject = QtGui.QLineEdit
            self.ui.le_cmd.type = 'qlineedit'

        self.ui.frame.layout().addWidget(self.ui.le_cmd, 0, 2, 1, 1)
        self.ui.le_cmd.keyPressEvent = self.cmdKeyPress

        # font
        if os.name == 'posix':
            font = QtGui.QFont("Monospace", fontSize)
        elif os.name == 'nt' or os.name == 'dos':
            font = QtGui.QFont("Courier New", fontSize)
        else:
            print(SystemExit, "FIXME for 'os2', 'mac', 'ce' or 'riscos'")
##            raise Exception(SystemExit, "FIXME for 'os2', 'mac', 'ce' or 'riscos'")
        font.setFixedPitch(1)
        ##        self.setFont(font)
        self.ui.tb_view.setFont(font)
        self.ui.le_cmd.setFont(font)
        self.ui.l_prompt.setFont(font)

        # geometry
        height = 40 * QtGui.QFontMetrics(font).lineSpacing()

        self.ui.tb_view.setTabStopWidth(
            QtGui.QFontMetrics(font).width('    ') - 1)

        # Setup Interpreter
        if locals == None:
            locals = {'self': self, 'scope': parent}
        self.interpreter = Interpreter(locals)

        # Exit with Ctrl+D
        if parent is None:
            self.eofKey = Qt.Key_D
        else:
            self.eofKey = None

##        self.viewers = []

        class SplitStdErr:
            def __init__(self, default_stderr, console_stderr):
                ##                self._targets=targets
                self.default_stderr = default_stderr
                self.console_stderr = console_stderr

            def write(self, line):
                self.default_stderr.write(line)
                self.console_stderr.write(line, mode=2)
##                for target in self._targets:
##                    target.write(line)

# capture all interactive input/output

        sys.stdout = self
        sys.stderr = SplitStdErr(sys.stderr, self)
        sys.stdin = self

        # last line + last incomplete lines
        self.lines = []

        # the cursor position in the last line
        self.point = 0
        # flag: the interpreter needs more input to run the last lines.
        self.more = 0
        # flag: readline() is being used for e.g. raw_input() and input()
        self.reading = 0
        # history
        self.history = []
        self.pointer = 0
        self.indent = ''
        self.prompt = '>>>'
        self.writecount = 0

        # interpreter prompt.
        try:
            sys.ps1
        except AttributeError:
            sys.ps1 = ">>> "
        try:
            sys.ps2
        except AttributeError:
            sys.ps2 = "... "

        self.write('# Python ' + '(' + str(sys.version_info.major) + '.' +
                   str(sys.version_info.minor) + '.' +
                   str(sys.version_info.micro) + ')\n',
                   mode=1)
        self.write('\n')
        # Focus to command prompt
        self.ui.le_cmd.setFocus()

    def cmdSizeHint(self):
        print 'size hint'
        return QtCore.QSize(20, 20)

    def enter(self):
        line = unicode(self.ui.le_cmd.text())

        if line.strip():
            self.history.append(line)
            self.pointer = len(self.history)
##            self.write(line+'\n',mode=1,prefix=unicode(self.ui.l_prompt.text())+' ')
        else:
            line = ''

        # Clear if 2 blank lines in a row
        cmd_reset = 0
        if len(self.lines) > 0:
            if self.lines[-1].rstrip() == '' and line.rstrip() == '':
                self.lines = []
                cmd_reset = 1

        if not cmd_reset:
            self.write(line + '\n',
                       mode=1,
                       prefix=unicode(self.ui.l_prompt.text()) + ' ')
            self.lines.append(line)

            if line == 'clear':
                # Clear Text
                self.prompt = '>>>'
                self.ui.tb_view.setText('')
                self.ui.le_cmd.setText('')
                self.lines = []

            else:
                source = '\n'.join(self.lines)
                self.more = self.interpreter.runsource(source)

                self.indent = ''
                if self.more:
                    self.prompt = sys.ps2
                    self.indent = line[0:len(line) - len(line.lstrip())]
                    if line.rstrip():
                        if line.rstrip()[-1] == ':':
                            self.indent += '    '

                else:
                    self.prompt = sys.ps1
                    self.lines = []

                self.setCommandText(self.indent)
        self.ui.l_prompt.setText(self.prompt)

    def write(self, text, mode=0, prefix=None):
        # modes
        #  0 = output
        #  1 = input
        #  2 = error
        ##        hack = self.ui.tb_view.toPlainText()
        ##        hack.append(text+'\n')
        ##        self.ui.tb_view.setText(hack)
        ##        print len(text),len(text.rstrip())

        self.writecount += 1
        ##        if text.rstrip() or 1:
        self.ui.tb_view.moveCursor(QtGui.QTextCursor.End, 0)
        if mode == 2:  # Error
            txt = '<font style="color:rgb(255,112,99);">' + str(
                QtCore.QString(text).toUtf8()).decode('utf-8').replace(
                    '<', '&lt;').replace('>', '&gt;').replace(
                        '  ', '&nbsp;&nbsp;').replace('\n', '<br>') + "</font>"
            txt = re_file.sub(
                r"<a style="
                "color:rgb(121,213,255);"
                " href='\g<2>'>\g<2></a>", txt)
            self.ui.tb_view.insertHtml(txt)
        elif mode == 1:  # Input
            txt = '<div style="color:rgb(89,197,254);">'
            if prefix:
                txt += '<span style="color:rgb(38,90,150);">' + prefix.replace(
                    '>', '&gt;') + '</span>'
            txt += str(QtCore.QString(text).toUtf8()).decode('utf-8').replace(
                '<', '&lt;').replace('>', '&gt;').replace(
                    '  ', '&nbsp;&nbsp;').replace('\n', '<br>') + "</div>"
            self.ui.tb_view.insertHtml(txt)
        else:  # Write
            txt = '<div style="color:rgb(255,255,255);">' + str(
                QtCore.QString(text).toUtf8()).decode('utf-8').replace(
                    '<', '&lt;').replace('>', '&gt;').replace(
                        '  ', '&nbsp;&nbsp;').replace('\n', '<br>') + "</div>"
            self.ui.tb_view.insertHtml(txt)

        self.ui.tb_view.moveCursor(QtGui.QTextCursor.End, 0)

    def cmdKeyPress(self, e):
        key = e.key()
        handled = 0

        if key == Qt.Key_Up:
            # Up
            if len(self.history):
                if self.pointer > 0:
                    self.pointer -= 1
                    self.setCommandText(self.history[self.pointer])
                    handled = 1
        elif key == Qt.Key_Down:
            # Down
            if len(self.history) and self.pointer < len(self.history):
                if self.pointer == len(self.history) - 1:
                    self.setCommandText('')
                    self.pointer += 1
                    handled = 1
                else:
                    self.pointer += 1
                    self.setCommandText(self.history[self.pointer])
                    handled = 1
        elif key == Qt.Key_Enter or key == Qt.Key_Return:
            # Enter
            if self.reading:
                self.reading = 0
            else:
                self.enter()
            handled = 1
        elif key == Qt.Key_Tab:
            self.ui.le_cmd.insert('    ')
            handled = 1

        # Ctrl
        if e.modifiers() & QtCore.Qt.ControlModifier:
            if key == QtCore.Qt.Key_V:  # paste
                # V
                ##                txt = QtGui.QApplication.clipboard().text('plain').split(QtCore.QRegExp("[\r\n]"),QtCore.QString.SkipEmptyParts)
                txt = str(QtGui.QApplication.clipboard().text(
                    'plain').toUtf8()).decode('utf-8').splitlines()
                if len(txt) > 0:
                    self.ui.le_cmd.insert(txt[0])
                    if len(txt) > 1:
                        self.enter()
                        for t in txt[1:-1]:
                            self.setCommandText(t)
                            self.enter()
                        self.setCommandText(txt[-1])
                    handled = 1
            elif key == QtCore.Qt.Key_L:  # launch
                # L
                from subprocess import Popen
                try:
                    if os.name == 'nt':
                        Popen(["pythonw", os.path.abspath(__file__)])
                    else:
                        Popen(["python", os.path.abspath(__file__)])
                except:
                    QtGui.QMessageBox.warning(
                        self, 'Error',
                        'The Python Shell could not open with your default Python install.  Please make sure you have Python 2.7 (or 2.6) installed and the Python executable is in your system path'
                    )

        if not handled:
            ##            QtGui.QLineEdit.keyPressEvent(self.ui.le_cmd,e)
            self.ui.le_cmd.widgetObject.keyPressEvent(self.ui.le_cmd, e)

    def setCommandText(self, text):
        self.ui.le_cmd.setText(text)
        if self.ui.le_cmd.type == 'qscintilla':
            self.ui.le_cmd.setCursorPosition(0, len(text))

    def readline(self):
        """
        Simulate stdin, stdout, and stderr.
        """
        self.reading = 1
        self.ui.le_cmd.setText('')
        self.ui.l_prompt.setText('?')
        ##        self.moveCursor(QtGui.QTextCursor.End, 0)
        while self.reading:
            QtGui.QApplication.processEvents()
        line = self.ui.le_cmd.text()

        if len(line) == 0:
            return_line = '\n'
        else:
            return_line = str(line)
        self.write('\n')
        return return_line

    def writelines(self, text):
        """
        Simulate stdin, stdout, and stderr.
        """
        map(self.write, text)

    def flush(self):
        """
        Simulate stdin, stdout, and stderr.
        """
        pass

    def isatty(self):
        """
        Simulate stdin, stdout, and stderr.
        """
        return 1

    #---Output Overrides
    def tb_out_keypress(self, e):
        key = e.key()
        handled = 0

        # Copy ahead of disable
        if e.modifiers() & QtCore.Qt.ControlModifier:
            # Copy
            if key == Qt.Key_C:
                txt = str(self.ui.tb_view.textCursor().selectedText().toUtf8()
                          ).replace('\xc2\xa0', ' ').decode('utf-8')
                ##                QtGui.QApplication.clipboard().clear()
                ntxt = []
                for ln in txt.splitlines():
                    t = ln
                    if ln.startswith('>>> ') or ln.startswith('... '):
                        t = ln[4:]
                    ntxt.append(t)
                txt = '\n'.join(ntxt)
                QtGui.QApplication.clipboard().setText(txt)
                handled = 1

        if not handled:
            QtGui.QTextEdit.keyPressEvent(self.ui.tb_view, e)
class ToolbarBehaviour_MDL(StateMachine):

  # Constants for this model
  StateNum=3
  EventNames=["(create)*",
              "<Any-ButtonRelease-1>",
              "[Done]" 
             ]
  StateNames=["Default",
              "Do Layout*",
              "Idle" 
             ]
  ParentTable=[-1,  # Default -- parent (None)
               -1,  # Do Layout* -- parent (None)
               -1   # Idle -- parent (None)
              ]
  HistoryStateTable=[0,
                     0,
                     0 
                    ]
  LeafStateTable=["Default",
                  "Do Layout*",
                  "Idle" 
                 ]
  OrthogonalInBetween=[[0, 0, 0],
                       [0, 0, 0],
                       [0, 0, 0],
                       [0, 0, 0] 
                      ]
  OrthogonalTable=[[0, 0, 0],
                   [0, 0, 0],
                   [0, 0, 0] 
                  ]
  IntervalTable=[None,
                 None,
                 None 
                ]
  RescheduleTable=[-1,
                   -1,
                   -1 
                  ]
  Hierarchy=[[0, 0, 0],  # substates of state Default
             [0, 0, 0],  # substates of state Do Layout*
             [0, 0, 0]   # substates of state Idle
            ]
  CommonStateTable=[[-1, -1, -1],
                    [-1, -1, -1],
                    [-1, -1, -1] 
                   ]
  Description=None

  ##Lock=thread.allocate_lock()
  CurrentModel=None

  def __init__(self, Interpreter=None, Parent=None, OldInstance=None):

    # Variables
    self.Parent=Parent
    self.HistoryCount=0
    self.state=None
    self.BackState=None
    if OldInstance!=None:
      self.Submodels=OldInstance.Submodels
    else:
      self.Submodels=[]
      for i in range(ToolbarBehaviour_MDL.StateNum):
        self.Submodels.append(None)
    self.history=[]
    for i in range(ToolbarBehaviour_MDL.StateNum):
      self.history.append(None)

    # Constructor
    for i in range(ToolbarBehaviour_MDL.StateNum):
      self.history[i]=History()
      self.history[i].States=[]
      self.history[i].Times=[]
      for j in range(ToolbarBehaviour_MDL.StateNum):
        self.history[i].States.append(-1)
        self.history[i].Times.append(-1)

    self.TimedTransitions=[] # used only when --ext is set
    for i in range(ToolbarBehaviour_MDL.StateNum):
      self.TimedTransitions.append(None)

    self.clearEnteredStates()
    self.HasInteractor=0

    # Interpreter of action code
    if self.Parent==None:  # Top-level model
      if Interpreter:
        self.DefaultInterpreter=Interpreter
      else:
        self.DefaultInterpreter=InteractiveInterpreter()
      self.setupInterpreter()

      ##self.EventsCond=threading.Condition()
      ##self.SchedulerCond=threading.Condition()
      self.Schedules=[]
      self.PendingEvents=None
      self.PendingEventsTail=None
    else:
      self.DefaultInterpreter=Interpreter
    self.Started=0
    self.Stopped=0

    self.description=ToolbarBehaviour_MDL.Description

  # Methods
  def isParent(self, sp, sc):

    return sc>=0 and (sp<0 or ToolbarBehaviour_MDL.Hierarchy[sp][sc])

  def isInState(self, s, check_substate=1, use_backup=1):

    if isinstance(s, int):
      if use_backup:
        st=self.BackState
      else:
        st=self.state
      while st!=None:
        if st.StateID==s or (check_substate and self.isParent(s, st.StateID)):
          return 1
        else:
          st=st.Next
      return 0

    elif isinstance(s, str):
      i=0
      while i<ToolbarBehaviour_MDL.StateNum:
        if s==ToolbarBehaviour_MDL.StateNames[i]:
          return self.isInState(i, check_substate, use_backup)
        i=i+1
      i=0
      while i<ToolbarBehaviour_MDL.StateNum:
        stname=ToolbarBehaviour_MDL.StateNames[i]
        if self.Submodels[i]!=None and startsWith(s, stname+"."):
          pos=len(stname)+1
          SubmodelState=s[pos:]
          return self.isInState(i, 0, use_backup) and self.Submodels[i].isInState(SubmodelState, check_substate, use_backup);
        i=i+1
      return 0

    else:
      return 0

  class main_callable:
    def __call__(self, argv):
      model=ToolbarBehaviour_MDL()
      cmd=""
      model.initModel()
      if model.HasInteractor:
        model.runInteractor()
      else:
        ##cond=thread.allocate_lock()
        while cmd!="exit":
          sys.__stdout__.write(model.getCurrentState()+" > ")
          cmd=string.strip(sys.__stdin__.readline())
          if cmd=="exit":
            break
          if not model.Stopped:
            ##cond.acquire()
            ##model.event(cmd, [], cond)
            model.event(cmd, [])
            ##cond.acquire()
            ##cond.release()
      model.runFinalizer()
  main=main_callable()

  def initModel(self, run_initializer=1, run_enter_actions=1, TkInstance = None ):

    self.clearEnteredStates()
    if self.Parent==None and ToolbarBehaviour_MDL.Description!=None:
      sys.__stdout__.write(ToolbarBehaviour_MDL.Description+"\n")
    self.addInState(0) # init state "Default"
    self.recordEnteredState(0)
    if run_initializer:
      self.runInitializer()
    if not self.HasInteractor:
      self.start(None, run_enter_actions, TkInstance )

  def applyMask(self, mask, dest):

    i=0
    while i<ToolbarBehaviour_MDL.StateNum:
      dest[i]=dest[i] and mask[i]
      i=i+1

  def handleEvent(self, se, params=[], cond=None, scheduler=None):

    if not self.Started:
      if cond:
        cond.release()
      return 0
    self.params=params
    handled=0
    table=[]
    i=0
    while i<ToolbarBehaviour_MDL.StateNum:
      table.append(1)
      i=i+1
    if self.state:
      self.BackState=self.state.copy()
    else:
      self.BackState=None
    e=self.eventStr2Int(se)
    if e==0: # event "(create)*"
      if table[0] and self.isInState(0) and self.testCondition(0):
        if (scheduler==self or scheduler==None) and table[0]:
          self.runActionCode(2) # output action(s)
          self.runExitActionsForStates(-1)
	  self.clearEnteredStates()
          self.changeState(0, 2)
          self.runEnterActionsForStates(self.StatesEntered, 1)
          self.applyMask(ToolbarBehaviour_MDL.OrthogonalTable[0], table)
          handled=1
    elif e==1: # event "<Any-ButtonRelease-1>"
      if table[2] and self.isInState(2) and self.testCondition(1):
        if (scheduler==self or scheduler==None) and table[2]:
          self.runExitActionsForStates(-1)
	  self.clearEnteredStates()
          self.changeState(2, 1)
          self.runEnterActionsForStates(self.StatesEntered, 1)
          self.applyMask(ToolbarBehaviour_MDL.OrthogonalTable[2], table)
          handled=1
    elif e==2: # event "[Done]"
      if table[1] and self.isInState(1) and self.testCondition(2):
        if (scheduler==self or scheduler==None) and table[1]:
          self.runExitActionsForStates(-1)
	  self.clearEnteredStates()
          self.changeState(1, 2)
          self.runEnterActionsForStates(self.StatesEntered, 1)
          self.applyMask(ToolbarBehaviour_MDL.OrthogonalTable[1], table)
          handled=1
    if cond and self.Parent==None:  # Top-level model
      cond.release()
    if not handled and e>=0 and (scheduler==self or scheduler==None) and ToolbarBehaviour_MDL.RescheduleTable[e]>=0:
      self.addSchedule(ToolbarBehaviour_MDL.RescheduleTable[e], ToolbarBehaviour_MDL.IntervalTable[e], ToolbarBehaviour_MDL.EventNames[e], scheduler)
    return handled

  def forceIntoState(self, s):

    changed=0
    s2=self.state
    while s2!=None:
      HasCommonParent=0
      for i in range(ToolbarBehaviour_MDL.StateNum):
        if self.isParent(i, s2.StateID) and self.isParent(i, s):
          HasCommonParent=1
          if not self.hasOrthogonalStateInBetween(i, s2.StateID):
            self.changeState(s2.StateID, s)
            changed=1
      if not HasCommonParent:
        self.changeState(s2.StateID, s)
        changed=1
      s2=s2.Next
    if not changed:
      self.addInState(s)

  def changeState(self, s1, s2, check_history=0, top_level=0):

    # t1=common(s1, s2)
    t1=ToolbarBehaviour_MDL.CommonStateTable[s1][s2]
    self.recordHistory(t1)
    if t1>=0:
      self.removeOutStates(t1)
    else:
      self.state=None
    # t2=history(s2)
    t2=ToolbarBehaviour_MDL.HistoryStateTable[s2]
    if t2==0: # no history
      self.generateStates(t1, s2)
    elif t2==1: # normal history
      if not check_history:
        self.generateStates(t1, s2)
      elif self.hasHistoryRecorded(s2) and self.Submodels[s2]==None:
        self.generateStates(t1, self.history[s2].States[s2])
      else:
        self.generateStates(t1, s2, 1)
    elif t2==2: # deep history
      if check_history and self.hasHistoryRecorded(s2):
        if self.Submodels[s2]:
          self.recordEnteredState(s2, 1, 1, t1)
          self.addInState(s2)
        else:
          for i in range(ToolbarBehaviour_MDL.StateNum):
            hs=self.history[s2].States[i]
            if hs>=0 and self.isLeafState(hs):
              self.recordEnteredState(hs, 1, 1, t1)
              self.addInState(hs)
      else:
        self.generateStates(t1, s2)

  def addInState(self, s):

    if not self.isInState(s, 1, 0):
      st=State()
      st.StateID=s
      st.Next=self.state
      self.state=st
      return 1
    else:
      return 0

  def generateStates(self, common, dest, history_type=0):

    if common==-1:
      if dest==0:
        if history_type!=2 or self.check_history(-1):
          if history_type!=2 or self.check_history(0):
            self.recordEnteredState(0)
            self.addInState(0)  # move into leaf state "Default"
      elif dest==1:
        if history_type!=2 or self.check_history(-1):
          if history_type!=2 or self.check_history(1):
            self.recordEnteredState(1)
            self.addInState(1)  # move into leaf state "Do Layout*"
      elif dest==2:
        if history_type!=2 or self.check_history(-1):
          if history_type!=2 or self.check_history(2):
            self.recordEnteredState(2)
            self.addInState(2)  # move into leaf state "Idle"
    elif common==0:
      if dest==0:
        if history_type!=2 or self.check_history(0):
          self.addInState(0)  # move into leaf state "Default"
    elif common==1:
      if dest==1:
        if history_type!=2 or self.check_history(1):
          self.addInState(1)  # move into leaf state "Do Layout*"
    elif common==2:
      if dest==2:
        if history_type!=2 or self.check_history(2):
          self.addInState(2)  # move into leaf state "Idle"

  def removeOutStates(self, common_state):

    s=self.state
    prev=None
    while s!=None:
      if self.isParent(common_state, s.StateID):
        if prev==None:
          self.state=self.state.Next
        else:
          prev.Next=s.Next
      else:
        prev=s
      s=s.Next

  def eventStr2Int(self, event):

    for i in range(3):
      if event==ToolbarBehaviour_MDL.EventNames[i]:
        return i
    return -1

  def stateInt2Str(self, state):

    if state==-1:
      return ""
    else:
      return ToolbarBehaviour_MDL.StateNames[state]

  def getCurrentStateList(self):

    sl=StringList()
    slend=sl
    s=self.state
    while s!=None:
      sm=self.Submodels[s.StateID]
      curstate=self.stateInt2Str(s.StateID)
      if sm!=None:
        slend.Next=sm.getCurrentStateList()
        while slend.Next!=None:
          slend.Next.str=curstate+"."+slend.Next.str
          slend=slend.Next
      else:
        slend.Next=StringList(curstate)
        slend=slend.Next
      s=s.Next
    return sl.Next

  def getCurrentState(self, states=None):

    if states==None:
      states=self.getCurrentStateList()
      if states!=None:
        states=states.sort()
        strst="['%s'%s]" % (states.str, self.getCurrentState(states))
      else:
        strst="[]"
    else:
      if states.Next:
        strst=", '%s'%s" % (states.Next.str, self.getCurrentState(states.Next))
      else:
        strst=""
    return strst

  def getParentState(self, state):

    return ToolbarBehaviour_MDL.ParentTable[state]

  def getSubstates(self, state):

    substates=None
    if state==-1: # substates of ""
      # add substate "Default"
      st=IntList()
      st.int=0
      st.Next=substates
      substates=st
      # add substate "Do Layout*"
      st=IntList()
      st.int=1
      st.Next=substates
      substates=st
      # add substate "Idle"
      st=IntList()
      st.int=2
      st.Next=substates
      substates=st
    elif state==0: # substates of "Default"
      pass
    elif state==1: # substates of "Do Layout*"
      pass
    elif state==2: # substates of "Idle"
      pass
    return substates

  def isHistoryState(self, state):

    return ToolbarBehaviour_MDL.HistoryStateTable[state]>0

  def isLeafState(self, state):

    if isinstance(state, int):
      return ToolbarBehaviour_MDL.LeafStateTable[state]!=None

    elif isinstance(state, str):
      for i in range(ToolbarBehaviour_MDL.StateNum):
        if ToolbarBehaviour_MDL.LeafStateTable[i]==None:
          continue
        if state==ToolbarBehaviour_MDL.LeafStateTable[i] and self.Submodels[i]==None:
          return 1
        elif startsWith(state, ToolbarBehaviour_MDL.LeafStateTable[i]+".") and self.Submodels[i]!=None:
          SubmodelState=state[ToolbarBehaviour_MDL.LeafStateTable[i].length()+1:]
          return self.Submodels[i].isLeafState(SubmodelState)
    return 0

  def isHistoryUp2Date(self, state, time):

    for i in range(ToolbarBehaviour_MDL.StateNum):
      if self.history[state].Times[i]>=time:
        return 1
    return 0

  def mergeHistory(self, state, states, times):

    max=-1
    for i in range(ToolbarBehaviour_MDL.StateNum):
      if times[i]>max:
        max=times[i]
    if self.isHistoryUp2Date(state, max):
      for i in range(ToolbarBehaviour_MDL.StateNum):
        if times[i]>self.history[state].Times[i]:
          self.history[state].States[i]=states[i]
          self.history[state].Times[i]=times[i]
    else:
      self.history[state].States=copy.copy(states)
      self.history[state].Times=copy.copy(times)

  def recordHistory(self, top_state):

    curtime=self.HistoryCount
    self.HistoryCount=self.HistoryCount+1
    s=self.state
    while s!=None:
      child=s.StateID
      states=[]
      times=[]
      for i in range(ToolbarBehaviour_MDL.StateNum):
        states.append(-1)
        times.append(-1)
      states[child]=child
      times[child]=curtime
      if top_state<0 or self.isParent(top_state, child):
        parent=self.getParentState(child)
        if self.isHistoryState(child):
          self.history[child].Submodel=self.Submodels[child]
        while parent>=0 and times[parent]!=curtime:
          states[parent]=child
          times[parent]=curtime
          if self.isHistoryState(parent):
            self.mergeHistory(parent, states, times)
          if parent==top_state:
            break
          child=parent
          parent=self.getParentState(child)
      s=s.Next

  def hasHistoryRecorded(self, state):

    for i in range(ToolbarBehaviour_MDL.StateNum):
      if self.history[state].States[i]!=-1:
        return 1
      if self.Submodels[state]!=None:
        return 1
    return 0

  def hasOrthogonalStateInBetween(self, parent, leaf):

    return ToolbarBehaviour_MDL.OrthogonalInBetween[parent+1][leaf]

  def check_history(self, dest):

    s=self.state
    while s!=None:
      if self.isParent(dest, s.StateID) and not self.hasOrthogonalStateInBetween(dest, s.StateID):
        return 0
      s=s.Next
    return 1

  def getEnabledEvents(self):

    events=EventList()
    if self.isInState(0):
      events.Append("(create)*")
    if self.isInState(2):
      events.Append("<Any-ButtonRelease-1>")
    if self.isInState(1):
      events.Append("[Done]")
    return events.Next

  def getHierarchy(self, start_level, state_prefix):

    h=Hierarchy()
    lasth=h
    # Generate state "Default" in the hierarchy table
    lasth.Next=Hierarchy()
    lasth.Next.StateName="Default"
    if state_prefix==None:
      lasth.Next.PathName="Default"
    else:
      lasth.Next.PathName=state_prefix+".Default"
    lasth.Next.StateNum=0
    lasth.Next.Level=start_level+0
    lasth=lasth.Next
    # Generate state "Do Layout*" in the hierarchy table
    lasth.Next=Hierarchy()
    lasth.Next.StateName="Do Layout*"
    if state_prefix==None:
      lasth.Next.PathName="Do Layout*"
    else:
      lasth.Next.PathName=state_prefix+".Do Layout*"
    lasth.Next.StateNum=1
    lasth.Next.Level=start_level+0
    lasth=lasth.Next
    # Generate state "Idle" in the hierarchy table
    lasth.Next=Hierarchy()
    lasth.Next.StateName="Idle"
    if state_prefix==None:
      lasth.Next.PathName="Idle"
    else:
      lasth.Next.PathName=state_prefix+".Idle"
    lasth.Next.StateNum=2
    lasth.Next.Level=start_level+0
    lasth=lasth.Next
    return h.Next

  def topLevelHistory(self):

    s=self.state.StateID
    t=self.getParentState(s)
    while t!=-1:
      s=t
      t=self.getParentState(s)
    self.changeState(s, s)

  def runActionCode(self, code_num):

    if code_num==0: # model finalizer
      pass
    elif code_num==1: # model initializer
      pass
    elif code_num==2: # output action(s) of a transition
      self.runCode("self = eventhandler.get_event_params()")
      self.runCode("atom3i = self.parent")
      self.runCode("cb = atom3i.cb")
    elif code_num==3: # enter actions for state "Do Layout*"
       self.runCode("from FSB_Code.Layout import toolbarLayout")
       self.runCode("toolbarLayout(self)")
       self.runCode("eventhandler.event(\'[Done]\')")

  def testCondition(self, cond_num):

    if cond_num==0 and \
       eval("(1)", self.DefaultInterpreter.locals):
      return 1
    elif cond_num==1 and \
       eval("(1)", self.DefaultInterpreter.locals):
      return 1
    elif cond_num==2 and \
       eval("(1)", self.DefaultInterpreter.locals):
      return 1
    return 0

  def runEnterActions(self, state):

    if state==1: # enter action(s) for state "Do Layout*"
      self.runActionCode(3)

  def runExitActions(self, state):

    pass

  def compareSchedule(self, sched_a, sched_b):

    return cmp(sched_a[1], sched_b[1])

  def addSchedule(self, id, interval, event, scheduler):

    if self.Parent!=None:  # Non-top-level model
      self.Parent.addSchedule(id, interval, event, scheduler)
      return
    f=eval(interval, self.DefaultInterpreter.locals)
    ##self.SchedulerCond.acquire()
    t=time.time()+f
    s=[id, t, interval, event, scheduler]
    self.Schedules.append(s)
    self.Schedules.sort(self.compareSchedule)
    ##self.SchedulerCond.notify()
    ##self.SchedulerCond.release()

  def removeSchedule(self, id, scheduler):

    if self.Parent!=None:  # Non-top-level model
      self.Parent.removeSchedule(id, scheduler)
      return
    ##self.SchedulerCond.acquire()
    i=0
    while i<len(self.Schedules):
      if self.Schedules[i][0]==id and self.Schedules[i][4]==scheduler:
        del self.Schedules[i]
      else:
        i=i+1
    ##self.SchedulerCond.release()

  def scheduler(self):

    if( not self.Schedules): return

    while( self.Schedules and self.Schedules[0][1]<=time.time()):
      this_sched=self.Schedules[0]
      del self.Schedules[0]
      self.event(this_sched[3], [], None, this_sched[4])

    if self.Schedules:
      t=self.Schedules[0][1]-time.time()

  def recordAllEnteredStates(self):

    st=self.state
    while st!=None:
      self.recordEnteredState(st.StateID, 1, 1)
      st=st.Next

  def recordEnteredState(self, s, superstates=0, submodel=0, commonstate=-1):

    # test if s is already recorded
    se=self.StatesEntered
    found=0
    while se!=None:
      if se.int==s:
        found=1
        break
      se=se.Next

    if not found:
      if superstates:
        parent=self.getParentState(s)
        if parent>=0 and parent!=commonstate:
          self.recordEnteredState(parent, 1, 0, commonstate)
      st=IntList()
      st.Next=self.StatesEntered
      st.int=s
      self.StatesEntered=st
      if submodel and self.Submodels[s]:
        self.Submodels[s].recordAllEnteredStates()

  def runAllEnterActions(self):

    self.runEnterActionsForStates(self.StatesEntered, 1)

  def runEnterActionsForStates(self, states, recursive=0):

    if states:
      self.runEnterActionsForStates(states.Next, 0)
      self.runEnterActions(states.int)
    if recursive:
      for s in self.Submodels:
        if s:
          s.runAllEnterActions()

  def runExitActionsForStates(self, common_state):

    substates=self.getSubstates(common_state)
    if substates==None:
      s=self.state
      while s!=None and s.StateID!=common_state:
        s=s.Next
      if s!=None and self.Submodels[s.StateID]:
        self.Submodels[s.StateID].runExitActionsForStates(-1)
      return s!=None
    else:
      has_current_substate=0
      while substates!=None:
        res=self.runExitActionsForStates(substates.int)
        has_current_substate=has_current_substate or res
        if res:
          self.runExitActions(substates.int)
        substates=substates.Next
      return has_current_substate

  def runInitializer(self):

    self.runActionCode(1)
    for s in self.Submodels:
      if s:
        s.runInitializer()

  def runFinalizer(self):

    if self.Started:
      self.Started=0
      for s in self.Submodels:
        if s:
          s.runFinalizer()
      self.runActionCode(0)
      if self.Parent==None:  # Top-level model
        ##self.EventsCond.acquire()
        ##self.SchedulerCond.acquire()
        self.Stopped=1
        ##self.EventsCond.notify()
        ##self.SchedulerCond.notify()
        ##self.SchedulerCond.release()
        ##self.EventsCond.release()
      else:
        self.Stopped=1

  def clearEnteredStates(self):

    self.StatesEntered=None
    for s in self.Submodels:
      if s:
        s.clearEnteredStates()

  def get_current_state(self):

    return self.getCurrentState()

  def runCode(self, c):

    self.DefaultInterpreter.runsource(c+"\n", "<input>", "exec")

  def setupInterpreter(self):

    self.DefaultInterpreter.locals["eventhandler"]=self
    self.DefaultInterpreter.locals["dump_message"]=self.dump_message

  def get_event_params(self):

    return self.params

  def dump_message(self, msg):

    print msg

  def is_in_state(self, s, check_substate=1):

    return self.isInState(s, check_substate)

  def start(self, lock=None, run_enter_actions=1, TkInstance = None):

    if self.Parent==None:  # Top-level model
      if run_enter_actions:
        self.runEnterActionsForStates(self.StatesEntered, 1)
      self.Started=1
      
      if( TkInstance ):
        self.sleepMethod = TkInstance.after 
        startTkMainloop = False
      else:
        import Tkinter
        TkInstance = Tkinter.Tk()
        self.sleepMethod = TkInstance.after 
        startTkMainloop = True
      
      self.pollingStation() 
      ##thread.start_new_thread(self.handleEvent_wrapper, ())
      ##thread.start_new_thread(self.scheduler, ())
      ## if lock:
        ## lock.release()
    else:
      self.Started=1
    for submodel in self.Submodels:
      if submodel!=None:
        submodel.start()

    if( self.Parent==None and startTkMainloop == None ): TkInstance.mainloop()

  def pollingStation(self):

    self.sleepMethod( 100, self.pollingStation )
    if self.Stopped: return 
    #self.handleEvent_wrapper()
    self.scheduler()
    #todo: pollingStation\,
  def shutdown(self):

    pass

  def handleEvent_wrapper(self):

    if( self.PendingEvents==None ): return
    event=self.PendingEvents
    self.PendingEvents=self.PendingEvents.Next
    if self.PendingEvents==None:
      self.PendingEventsTail=None
    event.next=None
    self.handleEvent(event.Event[0], event.Event[1], event.Event[2], event.Event[3])
    self.handleEvent_wrapper()

  def event(self, e, params=[], cond=None, scheduler=None):

    ev=EventList()
    ev.Event=[e, params, cond, scheduler]
    if self.PendingEventsTail!=None:
      self.PendingEventsTail.Next=ev
    else:
      self.PendingEvents=ev
    self.PendingEventsTail=ev
    self.handleEvent_wrapper()
Esempio n. 45
0
 def runsource(self, source):
     # Extend base class to stuff the source in the line cache first
     filename = self.stuffsource(source)
     self.more = 0
     return InteractiveInterpreter.runsource(self, source, filename)
class behaviour_generated_no_link_with_gui(StateMachine):

  # Constants for this model
  StateNum=4
  EventNames=["__INTERNAL_0_TIME_0",
              "press" 
             ]
  StateNames=["Disabled",
              "Enabled",
              "Enabled.Green",
              "Enabled.Red" 
             ]
  ParentTable=[-1,  # Disabled -- parent (None)
               -1,  # Enabled -- parent (None)
               1,  # Enabled.Green -- parent Enabled
               1   # Enabled.Red -- parent Enabled
              ]
  HistoryStateTable=[0,
                     0,
                     0,
                     0 
                    ]
  LeafStateTable=["Disabled",
                  None,
                  "Enabled.Green",
                  "Enabled.Red" 
                 ]
  OrthogonalInBetween=[[0, 0, 0, 0],
                       [0, 0, 0, 0],
                       [0, 0, 0, 0],
                       [0, 0, 0, 0],
                       [0, 0, 0, 0] 
                      ]
  Hierarchy=[[0, 0, 0, 0],  # substates of state Disabled
             [0, 0, 1, 1],  # substates of state Enabled
             [0, 0, 0, 0],  # substates of state Enabled.Green
             [0, 0, 0, 0]   # substates of state Enabled.Red
            ]
  CommonStateTable=[[0, -1, -1, -1],
                    [-1, 1, 1, 1],
                    [-1, 1, 2, 1],
                    [-1, 1, 1, 3] 
                   ]
  Description=None

  # used only when --pyext is set
  Lock=thread.allocate_lock()
  CurrentModel=None

  def __init__(self, Interpreter=None):

    # Variables
    self.state=None
    self.Submodels=[]
    for i in range(behaviour_generated_no_link_with_gui.StateNum):
      self.Submodels.append(None)
    self.history=[]
    for i in range(behaviour_generated_no_link_with_gui.StateNum):
      self.history.append(None)

    self.TimedTransitions=[] # used only when --pyext is set
    for i in range(behaviour_generated_no_link_with_gui.StateNum):
      self.TimedTransitions.append(None)

    self.clearEnteredStates()

    # Constructor
    for i in range(behaviour_generated_no_link_with_gui.StateNum):
      self.history[i]=History()
      self.history[i].States=[]
      self.history[i].Times=[]
      for j in range(behaviour_generated_no_link_with_gui.StateNum):
        self.history[i].States.append(-1)
        self.history[i].Times.append(-1)

    # Interpreter of action code
    if Interpreter:
      self.DefaultInterpreter=Interpreter
    else:
      self.DefaultInterpreter=InteractiveInterpreter()
    self.HasInteractor=0
    self.setupInterpreter()

    self.Started=0

    self.EventsLock=thread.allocate_lock()
    self.PendingEvents=None
    self.PendingEventsTail=None
    self.HandleEventRunning=0

    self.description=behaviour_generated_no_link_with_gui.Description

  # Methods
  def isParent(self, sp, sc):

    return sc>=0 and (sp<0 or behaviour_generated_no_link_with_gui.Hierarchy[sp][sc])

  def isInState(self, s):

    if isinstance(s, int):
      st=self.state
      while st!=None:
        if st.StateID==s or self.isParent(s, st.StateID):
          return 1
        else:
          st=st.Next
      return 0

    elif isinstance(s, str):
      for i in range(behaviour_generated_no_link_with_gui.StateNum):
        if s==behaviour_generated_no_link_with_gui.StateNames[i]:
          return self.isInState(i)
      for i in range(behaviour_generated_no_link_with_gui.StateNum):
        if self.Submodels[i]!=None and startsWith(s, behaviour_generated_no_link_with_gui.StateNames[i]+"."):
          SubmodelState=s[len(behaviour_generated_no_link_with_gui.StateNames[i])+1:]
          return self.isInState(i) and self.Submodels[i].isInState(SubmodelState)
    return 0

  def main(self, argv):

    model=behaviour_generated_no_link_with_gui()
    cmd=""
    model.initModel()
    if model.HasInteractor:
      model.runInteractor()
    else:
      if behaviour_generated_no_link_with_gui.Description:
        sys.__stdout__.write(behaviour_generated_no_link_with_gui.Description+"\n")
      lock=thread.allocate_lock()
      while cmd!="exit":
        sys.__stdout__.write(model.getCurrentState()+" > ")
        cmd=string.strip(sys.__stdin__.readline())
        if cmd=="exit":
          break
        lock.acquire()
        model.event(cmd, [], lock)
        lock.acquire()
        lock.release()
    model.runFinalizer()

  def initModel(self, run_initializer=1, run_enter_actions=1):

    self.clearEnteredStates()
    self.Started=1
    self.addInState(3) # init state "Enabled.Red"
    self.recordEnteredState(1)
    self.recordEnteredState(3)
    self.Started=1
    if run_initializer:
      self.runInitializer()
    if not self.HasInteractor:
      self.start(run_enter_actions)

  def handleEvent(self, se, params=[], lock=None, call_submodels=1):

    if not self.Started:
      if lock:
        lock.release()
      return 0
    e=self.eventStr2Int(se)
    self.EventsLock.acquire()
    self.HandleEventRunning=1
    self.EventsLock.release()
    self.params=params
    if e==0: # event "__INTERNAL_0_TIME_0"
      if self.isInState(1) and self.testCondition(0):
        self.runExitActionsForStates(-1)
	self.clearEnteredStates()
        self.changeState(1, 0)
        self.runEnterActionsForStates(self.StatesEntered, 1)
        if lock:
          lock.release()
        self.checkPendingEvents()
        return 1
    elif e==1: # event "press"
      if self.isInState(3) and self.testCondition(1):
        self.runExitActionsForStates(1)
	self.clearEnteredStates()
        self.changeState(3, 2)
        self.runEnterActionsForStates(self.StatesEntered, 1)
        if lock:
          lock.release()
        self.checkPendingEvents()
        return 1
      if self.isInState(2) and self.testCondition(2):
        self.runExitActionsForStates(1)
	self.clearEnteredStates()
        self.changeState(2, 3)
        self.runEnterActionsForStates(self.StatesEntered, 1)
        if lock:
          lock.release()
        self.checkPendingEvents()
        return 1
    if lock:
      lock.release()
    self.checkPendingEvents()
    return 0

  def forceIntoState(self, s):

    changed=0
    s2=self.state
    while s2!=None:
      HasCommonParent=0
      for i in range(behaviour_generated_no_link_with_gui.StateNum):
        if self.isParent(i, s2.StateID) and self.isParent(i, s):
          HasCommonParent=1
          if not self.hasOrthogonalStateInBetween(i, s2.StateID):
            self.changeState(s2.StateID, s)
            changed=1
      if not HasCommonParent:
        self.changeState(s2.StateID, s)
        changed=1
      s2=s2.Next
    if not changed:
      self.addInState(s)

  def changeState(self, s1, s2, check_history=0, top_level=0):

    # t1=common(s1, s2)
    t1=behaviour_generated_no_link_with_gui.CommonStateTable[s1][s2]
    self.recordHistory(t1)
    if t1>=0:
      self.removeOutStates(t1)
    else:
      self.state=None
    # t2=history(s2)
    t2=behaviour_generated_no_link_with_gui.HistoryStateTable[s2]
    if t2==0: # no history
      self.generateStates(t1, s2)
    elif t2==1: # normal history
      if not check_history:
        self.generateStates(t1, s2)
      elif self.hasHistoryRecorded(s2):
        self.generateStates(t1, self.history[s2].States[s2])
      else:
        self.generateStates(t1, s2, 1)
    elif t2==2: # deep history
      if check_history and self.hasHistoryRecorded(s2):
        for i in range(behaviour_generated_no_link_with_gui.StateNum):
          hs=self.history[s2].States[i]
          if hs>=0 and self.isLeafState(hs):
            # used only when --pyext is set
            self.recordEnteredState(hs, 1, 1, t1)
            self.addInState(hs)
      else:
        self.generateStates(t1, s2)

  def recordEnteredState(self, s, superstates=0, submodel=0, commonstate=-1):

    # test is s is already recorded
    se=self.StatesEntered
    found=0
    while se!=None:
      if se.int==s:
        found=1
        break
      se=se.Next

    if not found:
      if superstates:
        parent=self.getParentState(s)
        if parent>=0 and parent!=commonstate:
          self.recordEnteredState(parent, 1)
      st=IntList()
      st.Next=self.StatesEntered
      st.int=s
      self.StatesEntered=st
      if submodel and self.Submodels[s]:
        mdl=self.Submodels[s]
        st=mdl.state
        while st!=None:
          mdl.recordEnteredState(st.StateID, 1, 1)
          st=st.Next

  def addInState(self, s):
    if not self.isInState(s):
      st=State()
      st.StateID=s
      st.Next=self.state
      self.state=st
      return 1
    else:
      return 0

  def generateStates(self, common, dest, history_type=0):

    if common==-1:
      if dest==0:
        if history_type!=2 or self.check_history(-1):
          if history_type!=2 or self.check_history(0):
            self.recordEnteredState(0)
            self.addInState(0)  # move into leaf state "Disabled"
      elif dest==1:
        if history_type!=2 or self.check_history(-1):
          if history_type!=2 or self.check_history(1):
            self.recordEnteredState(1)
            if history_type!=2 or self.check_history(3):
              self.recordEnteredState(3)
              self.addInState(3)  # move into leaf state "Enabled.Red"
      elif dest==2:
        if history_type!=2 or self.check_history(-1):
          if history_type!=2 or self.check_history(1):
            self.recordEnteredState(1)
            if history_type!=2 or self.check_history(2):
              self.recordEnteredState(2)
              self.addInState(2)  # move into leaf state "Enabled.Green"
      elif dest==3:
        if history_type!=2 or self.check_history(-1):
          if history_type!=2 or self.check_history(1):
            self.recordEnteredState(1)
            if history_type!=2 or self.check_history(3):
              self.recordEnteredState(3)
              self.addInState(3)  # move into leaf state "Enabled.Red"
    elif common==0:
      if dest==0:
        if history_type!=2 or self.check_history(0):
          self.addInState(0)  # move into leaf state "Disabled"
    elif common==1:
      if dest==1:
        if history_type!=2 or self.check_history(1):
          if history_type!=2 or self.check_history(3):
            self.recordEnteredState(3)
            self.addInState(3)  # move into leaf state "Enabled.Red"
      elif dest==2:
        if history_type!=2 or self.check_history(1):
          if history_type!=2 or self.check_history(2):
            self.recordEnteredState(2)
            self.addInState(2)  # move into leaf state "Enabled.Green"
      elif dest==3:
        if history_type!=2 or self.check_history(1):
          if history_type!=2 or self.check_history(3):
            self.recordEnteredState(3)
            self.addInState(3)  # move into leaf state "Enabled.Red"
    elif common==2:
      if dest==2:
        if history_type!=2 or self.check_history(2):
          self.addInState(2)  # move into leaf state "Enabled.Green"
    elif common==3:
      if dest==3:
        if history_type!=2 or self.check_history(3):
          self.addInState(3)  # move into leaf state "Enabled.Red"

  def removeOutStates(self, common_state):

    s=self.state
    prev=None
    while s!=None:
      if self.isParent(common_state, s.StateID):
        if prev==None:
          self.state=self.state.Next
        else:
          prev.Next=s.Next
      else:
        prev=s
      s=s.Next

  def eventStr2Int(self, event):

    for i in range(2):
      if event==behaviour_generated_no_link_with_gui.EventNames[i]:
        return i
    return -1

  def stateInt2Str(self, state):

    if state==-1:
      return ""
    else:
      return behaviour_generated_no_link_with_gui.StateNames[state]

  def getCurrentStateList(self):

    sl=StringList()
    slend=sl
    s=self.state
    while s!=None:
      sm=self.Submodels[s.StateID]
      curstate=self.stateInt2Str(s.StateID)
      if sm!=None:
        slend.Next=sm.getCurrentStateList()
        while slend.Next!=None:
          slend.Next.str=curstate+"."+slend.Next.str
          slend=slend.Next
      else:
        slend.Next=StringList(curstate)
        slend=slend.Next
      s=s.Next
    return sl.Next

  def getCurrentState(self, states=None):

    if states==None:
      states=self.getCurrentStateList()
      if states!=None:
        strst="[%s'%s']" % (self.getCurrentState(states), states.str)
      else:
        strst="[]"
    else:
      if states.Next:
        strst="%s'%s', " % (self.getCurrentState(states.Next), states.Next.str)
      else:
        strst=""
    return strst

  def getParentState(self, state):

    return behaviour_generated_no_link_with_gui.ParentTable[state]

  def getSubstates(self, state):

    substates=None
    if state==-1: # substates of ""
      # add substate "Disabled"
      st=IntList()
      st.int=0
      st.Next=substates
      substates=st
      # add substate "Enabled"
      st=IntList()
      st.int=1
      st.Next=substates
      substates=st
    elif state==0: # substates of "Disabled"
      pass
    elif state==1: # substates of "Enabled"
      # add substate "Enabled.Green"
      st=IntList()
      st.int=2
      st.Next=substates
      substates=st
      # add substate "Enabled.Red"
      st=IntList()
      st.int=3
      st.Next=substates
      substates=st
    elif state==2: # substates of "Enabled.Green"
      pass
    elif state==3: # substates of "Enabled.Red"
      pass
    return substates

  def isHistoryState(self, state):

    return behaviour_generated_no_link_with_gui.HistoryStateTable[state]>0

  def isLeafState(self, state):

    if isinstance(state, int):
      return behaviour_generated_no_link_with_gui.LeafStateTable[state]!=None

    elif isinstance(state, str):
      for i in range(behaviour_generated_no_link_with_gui.StateNum):
        if behaviour_generated_no_link_with_gui.LeafStateTable[i]==None:
          continue
        if state==behaviour_generated_no_link_with_gui.LeafStateTable[i] and self.Submodels[i]==None:
          return 1
        elif startswith(state, behaviour_generated_no_link_with_gui.LeafStateTable[i]+".") and self.Submodels[i]!=None:
          SubmodelState=state[behaviour_generated_no_link_with_gui.LeafStateTable[i].length()+1:]
          return self.Submodels[i].isLeafState(SubmodelState)
    return 0

  def isHistoryUp2Date(self, state, time):

    for i in range(behaviour_generated_no_link_with_gui.StateNum):
      if self.history[state].Times[i]>=time:
        return 1
    return 0

  def mergeHistory(self, state, states, times):

    max=-1
    for i in range(behaviour_generated_no_link_with_gui.StateNum):
      if times[i]>max:
        max=times[i]
    if self.isHistoryUp2Date(state, max):
      for i in range(behaviour_generated_no_link_with_gui.StateNum):
        if times[i]>self.history[state].Times[i]:
          self.history[state].States[i]=states[i]
          self.history[state].Times[i]=times[i]
    else:
      self.history[state].States=copy.copy(states)
      self.history[state].Times=copy.copy(times)

  def recordHistory(self, top_state):

    curtime=time.time();
    s=self.state;
    while s!=None:
      child=s.StateID
      states=[]
      times=[]
      for i in range(behaviour_generated_no_link_with_gui.StateNum):
        states.append(-1)
        times.append(-1)
      states[child]=child
      times[child]=curtime
      if top_state<0 or self.isParent(top_state, child):
        parent=self.getParentState(child)
        if self.isHistoryState(child):
          self.history[child].Submodel=self.Submodels[child]
        while parent!=top_state and times[parent]!=curtime:
          states[parent]=child
          times[parent]=curtime
          if self.isHistoryState(parent):
            self.mergeHistory(parent, states, times)
          child=parent
          parent=self.getParentState(child)
      s=s.Next

  def hasHistoryRecorded(self, state):

    for i in range(behaviour_generated_no_link_with_gui.StateNum):
      if self.history[state].States[i]!=-1:
        return 1
      if self.Submodels[state]!=None:
        return 1
    return 0

  def hasOrthogonalStateInBetween(self, parent, leaf):

    return behaviour_generated_no_link_with_gui.OrthogonalInBetween[parent+1][leaf]

  def check_history(self, dest):

    s=self.state
    while s!=None:
      if self.isParent(dest, s.StateID) and not self.hasOrthogonalStateInBetween(dest, s.StateID):
        return 0
      s=s.Next
    return 1

  def getEnabledEvents(self):

    events=EventList()
    if self.isInState(1):
      events.Append("__INTERNAL_0_TIME_0")
    if self.isInState(3):
      events.Append("press")
    if self.isInState(2):
      events.Append("press")
    return events.Next

  def getHierarchy(self, start_level, state_prefix):

    h=Hierarchy()
    lasth=h
    # Generate state "Disabled" in the hierarchy table
    lasth.Next=Hierarchy()
    lasth.Next.StateName="Disabled"
    if state_prefix==None:
      lasth.Next.PathName="Disabled"
    else:
      lasth.Next.PathName=state_prefix+".Disabled"
    lasth.Next.StateNum=0
    lasth.Next.Level=start_level+0
    lasth=lasth.Next
    # Generate state "Enabled" in the hierarchy table
    lasth.Next=Hierarchy()
    lasth.Next.StateName="Enabled"
    if state_prefix==None:
      lasth.Next.PathName="Enabled"
    else:
      lasth.Next.PathName=state_prefix+".Enabled"
    lasth.Next.StateNum=1
    lasth.Next.Level=start_level+0
    lasth=lasth.Next
    # Generate state "Enabled.Green" in the hierarchy table
    lasth.Next=Hierarchy()
    lasth.Next.StateName="Green"
    if state_prefix==None:
      lasth.Next.PathName="Enabled.Green"
    else:
      lasth.Next.PathName=state_prefix+".Enabled.Green"
    lasth.Next.StateNum=2
    lasth.Next.Level=start_level+1
    lasth=lasth.Next
    # Generate state "Enabled.Red" in the hierarchy table
    lasth.Next=Hierarchy()
    lasth.Next.StateName="Red"
    if state_prefix==None:
      lasth.Next.PathName="Enabled.Red"
    else:
      lasth.Next.PathName=state_prefix+".Enabled.Red"
    lasth.Next.StateNum=3
    lasth.Next.Level=start_level+1
    lasth=lasth.Next
    return h.Next

  def topLevelHistory(self):

    s=self.state.StateID
    t=self.getParentState(s)
    while t!=-1:
      s=t
      t=self.getParentState(s)
    self.changeState(s, s)

  def runActionCode(self, code_num):

    if code_num==0: # model finalizer
      pass
    elif code_num==1: # model initializer
      pass
    elif code_num==2: # enter actions for state "Enabled"
      # a timed transition
      sched=Scheduler(self, "__INTERNAL_0_TIME_0", eval("10", self.DefaultInterpreter.locals), 1)
      sched.Next=self.TimedTransitions[1]
      self.TimedTransitions[1]=sched
      sched.start()
    elif code_num==3: # exit actions for state "Enabled"
      # clean up timed transitions
      if self.TimedTransitions[1]:
        self.TimedTransitions[1].clear()
        self.TimedTransitions[1]=None

  def testCondition(self, cond_num):

    if cond_num==0 and \
       self.DefaultInterpreter.runsource("eventhandler.TestResult=(1)")==0 and self.TestResult:
      return 1
    elif cond_num==1 and \
       self.DefaultInterpreter.runsource("eventhandler.TestResult=(1)")==0 and self.TestResult:
      return 1
    elif cond_num==2 and \
       self.DefaultInterpreter.runsource("eventhandler.TestResult=(1)")==0 and self.TestResult:
      return 1
    return 0

  def runEnterActionsForStates(self, states, recursive=0):

    if states:
      self.runEnterActionsForStates(states.Next, 0)
      self.runEnterActions(states.int)
    if recursive:
      for s in self.Submodels:
        if s:
          s.runEnterActionsForStates(s.StatesEntered, 1)

  def runEnterActions(self, state):

    if state==1: # enter action(s) for state "Enabled"
      self.runActionCode(2)

  def runExitActions(self, state):

    if state==1: # exit action(s) for state "Enabled"
      self.runActionCode(3)

  def runExitActionsForStates(self, common_state):

    substates=self.getSubstates(common_state)
    if substates==None:
      s=self.state
      while s!=None and s.StateID!=common_state:
        s=s.Next
      if s!=None and self.Submodels[s.StateID]:
        self.Submodels[s.StateID].runExitActionsForStates(-1)
      return s!=None
    else:
      has_current_substate=0
      while substates!=None:
        res=self.runExitActionsForStates(substates.int)
        has_current_substate=has_current_substate or res
        if res:
          self.runExitActions(substates.int)
        substates=substates.Next
      return has_current_substate

  def runInitializer(self):

    self.runActionCode(1)
    for s in self.Submodels:
      if s:
        s.runInitializer()

  def runFinalizer(self):
    if self.Started:
      for s in self.Submodels:
        if s:
          s.runFinalizer()
      self.runActionCode(0)
      self.Started=0

  def runInteractor(self):

    pass

  def clearEnteredStates(self):

    self.StatesEntered=None
    for s in self.Submodels:
      if s:
        s.clearEnteredStates()

  def runCode(self, c):
    if len(c)>0:
      l=""
      for i in string.split(c, "\n"):
        if len(l)==0:
          l=i
        elif string.find(i, " ")!=0 and not (string.find(i, "else")==0 and string.strip(i[4:])==":") and \
                               string.find(i, "elif ")!=0 and string.find(i, "elif\t")!=0 and \
                               not (string.find(i, "except")==0 and string.strip(i[6:])==":") and \
                               string.find(i, "except ")!=0 and string.find(i, "except\t")!=0:
          self.DefaultInterpreter.runsource(l+"\n")
          l=i
        else:
          l=l+"\n"+i
      if len(l)>0:
        self.DefaultInterpreter.runsource(l+"\n")

  def setupInterpreter(self):

    self.DefaultInterpreter.locals["eventhandler"]=self
    self.DefaultInterpreter.locals["dump_message"]=self.dump_message

  def start(self, run_enter_actions=1):
    if run_enter_actions:
      self.runEnterActionsForStates(self.StatesEntered, 1)
    self.Started=1
    if run_enter_actions:
      self.checkPendingEvents()

  def event(self, e, params=[], lock=None, call_submodels=1):

    self.EventsLock.acquire()
    running=self.HandleEventRunning
    if not running and self.Started:
      self.HandleEventRunning=1
    self.EventsLock.release()
    if not running:
      thread.start_new_thread(self.handleEvent, (e, params, lock, call_submodels))
    else:
      self.EventsLock.acquire()
      ev=EventList()
      ev.Event=[e, params, lock, call_submodels]
      if self.PendingEventsTail!=None:
        self.PendingEventsTail.Next=ev
      else:
        self.PendingEvents=ev
      self.PendingEventsTail=ev
      self.EventsLock.release()

  def checkPendingEvents(self):

    self.EventsLock.acquire()
    ev=self.PendingEvents
    if ev!=None:
      self.PendingEvents=ev.Next
      if self.PendingEvents==None:
        self.PendingEventsTail=None
    if ev:
      self.EventsLock.release()
      self.handleEvent(ev.Event[0], ev.Event[1], ev.Event[2], ev.Event[3])
    else:
      self.HandleEventRunning=0
      self.EventsLock.release()

  def get_event_params(self):

    return self.params

  def dump_message(self, msg):

    print msg

  def is_in_state(self, state, check_substate=0):

    i=0
    while i<behaviour_generated_no_link_with_gui.StateNum and behaviour_generated_no_link_with_gui.StateNames[i]!=state:
      i=i+1
    if i<behaviour_generated_no_link_with_gui.StateNum:
      return (not check_substate or self.isLeafState(i)) and self.isInState(i)
    else:
      return 0
Esempio n. 47
0
class QShell(QtGui.QTextEdit):
    """This class embeds a python interperter in a QTextEdit Widget
    It is based on PyCute developed by Gerard Vermeulen.
    
    """
    def __init__(self, locals=None, parent=None):
        """Constructor.

        The optional 'locals' argument specifies the dictionary in which code
        will be executed; it defaults to a newly created dictionary with key 
        "__name__" set to "__console__" and key "__doc__" set to None.

        The optional 'log' argument specifies the file in which the interpreter
        session is to be logged.
        
        The optional 'parent' argument specifies the parent widget. If no parent
        widget has been specified, it is possible to exit the interpreter 
        by Ctrl-D.

        """

        QtGui.QTextEdit.__init__(self, parent)
        self.setReadOnly(False)
        self.setWindowTitle("Console")
        # to exit the main interpreter by a Ctrl-D if QShell has no parent
        if parent is None:
            self.eofKey = QtCore.Qt.Key_D
        else:
            self.eofKey = None

        # flag for knowing when selecting text
        self.selectMode = False
        self.interpreter = None
        self.controller = None
        # storing current state
        #this is not working on mac
        #self.prev_stdout = sys.stdout
        #self.prev_stdin = sys.stdin
        #self.prev_stderr = sys.stderr
        # capture all interactive input/output
        #sys.stdout   = self
        #sys.stderr   = self
        #sys.stdin    = self
        
        # user interface setup
        
        self.setAcceptRichText(False)
        self.setWordWrapMode(QtGui.QTextOption.WrapAnywhere)
        
        conf = get_vistrails_configuration()
        shell_conf = conf.shell
        # font
        font = QtGui.QFont(shell_conf.font_face, shell_conf.font_size)
        font.setFixedPitch(1)
        self.setFont(font)
        self.reset(locals)

    def load_package(self, pkg_name):
        reg = vistrails.core.modules.module_registry.get_module_registry()
        package = reg.get_package_by_name(pkg_name)
        
        def create_dict(modules, ns, m, mdesc):
            md = {}
            if len(ns) == 0:
                d = {'_module_desc': mdesc,
                     '_package': pkg,}
                modules[m] = type('module', (vistrails_module,), d)
            else:
                if ns[0] in modules:
                    md = create_dict(modules[ns[0]], ns[1:], m, mdesc)
                else:
                    md = create_dict(md, ns[1:], m, mdesc)
                    modules[ns[0]] = md
            return modules
        
        def create_namespace_path(root, modules):
            for k,v in modules.iteritems():
                if isinstance(v, dict):
                    d = create_namespace_path(k,v)
                    modules[k] = d
            
            if root is not None:
                modules['_package'] = pkg
                return type(root, (object,), modules)()
            else:
                return modules
        
        def get_module_init(module_desc):
            def init(self, *args, **kwargs):
                self.__dict__['module'] = \
                    vistrails.api.add_module_from_descriptor(module_desc)
            return init
        
        def get_module(package):
            def getter(self, attr_name):
                desc_tuple = (attr_name, '')
                if desc_tuple in package.descriptors:
                    module_desc = package.descriptors[desc_tuple]
                    d = {'_module_desc': module_desc,
                         '_package': self,}
                    return type('module', (vistrails_module,), d)
                else:
                    raise AttributeError("type object '%s' has no attribute "
                                         "'%s'" % (self.__class__.__name__, 
                                                   attr_name))
            return getter
        
        d = {'__getattr__': get_module(package),}
        pkg = type(package.name, (object,), d)()
        
        modules = {}
        for (m,ns) in package.descriptors:
            module_desc = package.descriptors[(m,ns)]
            modules = create_dict(modules, ns.split('|'), m, module_desc)   
        
        modules = create_namespace_path(None, modules)
        
        for (k,v) in modules.iteritems():
            setattr(pkg, k, v)
        return pkg

    def selected_modules(self):
        shell_modules = []
        modules = vistrails.api.get_selected_modules()
        for module in modules:
            d = {'_module': module}
            shell_modules.append(type('module', (vistrails_module,), d)())
        return shell_modules

    def reset(self, locals):
        """reset(locals) -> None
        Reset shell preparing it for a new session.
        
        """
        locals['load_package'] = self.load_package
        locals['selected_modules'] = self.selected_modules
        if self.interpreter:
            del self.interpreter
        self.interpreter = InteractiveInterpreter(locals)
 
        # last line + last incomplete lines
        self.line    = ''
        self.lines   = []
        # the cursor position in the last line
        self.point   = 0
        # flag: the interpreter needs more input to run the last lines. 
        self.more    = 0
        # flag: readline() is being used for e.g. raw_input() and input()
        self.reading = 0
        # history
        self.history = []
        self.pointer = 0
        self.last   = 0
                # interpreter prompt.
        if hasattr(sys, "ps1"):
            sys.ps1
        else:
            sys.ps1 = ">>> "
        if hasattr(sys, "ps2"):
            sys.ps2
        else:
            sys.ps2 = "... "
        
        # interpreter banner
        
        self.write('VisTrails shell running Python %s on %s.\n' %
                   (sys.version, sys.platform))
        self.write('Type "copyright", "credits" or "license"'
                   ' for more information on Python.\n')
        self.write(sys.ps1)


    def flush(self):
        """flush() -> None. 
        Simulate stdin, stdout, and stderr.
        
        """
        pass

    def isatty(self):
        """isatty() -> int
        Simulate stdin, stdout, and stderr.
        
        """
        return 1

    def readline(self):
        """readline() -> str
        
        Simulate stdin, stdout, and stderr.
        
        """
        self.reading = 1
        self.__clearLine()
        cursor = self.textCursor()
        cursor.movePosition(QtGui.QTextCursor.End)
        self.setTextCursor(cursor)
      
        while self.reading:
            qApp.processOneEvent()
        if len(self.line) == 0:
            return '\n'
        else:
            return self.line 
    
    def write(self, text):
        """write(text: str) -> None
        Simulate stdin, stdout, and stderr.
        
        """
                
        cursor = self.textCursor()
        cursor.movePosition(QtGui.QTextCursor.End)
        cursor.clearSelection()
        self.setTextCursor(cursor)
        self.insertPlainText(text)
        cursor = self.textCursor()
        self.last = cursor.position()

    def insertFromMimeData(self, source):
        if source.hasText():
            cursor = self.textCursor()
            cursor.movePosition(QtGui.QTextCursor.End)
            cursor.clearSelection()
            self.setTextCursor(cursor)
            self.__insertText(source.text())
        
    def scroll_bar_at_bottom(self):
        """Returns true if vertical bar exists and is at bottom, or if
        vertical bar does not exist."""
        bar = self.verticalScrollBar()
        if not bar:
            return True
        return bar.value() == bar.maximum()
        
    def __run(self):
        """__run() -> None
        Append the last line to the history list, let the interpreter execute
        the last line(s), and clean up accounting for the interpreter results:
        (1) the interpreter succeeds
        (2) the interpreter fails, finds no errors and wants more line(s)
        (3) the interpreter fails, finds errors and writes them to sys.stderr
        
        """
        cursor = self.textCursor()
        cursor.movePosition(QtGui.QTextCursor.End)
        self.setTextCursor(cursor)
        # self.set_controller()
        should_scroll = self.scroll_bar_at_bottom()
        self.pointer = 0
        self.history.append(self.line)
        self.lines.append(self.line)
        source = '\n'.join(self.lines)
        self.write('\n')
        self.more = self.interpreter.runsource(source)
        if self.more:
            self.write(sys.ps2)
        else:
            self.write(sys.ps1)
            self.lines = []
        self.__clearLine()
        if should_scroll:
            bar = self.verticalScrollBar()
            if bar:
                bar.setValue(bar.maximum())

    def __clearLine(self):
        """__clearLine() -> None
        Clear input line buffer.
        
        """
        self.line = ""
        self.point = 0
        
    def __insertText(self, text):
        """__insertText(text) -> None
        Insert text at the current cursor position.
        
        """
        self.insertPlainText(text)
        self.line = self.line[:self.point] + text + self.line[self.point:]
        self.point += len(text)

    # def add_pipeline(self, p):
    #     """
    #     add_pipeline(p) -> None
    #     Set the active pipeline in the command shell.  This replaces the modules
    #     variable with the list of current active modules of the selected pipeline.
    #     """
    #     if self.controller:
    #         self.interpreter.active_pipeline = self.controller.current_pipeline
    #     else:
    #         self.interpreter.active_pipeline = p
    #     cmd = 'active_pipeline = self.shell.interpreter.active_pipeline'
    #     self.interpreter.runcode(cmd)
    #     cmd = 'modules = self.vistrails_interpreter.find_persistent_entities(active_pipeline)[0]'
    #     self.interpreter.runcode(cmd)

    def set_controller(self, controller=None):
        """set_controller(controller: VistrailController) -> None
        Set the current VistrailController on the shell.
        """
        self.controller = controller
        if controller:
            self.interpreter.active_pipeline = self.controller.current_pipeline
            cmd = 'active_pipeline = self.shell.interpreter.active_pipeline'
            self.interpreter.runcode(cmd)
            cmd = 'modules = self.vistrails_interpreter.' \
                'find_persistent_entities(active_pipeline)[0]'
            self.interpreter.runcode(cmd)

    # def set_pipeline(self):
    #     """set_active_pipeline() -> None
    #     Makes sure that the pipeline being displayed is present in the shell for
    #     direct inspection and manipulation
    #     """
    #     self.add_pipeline(None)
        
    def keyPressEvent(self, e):
        """keyPressEvent(e) -> None
        Handle user input a key at a time.

        Notice that text might come more than one keypress at a time
        if user is a fast enough typist!
        
        """
        text  = e.text()
        key   = e.key()

        # NB: Sometimes len(str(text)) > 1!
        if len(text) and all(ord(x) >= 32 and
                             ord(x) < 127
                             for x in str(text)):
        # exit select mode and jump to end of text
            cursor = self.textCursor()
            if self.selectMode or cursor.hasSelection():
                self.selectMode = False
                cursor.movePosition(QtGui.QTextCursor.End)
                cursor.clearSelection()
                self.setTextCursor(cursor)
            self.__insertText(text)
            return
 
        if e.modifiers() & QtCore.Qt.MetaModifier and key == self.eofKey:
            self.parent().closeSession()
        
        if e.modifiers() & QtCore.Qt.ControlModifier:
            if key == QtCore.Qt.Key_C or key == QtCore.Qt.Key_Insert:
                self.copy()
            elif key == QtCore.Qt.Key_V:
                cursor = self.textCursor()
                cursor.movePosition(QtGui.QTextCursor.End)
                cursor.clearSelection()
                self.setTextCursor(cursor)
                self.paste()
            elif key == QtCore.Qt.Key_A:
                self.selectAll()
                self.selectMode = True
            else:
                e.ignore()
            return

        if e.modifiers() & QtCore.Qt.ShiftModifier:
            if key == QtCore.Qt.Key_Insert:
                cursor = self.textCursor()
                cursor.movePosition(QtGui.QTextCursor.End)
                cursor.clearSelection()
                self.setTextCursor(cursor)
                self.paste()
            else:
                e.ignore()
            return

        # exit select mode and jump to end of text
        cursor = self.textCursor()
        if self.selectMode or cursor.hasSelection():
            self.selectMode = False
            cursor.movePosition(QtGui.QTextCursor.End)
            cursor.clearSelection()
            self.setTextCursor(cursor)

        if key == QtCore.Qt.Key_Backspace:
            if self.point:
                QtGui.QTextEdit.keyPressEvent(self, e)
                self.point -= 1
                self.line = self.line[:self.point] + self.line[self.point+1:]
        elif key == QtCore.Qt.Key_Delete:
            QtGui.QTextEdit.keyPressEvent(self, e)
            self.line = self.line[:self.point] + self.line[self.point+1:]
        elif key == QtCore.Qt.Key_Return or key == QtCore.Qt.Key_Enter:
            if self.reading:
                self.reading = 0
            else:
                self.__run()
        elif key == QtCore.Qt.Key_Tab:
            self.__insertText(text)
        elif key == QtCore.Qt.Key_Left:
            if self.point:
                QtGui.QTextEdit.keyPressEvent(self, e)
                self.point -= 1
        elif key == QtCore.Qt.Key_Right:
            if self.point < len(self.line):
                QtGui.QTextEdit.keyPressEvent(self, e)
                self.point += 1
        elif key == QtCore.Qt.Key_Home:
            cursor = self.textCursor()
            cursor.movePosition(QtGui.QTextCursor.StartOfLine)
            cursor.setPosition(cursor.position() + 4)
            self.setTextCursor(cursor)
            self.point = 0
        elif key == QtCore.Qt.Key_End:
            QtGui.QTextEdit.keyPressEvent(self, e)
            self.point = len(self.line)
        elif key == QtCore.Qt.Key_Up:
            if len(self.history):
                if self.pointer == 0:
                    self.pointer = len(self.history)
                self.pointer -= 1
                self.__recall()
        elif key == QtCore.Qt.Key_Down:
            if len(self.history):
                self.pointer += 1
                if self.pointer == len(self.history):
                    self.pointer = 0
                self.__recall()
        else:
            e.ignore()

    def __recall(self):
        """__recall() -> None
        Display the current item from the command history.
        
        """
        cursor = self.textCursor()
        cursor.setPosition(self.last)
        
        cursor.select(QtGui.QTextCursor.LineUnderCursor)

        cursor.removeSelectedText()
        self.setTextCursor(cursor)
        self.insertPlainText(sys.ps1)
        self.__clearLine()
        self.__insertText(self.history[self.pointer])

        
    def focusNextPrevChild(self, next):
        """focusNextPrevChild(next) -> None
        Suppress tabbing to the next window in multi-line commands. 
        
        """
        if next and self.more:
            return 0
        return QtGui.QTextEdit.focusNextPrevChild(self, next)

    def mousePressEvent(self, e):
        """mousePressEvent(e) -> None
        Keep the cursor after the last prompt.
        """
        if e.button() == QtCore.Qt.LeftButton:
            self.selectMode = True
            QtGui.QTextEdit.mousePressEvent(self, e)
#            cursor = self.textCursor()
#            cursor.movePosition(QtGui.QTextCursor.End)
#            self.setTextCursor(cursor)
        return

    def hide(self):
        """suspend() -> None
        Called when hiding the parent window in order to recover the previous
        state.

        """
        #recovering the state
        sys.stdout   = sys.__stdout__
        sys.stderr   = sys.__stderr__
        sys.stdin    = sys.__stdin__

    def show(self):
        """show() -> None
        Store previous state and starts capturing all interactive input and 
        output.
        
        """
        # capture all interactive input/output
        sys.stdout   = self
        sys.stderr   = self
        sys.stdin    = self
        self.setFocus()

    def saveSession(self, fileName):
        """saveSession(fileName: str) -> None 
        Write its contents to a file """
        output = open(str(fileName), 'w')
        output.write(self.toPlainText())
        output.close()

    def restart(self, locals=None):
        """restart(locals=None) -> None 
        Restart a new session 

        """
        self.clear()
        self.reset(locals)

    def contentsContextMenuEvent(self,ev):
        """
        contentsContextMenuEvent(ev) -> None
        Suppress the right button context menu.
        
        """
        return
Esempio n. 48
0
class PyCute(QTextEdit):

    reading = 0
    history = []
    pointer = 0

    def __init__(self, locals=None, log='', parent=None):
        """Constructor.

        The optional 'locals' argument specifies the dictionary in
        which code will be executed; it defaults to a newly created
        dictionary with key "__name__" set to "__console__" and key
        "__doc__" set to None.

        The optional 'log' argument specifies the file in which the
        interpreter session is to be logged.

        The optional 'parent' argument specifies the parent widget.
        If no parent widget has been specified, you can exit the
        interpreter by typing Ctrl-D.
        """

        QTextEdit.__init__(self)
        self.interpreter = Interpreter(locals)
        self.connect(self, SIGNAL("returnPressed()"), self.onReturnPressed)

        # session log
        self.log = log or 'PyCute.log'

        # to exit the main interpreter by a Ctrl-D if PyCute has no parent
        if parent is None:
            self.eofKey = Qt.Key_D
        else:
            self.eofKey = None

        # capture all interactive input/output
        sys.stdout = self
        sys.stderr = self
        sys.stdin  = self

        # user interface setup
        self.setTextFormat(QTextEdit.PlainText)
        self.setWrapPolicy(QTextEdit.Anywhere)
        self.setCaption('PyCute -- a Python Shell for PyQt -- '
                        'http://gerard.vermeulen.free.fr')

        # font
        if os.name == 'posix':
            font = QFont("Fixed", 12)
        elif os.name == 'nt' or os.name == 'dos':
            font = QFont("Courier New", 8)
        else:
            raise SystemExit, "FIXME for 'os2', 'mac', 'ce' or 'riscos'"
        font.setFixedPitch(1)
        self.setFont(font)

        # geometry
        height = 40*QFontMetrics(font).lineSpacing()
        request = QSize(600, height)
        if parent is not None:
            request = request.boundedTo(parent.size())
        self.resize(request)

        # interpreter prompt.
        try:
            sys.ps1
        except AttributeError:
            sys.ps1 = ">>> "
        try:
            sys.ps2
        except AttributeError:
            sys.ps2 = "... "

        # interpreter banner
        self.write('The PyCute shell running Python %s on %s.\n' %
                   (sys.version, sys.platform))
        self.write('Type "copyright", "credits" or "license"'
                   ' for more information on Python.')
        self.ps1()

    # __init__()

    def write(self, line):
        self.append(line.rstrip('\n'))
        self.moveCursor(QTextEdit.MoveEnd, 0)

    # write()

    def flush(self):
        pass

    # flush()
    
    def ps1(self):
        self.append(sys.ps1)
        self.moveCursor(QTextEdit.MoveEnd, 0)
        self.mark = self.getCursorPosition()

    # ps1()

    def ps2(self):
        self.append(sys.ps2)
        self.moveCursor(QTextEdit.MoveEnd, 0)

    # ps2()

    def tab(self):
        self.insert('    ')
        self.moveCursor(QTextEdit.MoveEnd, 0)

    # tab()

    def getLines(self):
        apply(self.setSelection, self.mark + self.getCursorPosition())
        lines = self.selectedText()
        return str(lines)

    # getLines()
        
    def readline(self):
        lines = self.getLines()
        self.history.insert(0, (self.mark, lines))
        self.moveCursor(QTextEdit.MoveEnd, 0)
        self.mark = self.getCursorPosition()
        self.reading = 1
        while self.reading:
            qApp.processOneEvent()
        return self.getLines().rstrip() or '\n'

    # readline()
        
    def push(self):
        lines = self.getLines()
        if not self.interpreter.runsource(lines.replace(sys.ps2, '')):
            self.history.insert(0, (self.mark, lines))
            #print self.history
            self.ps1()
        else:
            self.ps2()

    # push()

    def onReturnPressed(self):
        if self.reading:
            self.reading = 0
        else:
            self.push()

    # onReturnPressed()

    def keyPressEvent(self, e):
        ascii = e.ascii()
        key   = e.key()
        state = e.state()
        text  = e.text()

        #print "'%s' '%s' '%s' '%s'" % (ascii, key, state, text)
        if state & Qt.ControlButton and key == self.eofKey:
            try:
                file = open(self.log, "w")
                file.write(str(self.text()))
                file.close()
            except:
                pass
            sys.exit()
            return

        if state & Qt.ControlButton and key == Qt.Key_I:
            self.tab()
            return

        if key == Qt.Key_Tab:
            # completion
            return
        
        if key == Qt.Key_Return and not self.reading:
            position = self.getCursorPosition()
            if self.mark > position:
                for mark, lines in self.history:
                    if mark < position:
                        apply(self.setCursorPosition, self.mark)
                        self.insert(lines.rstrip('\n'))
                        return
                else:
                    return

        QTextEdit.keyPressEvent(self, e)
Esempio n. 49
0
class PythonWidget(HistoryConsoleWidget):
    """ A basic in-process Python interpreter.
    """

    # Emitted when a command has been executed in the interpeter.
    executed = QtCore.Signal()

    #--------------------------------------------------------------------------
    # 'object' interface
    #--------------------------------------------------------------------------

    def __init__(self, parent=None):
        super(PythonWidget, self).__init__(parent)

        # PythonWidget attributes.
        self.locals = dict(__name__='__console__', __doc__=None)
        self.interpreter = InteractiveInterpreter(self.locals)

        # PythonWidget protected attributes.
        self._buffer = StringIO()
        self._bracket_matcher = BracketMatcher(self._control)
        self._call_tip_widget = CallTipWidget(self._control)
        self._completion_lexer = CompletionLexer(PythonLexer())
        self._hidden = False
        self._highlighter = PythonWidgetHighlighter(self)
        self._last_refresh_time = 0

        # file-like object attributes.
        self.encoding = sys.stdin.encoding

        # Configure the ConsoleWidget.
        self.tab_width = 4
        self._set_continuation_prompt('... ')

        # Configure the CallTipWidget.
        self._call_tip_widget.setFont(self.font)
        self.font_changed.connect(self._call_tip_widget.setFont)

        # Connect signal handlers.
        document = self._control.document()
        document.contentsChange.connect(self._document_contents_change)

        # Display the banner and initial prompt.
        self.reset()

    #--------------------------------------------------------------------------
    # file-like object interface
    #--------------------------------------------------------------------------

    def flush(self):
        """ Flush the buffer by writing its contents to the screen.
        """
        self._buffer.seek(0)
        text = self._buffer.getvalue()
        self._buffer.close()
        self._buffer = StringIO()

        self._append_plain_text(text)
        self._control.moveCursor(QtGui.QTextCursor.End)

    def readline(self, prompt=None):
        """ Read and return one line of input from the user.
        """
        return self._readline(prompt)

    def write(self, text, refresh=True):
        """ Write text to the buffer, possibly flushing it if 'refresh' is set.
        """
        if not self._hidden:
            self._buffer.write(text)
            if refresh:
                current_time = time()
                if current_time - self._last_refresh_time > 0.05:
                    self.flush()
                    self._last_refresh_time = current_time

    def writelines(self, lines, refresh=True):
        """ Write a list of lines to the buffer.
        """
        for line in lines:
            self.write(line, refresh=refresh)

    #---------------------------------------------------------------------------
    # 'ConsoleWidget' abstract interface
    #---------------------------------------------------------------------------

    def _is_complete(self, source, interactive):
        """ Returns whether 'source' can be completely processed and a new
            prompt created. When triggered by an Enter/Return key press,
            'interactive' is True; otherwise, it is False.
        """
        if interactive:
            lines = source.splitlines()
            if len(lines) == 1:
                try:
                    return compile_command(source) is not None
                except:
                    # We'll let the interpeter handle the error.
                    return True
            else:
                return lines[-1].strip() == ''
        else:
            return True

    def _execute(self, source, hidden):
        """ Execute 'source'. If 'hidden', do not show any output.

        See parent class :meth:`execute` docstring for full details.
        """
        # Save the current std* and point them here
        old_stdin = sys.stdin
        old_stdout = sys.stdout
        old_stderr = sys.stderr
        sys.stdin = sys.stdout = sys.stderr = self

        # Run the source code in the interpeter
        self._hidden = hidden
        try:
            more = self.interpreter.runsource(source)
        finally:
            self._hidden = False

            # Restore std* unless the executed changed them
            if sys.stdin is self:
                sys.stdin = old_stdin
            if sys.stdout is self:
                sys.stdout = old_stdout
            if sys.stderr is self:
                sys.stderr = old_stderr

            self.executed.emit()
            self._show_interpreter_prompt()

    def _prompt_started_hook(self):
        """ Called immediately after a new prompt is displayed.
        """
        if not self._reading:
            self._highlighter.highlighting_on = True

    def _prompt_finished_hook(self):
        """ Called immediately after a prompt is finished, i.e. when some input
            will be processed and a new prompt displayed.
        """
        if not self._reading:
            self._highlighter.highlighting_on = False

    def _tab_pressed(self):
        """ Called when the tab key is pressed. Returns whether to continue
            processing the event.
        """
        # Perform tab completion if:
        # 1) The cursor is in the input buffer.
        # 2) There is a non-whitespace character before the cursor.
        text = self._get_input_buffer_cursor_line()
        if text is None:
            return False
        complete = bool(text[:self._get_input_buffer_cursor_column()].strip())
        if complete:
            self._complete()
        return not complete

    #---------------------------------------------------------------------------
    # 'ConsoleWidget' protected interface
    #---------------------------------------------------------------------------

    def _event_filter_console_keypress(self, event):
        """ Reimplemented for smart backspace.
        """
        if event.key() == QtCore.Qt.Key_Backspace and \
                not event.modifiers() & QtCore.Qt.AltModifier:
            # Smart backspace: remove four characters in one backspace if:
            # 1) everything left of the cursor is whitespace
            # 2) the four characters immediately left of the cursor are spaces
            col = self._get_input_buffer_cursor_column()
            cursor = self._control.textCursor()
            if col > 3 and not cursor.hasSelection():
                text = self._get_input_buffer_cursor_line()[:col]
                if text.endswith('    ') and not text.strip():
                    cursor.movePosition(QtGui.QTextCursor.Left,
                                        QtGui.QTextCursor.KeepAnchor, 4)
                    cursor.removeSelectedText()
                    return True

        return super(PythonWidget, self)._event_filter_console_keypress(event)

    def _insert_continuation_prompt(self, cursor):
        """ Reimplemented for auto-indentation.
        """
        super(PythonWidget, self)._insert_continuation_prompt(cursor)
        source = self.input_buffer
        space = 0
        for c in source.splitlines()[-1]:
            if c == '\t':
                space += 4
            elif c == ' ':
                space += 1
            else:
                break
        if source.rstrip().endswith(':'):
            space += 4
        cursor.insertText(' ' * space)

    #---------------------------------------------------------------------------
    # 'PythonWidget' public interface
    #---------------------------------------------------------------------------

    def execute_file(self, path, hidden=False):
        """ Attempts to execute file with 'path'. If 'hidden', no output is
            shown.
        """
        self.execute('execfile("%s")' % path, hidden=hidden)

    def reset(self):
        """ Resets the widget to its initial state. Similar to ``clear``, but
            also re-writes the banner.
        """
        self._reading = False
        self._highlighter.highlighting_on = False

        self._control.clear()
        self._append_plain_text(self._get_banner())
        self._show_interpreter_prompt()

    #---------------------------------------------------------------------------
    # 'PythonWidget' protected interface
    #---------------------------------------------------------------------------

    def _call_tip(self):
        """ Shows a call tip, if appropriate, at the current cursor location.
        """
        # Decide if it makes sense to show a call tip
        cursor = self._get_cursor()
        cursor.movePosition(QtGui.QTextCursor.Left)
        if cursor.document().characterAt(cursor.position()) != '(':
            return False
        context = self._get_context(cursor)
        if not context:
            return False

        # Look up the context and show a tip for it
        symbol, leftover = self._get_symbol_from_context(context)
        doc = getattr(symbol, '__doc__', None)
        if doc is not None and not leftover:
            self._call_tip_widget.show_call_info(doc=doc)
            return True
        return False

    def _complete(self):
        """ Performs completion at the current cursor location.
        """
        context = self._get_context()
        if context:
            symbol, leftover = self._get_symbol_from_context(context)
            if len(leftover) == 1:
                leftover = leftover[0]
                if symbol is None:
                    names = self.interpreter.locals.keys()
                    names += __builtin__.__dict__.keys()
                else:
                    names = dir(symbol)
                completions = [n for n in names if n.startswith(leftover)]
                if completions:
                    cursor = self._get_cursor()
                    cursor.movePosition(QtGui.QTextCursor.Left,
                                        n=len(context[-1]))
                    self._complete_with_items(cursor, completions)

    def _get_banner(self):
        """ Gets a banner to display at the beginning of a session.
        """
        banner = 'Python %s on %s\nType "help", "copyright", "credits" or ' \
            '"license" for more information.'
        return banner % (sys.version, sys.platform)

    def _get_context(self, cursor=None):
        """ Gets the context for the specified cursor (or the current cursor
            if none is specified).
        """
        if cursor is None:
            cursor = self._get_cursor()
        cursor.movePosition(QtGui.QTextCursor.StartOfBlock,
                            QtGui.QTextCursor.KeepAnchor)
        text = cursor.selection().toPlainText()
        return self._completion_lexer.get_context(text)

    def _get_symbol_from_context(self, context):
        """ Find a python object in the interpeter namespace from a context (a
            list of names).
        """
        context = map(str, context)
        if len(context) == 0:
            return None, context

        base_symbol_string = context[0]
        symbol = self.interpreter.locals.get(base_symbol_string, None)
        if symbol is None:
            symbol = __builtin__.__dict__.get(base_symbol_string, None)
        if symbol is None:
            return None, context

        context = context[1:]
        for i, name in enumerate(context):
            new_symbol = getattr(symbol, name, None)
            if new_symbol is None:
                return symbol, context[i:]
            else:
                symbol = new_symbol

        return symbol, []

    def _show_interpreter_prompt(self):
        """ Shows a prompt for the interpreter.
        """
        self.flush()
        self._show_prompt('>>> ')

    #------ Signal handlers ----------------------------------------------------

    def _document_contents_change(self, position, removed, added):
        """ Called whenever the document's content changes. Display a call tip
            if appropriate.
        """
        # Calculate where the cursor should be *after* the change:
        position += added

        document = self._control.document()
        if position == self._get_cursor().position():
            self._call_tip()
Esempio n. 50
0
class QShell(QtGui.QTextEdit):
    """This class embeds a python interperter in a QTextEdit Widget
    It is based on PyCute developed by Gerard Vermeulen.
    
    """
    def __init__(self, locals=None, parent=None):
        """Constructor.

        The optional 'locals' argument specifies the dictionary in which code
        will be executed; it defaults to a newly created dictionary with key 
        "__name__" set to "__console__" and key "__doc__" set to None.

        The optional 'log' argument specifies the file in which the interpreter
        session is to be logged.
        
        The optional 'parent' argument specifies the parent widget. If no parent
        widget has been specified, it is possible to exit the interpreter 
        by Ctrl-D.

        """

        QtGui.QTextEdit.__init__(self, parent)
        self.setReadOnly(False)
        
        # to exit the main interpreter by a Ctrl-D if QShell has no parent
        if parent is None:
            self.eofKey = QtCore.Qt.Key_D
        else:
            self.eofKey = None

        self.interpreter = None
        # storing current state
        #this is not working on mac
        #self.prev_stdout = sys.stdout
        #self.prev_stdin = sys.stdin
        #self.prev_stderr = sys.stderr
        # capture all interactive input/output
        #sys.stdout   = self
        #sys.stderr   = self
        #sys.stdin    = self
        
        # user interface setup
        
        self.setAcceptRichText(False)
        self.setWordWrapMode(QtGui.QTextOption.WrapAnywhere)
        
        app = gui.application.VistrailsApplication
        shell_conf = app.configuration.shell
        # font
        font = QtGui.QFont(shell_conf.font_face, shell_conf.font_size)
        font.setFixedPitch(1)
        self.setCurrentFont(font)
        self.reset(locals)

    def reset(self, locals):
        """reset(locals) -> None
        Reset shell preparing it for a new session.
        
        """
        if self.interpreter:
            del self.interpreter
        self.interpreter = InteractiveInterpreter(locals)
 
        # last line + last incomplete lines
        self.line    = QtCore.QString()
        self.lines   = []
        # the cursor position in the last line
        self.point   = 0
        # flag: the interpreter needs more input to run the last lines. 
        self.more    = 0
        # flag: readline() is being used for e.g. raw_input() and input()
        self.reading = 0
        # history
        self.history = []
        self.pointer = 0
        self.last   = 0
                # interpreter prompt.
        if hasattr(sys, "ps1"):
            sys.ps1
        else:
            sys.ps1 = ">>> "
        if hasattr(sys, "ps2"):
            sys.ps2
        else:
            sys.ps2 = "... "
        
        # interpreter banner
        
        self.write('VisTrails shell running Python %s on %s.\n' %
                   (sys.version, sys.platform))
        self.write('Type "copyright", "credits" or "license"'
                   ' for more information on Python.\n')
        self.write(sys.ps1)


    def flush(self):
        """flush() -> None. 
        Simulate stdin, stdout, and stderr.
        
        """
        pass

    def isatty(self):
        """isatty() -> int
        Simulate stdin, stdout, and stderr.
        
        """
        return 1

    def readline(self):
        """readline() -> str
        
        Simulate stdin, stdout, and stderr.
        
        """
        self.reading = 1
        self.__clearLine()
        cursor = self.textCursor()
        cursor.movePosition(QtGui.QTextCursor.End)
        self.setTextCursor(cursor)
      
        while self.reading:
            qApp.processOneEvent()
        if self.line.length() == 0:
            return '\n'
        else:
            return str(self.line) 
    
    def write(self, text):
        """write(text: str) -> None
        Simulate stdin, stdout, and stderr.
        
        """
                
        self.insertPlainText(text)
        cursor = self.textCursor()
        self.last = cursor.position()

    def scroll_bar_at_bottom(self):
        """Returns true if vertical bar exists and is at bottom, or if
        vertical bar does not exist."""
        bar = self.verticalScrollBar()
        if not bar:
            return True
        return bar.value() == bar.maximum()
        
    def __run(self):
        """__run() -> None
        Append the last line to the history list, let the interpreter execute
        the last line(s), and clean up accounting for the interpreter results:
        (1) the interpreter succeeds
        (2) the interpreter fails, finds no errors and wants more line(s)
        (3) the interpreter fails, finds errors and writes them to sys.stderr
        
        """
        should_scroll = self.scroll_bar_at_bottom()
        self.pointer = 0
        self.history.append(QtCore.QString(self.line))
        self.lines.append(str(self.line))
        source = '\n'.join(self.lines)
        self.write('\n')
        self.more = self.interpreter.runsource(source)
        if self.more:
            self.write(sys.ps2)
        else:
            self.write(sys.ps1)
            self.lines = []
        self.__clearLine()
        if should_scroll:
            bar = self.verticalScrollBar()
            if bar:
                bar.setValue(bar.maximum())

    def __clearLine(self):
        """__clearLine() -> None
        Clear input line buffer.
        
        """
        self.line.truncate(0)
        self.point = 0
        
    def __insertText(self, text):
        """__insertText(text) -> None
        Insert text at the current cursor position.
        
        """
        self.insertPlainText(text)
        self.line.insert(self.point, text)
        self.point += text.length()
        
    def keyPressEvent(self, e):
        """keyPressEvent(e) -> None
        Handle user input a key at a time.
        
        """
        text  = e.text()
        key   = e.key()
        if not text.isEmpty():
            ascii = ord(str(text))
        else:
            ascii = -1
        if text.length() and ascii>=32 and ascii<127:
            self.__insertText(text)
            return

        if e.modifiers() & QtCore.Qt.MetaModifier and key == self.eofKey:
            self.parent().closeSession()
        
        if (e.modifiers() & QtCore.Qt.ControlModifier or 
            e.modifiers() & QtCore.Qt.ShiftModifier):
            e.ignore()
            return

        if key == QtCore.Qt.Key_Backspace:
            if self.point:
                QtGui.QTextEdit.keyPressEvent(self, e)
                self.point -= 1
                self.line.remove(self.point, 1)
        elif key == QtCore.Qt.Key_Delete:
            QtGui.QTextEdit.keyPressEvent(self, e)
            self.line.remove(self.point, 1)
        elif key == QtCore.Qt.Key_Return or key == QtCore.Qt.Key_Enter:
            if self.reading:
                self.reading = 0
            else:
                self.__run()
        elif key == QtCore.Qt.Key_Tab:
            self.__insertText(text)
        elif key == QtCore.Qt.Key_Left:
            if self.point:
                QtGui.QTextEdit.keyPressEvent(self, e)
                self.point -= 1
        elif key == QtCore.Qt.Key_Right:
            if self.point < self.line.length():
                QtGui.QTextEdit.keyPressEvent(self, e)
                self.point += 1
        elif key == QtCore.Qt.Key_Home:
            cursor = self.textCursor()
            cursor.movePosition(QtGui.QTextCursor.StartOfLine)
            cursor.setPosition(cursor.position() + 4)
            self.setTextCursor(cursor)
            self.point = 0
        elif key == QtCore.Qt.Key_End:
            QtGui.QTextEdit.keyPressEvent(self, e)
            self.point = self.line.length()
        elif key == QtCore.Qt.Key_Up:
            if len(self.history):
                if self.pointer == 0:
                    self.pointer = len(self.history)
                self.pointer -= 1
                self.__recall()
        elif key == QtCore.Qt.Key_Down:
            if len(self.history):
                self.pointer += 1
                if self.pointer == len(self.history):
                    self.pointer = 0
                self.__recall()
        else:
            e.ignore()

    def __recall(self):
        """__recall() -> None
        Display the current item from the command history.
        
        """
        cursor = self.textCursor()
        cursor.setPosition(self.last)
        
        cursor.select(QtGui.QTextCursor.LineUnderCursor)

        cursor.removeSelectedText()
        self.setTextCursor(cursor)
        self.insertPlainText(sys.ps1)
        self.__clearLine()
        self.__insertText(self.history[self.pointer])

        
    def focusNextPrevChild(self, next):
        """focusNextPrevChild(next) -> None
        Suppress tabbing to the next window in multi-line commands. 
        
        """
        if next and self.more:
            return 0
        return QtGui.QTextEdit.focusNextPrevChild(self, next)

    def mousePressEvent(self, e):
        """mousePressEvent(e) -> None
        Keep the cursor after the last prompt.
        """
        if e.button() == QtCore.Qt.LeftButton:
            cursor = self.textCursor()
            cursor.movePosition(QtGui.QTextCursor.End)
            self.setTextCursor(cursor)
        return

#     def suspend(self):
#         """suspend() -> None
#         Called when hiding the parent window in order to recover the previous
#         state.

#         """
#         #recovering the state
#         sys.stdout   = self.prev_stdout
#         sys.stderr   = self.prev_stderr
#         sys.stdin    = self.prev_stdin

    def show(self):
        """show() -> None
        Store previous state and starts capturing all interactive input and 
        output.
        
        """
#         # storing current state
#         self.prev_stdout = sys.stdout
#         self.prev_stdin = sys.stdin
#         self.prev_stderr = sys.stderr

        # capture all interactive input/output
        sys.stdout   = self
        sys.stderr   = self
        sys.stdin    = self

    def saveSession(self, fileName):
        """saveSession(fileName: str) -> None 
        Write its contents to a file """
        output = open(str(fileName), 'w')
        output.write(self.toPlainText())
        output.close()

    def restart(self, locals=None):
        """restart(locals=None) -> None 
        Restart a new session 

        """
        self.clear()
        self.reset(locals)

    def contentsContextMenuEvent(self,ev):
        """
        contentsContextMenuEvent(ev) -> None
        Suppress the right button context menu.
        
        """
        return