Go to the documentation of this file.00001 
00002 
00003 
00004 
00005 
00006 
00007 
00008 
00009 
00010 
00011 
00012 
00013 
00014 
00015 
00016 
00017 
00018 
00019 
00020 
00021 
00022 
00023 
00024 
00025 
00026 
00027 
00028 
00029 
00030 
00031 
00032 
00033 import sys
00034 
00035 from python_qt_binding.QtCore import Qt
00036 from python_qt_binding.QtGui import QFont, QTextEdit
00037 
00038 
00039 class ConsoleTextEdit(QTextEdit):
00040     _color_stdout = Qt.blue
00041     _color_stderr = Qt.red
00042     _color_stdin = Qt.black
00043     _multi_line_char = '\\'
00044     _multi_line_indent = '    '
00045     _prompt = ('$ ', '  ')  
00046 
00047     class TextEditColoredWriter:
00048         def __init__(self, text_edit, color):
00049             self._text_edit = text_edit
00050             self._color = color
00051 
00052         def write(self, line):
00053             old_color = self._text_edit.textColor()
00054             self._text_edit.setTextColor(self._color)
00055             self._text_edit.insertPlainText(line)
00056             self._text_edit.setTextColor(old_color)
00057             self._text_edit.ensureCursorVisible()
00058 
00059     def __init__(self, parent=None):
00060         super(ConsoleTextEdit, self).__init__(parent)
00061         self.setFont(QFont('Mono'))
00062 
00063         self._multi_line = False
00064         self._multi_line_level = 0
00065         self._command = ''
00066         self._history = []
00067         self._history_index = -1
00068 
00069         
00070         self._stdout = self.TextEditColoredWriter(self, self._color_stdout)
00071         self._stderr = self.TextEditColoredWriter(self, self._color_stderr)
00072         self._comment_writer = self.TextEditColoredWriter(self, self._color_stdin)
00073 
00074     def print_message(self, msg):
00075         self._clear_current_line(clear_prompt=True)
00076         self._comment_writer.write(msg + '\n')
00077         self._add_prompt()
00078 
00079     def _add_prompt(self):
00080         self._comment_writer.write(self._prompt[self._multi_line] + self._multi_line_indent * self._multi_line_level)
00081 
00082     def _clear_current_line(self, clear_prompt=False):
00083         
00084         prompt_length = len(self._prompt[self._multi_line])
00085         if clear_prompt:
00086             prompt_length = 0
00087         length = len(self.document().lastBlock().text()[prompt_length:])
00088         if length == 0:
00089             return None
00090         else:
00091             
00092             for _ in xrange(length):
00093                 self.textCursor().deletePreviousChar()
00094         return True
00095 
00096     def _move_in_history(self, delta):
00097         
00098         self._clear_current_line()
00099         if -1 <= self._history_index + delta < len(self._history):
00100             self._history_index += delta
00101         if self._history_index >= 0:
00102             self.insertPlainText(self._history[self._history_index])
00103         return True
00104 
00105     def _exec_code(self, code):
00106         raise NotImplementedError
00107 
00108     def _exec_with_captured_output(self, code):
00109         old_out, old_err = sys.stdout, sys.stderr
00110         sys.stdout, sys.stderr = self._stdout, self._stderr
00111         self._exec_code(code)
00112         sys.stdout, sys.stderr = old_out, old_err
00113 
00114     def keyPressEvent(self, event):
00115         prompt_length = len(self._prompt[self._multi_line])
00116         block_length = self.document().lastBlock().length()
00117         document_length = self.document().characterCount()
00118         line_start = document_length - block_length
00119         prompt_position = line_start + prompt_length
00120 
00121         
00122         if self.textCursor().position() >= prompt_position:
00123             if event.key() == Qt.Key_Down:
00124                 if self._history_index == len(self._history):
00125                     self._history_index -= 1
00126                 self._move_in_history(-1)
00127                 return None
00128 
00129             if event.key() == Qt.Key_Up:
00130                 self._move_in_history(1)
00131                 return None
00132 
00133             if event.key() in [Qt.Key_Backspace]:
00134                 
00135                 if self.textCursor().positionInBlock() == prompt_length and not self.textCursor().hasSelection():
00136                     return None
00137 
00138             if event.key() in [Qt.Key_Return, Qt.Key_Enter]:
00139                 
00140                 cursor = self.textCursor()
00141                 cursor.setPosition(document_length - 1)
00142                 self.setTextCursor(cursor)
00143 
00144                 self._history_index = -1
00145                 line = str(self.document().lastBlock().text())[prompt_length:].rstrip()  
00146 
00147                 self.insertPlainText('\n')
00148                 if len(line) > 0:
00149                     if line[-1] == self._multi_line_char:
00150                         self._multi_line = True
00151                         self._multi_line_level += 1
00152                     self._history.insert(0, line)
00153 
00154                     if self._multi_line:  
00155                         self._command += line + '\n'
00156 
00157                     else:  
00158                         self._exec_with_captured_output(line)
00159                         self._command = ''
00160 
00161                 else:  
00162 
00163                     if self._multi_line:  
00164                         self._exec_with_captured_output(self._command)
00165                         self._command = ''
00166                         self._multi_line = False
00167                         self._multi_line_level = 0
00168 
00169                 self._add_prompt()
00170                 return None
00171 
00172         
00173         super(ConsoleTextEdit, self).keyPressEvent(event)
00174 
00175         
00176         if line_start <= self.textCursor().position() < prompt_position:
00177             cursor = self.textCursor()
00178             cursor.setPosition(prompt_position)
00179             self.setTextCursor(cursor)