Main Page | Packages | Class Hierarchy | Alphabetical List | Class List | Directories | File List | Namespace Members | Class Members | Related Pages

rcPythonShell.py

00001 #!/usr/local/bin/python
00002 #
00003 #                               Copyright 2002
00004 #                                     by
00005 #                        The Board of Trustees of the
00006 #                     Leland Stanford Junior University.
00007 #                            All rights reserved.
00008 #
00009 
00010 __facility__ = "Online"
00011 __abstract__ = "Python shell class for RunControl"
00012 __author__   = "S. Tuvi <stuvi@SLAC.Stanford.edu> SLAC - GLAST LAT I&T/Online"
00013 __date__     = ("$Date: 2004/08/24 23:16:43 $").split(' ')[1]
00014 __version__  = "$Revision: 2.1 $"
00015 __credits__  = "SLAC"
00016 
00017 
00018 import LATTE.copyright_SLAC
00019 
00020 import os, sys
00021 from code import InteractiveInterpreter as Interpreter
00022 from qt import *
00023 
00024 class rcPythonShell(QWidget):
00025   def __init__(self,parent = None,name = None,fl = 0):
00026     QWidget.__init__(self,parent,name,fl)
00027 
00028     if not name:
00029       self.setName("rcPythonShell")
00030 
00031     self.__parent = parent
00032 
00033     Form2Layout = QGridLayout(self,1,1,0,6,"Form2Layout")
00034 
00035     self.__teShell = PythonShellWidget(locals=sys.modules['__main__'].__dict__, log='', parent=self)
00036 
00037     Form2Layout.addWidget(self.__teShell,0,0)
00038 
00039     self.languageChange()
00040 
00041     self.resize(QSize(291,219).expandedTo(self.minimumSizeHint()))
00042 
00043   def getParent(self):
00044     return self.__parent
00045 
00046   def getWidget(self):
00047     return self.__teShell
00048 
00049   def languageChange(self):
00050     self.setCaption(self.tr("rcPythonShell"))
00051 
00052 class PythonShellWidget(QTextEdit):
00053   def __init__(self, locals=None, log='', parent=None):
00054     """Constructor.
00055 
00056     The optional 'locals' argument specifies the dictionary in
00057     which code will be executed; it defaults to a newly created
00058     dictionary with key "__name__" set to "__console__" and key
00059     "__doc__" set to None.
00060 
00061     The optional 'log' argument specifies the file in which the
00062     interpreter session is to be logged.
00063 
00064     The optional 'parent' argument specifies the parent widget.
00065     If no parent widget has been specified, it is possible to
00066     exit the interpreter by Ctrl-D.
00067     """
00068 
00069     QTextEdit.__init__(self, parent)
00070     self.interpreter = Interpreter(locals)
00071 
00072     # session log
00073     self.log = log or ''
00074 
00075     self.parent = parent
00076 
00077     # to exit the main interpreter by a Ctrl-D if PyCute has no parent
00078     if os.name == 'nt' or os.name == 'dos':
00079       self.eofKey = Qt.Key_Z
00080     else:
00081       self.eofKey = Qt.Key_D
00082 
00083     # last line + last incomplete lines
00084     self.line    = QString()
00085     self.lines   = []
00086     # the cursor position in the last line
00087     self.point   = 0
00088     # flag: the interpreter needs more input to run the last lines.
00089     self.more    = 0
00090     # flag: readline() is being used for e.g. raw_input() and input()
00091     self.reading = 0
00092     # history
00093     self.history = []
00094     self.pointer = 0
00095     self.xLast   = 0
00096     self.yLast   = 0
00097     self.clip = QApplication.clipboard()
00098 
00099 
00100     # user interface setup
00101     self.setTextFormat(QTextEdit.PlainText)
00102     self.setWrapPolicy(QTextEdit.Anywhere)
00103     self.setCaption('Python Shell')
00104     # font
00105     if os.name == 'posix':
00106       font = QFont("Fixed", 12)
00107     elif os.name == 'nt' or os.name == 'dos':
00108       font = QFont("Courier New", 8)
00109     else:
00110       raise SystemExit, "FIXME for 'os2', 'mac', 'ce' or 'riscos'"
00111     font.setFixedPitch(1)
00112     self.setFont(font)
00113 
00114     # geometry
00115     height = 40*QFontMetrics(font).lineSpacing()
00116     request = QSize(600, height)
00117     if parent is not None:
00118       request = request.boundedTo(parent.size())
00119     self.resize(request)
00120 
00121     # interpreter prompt.
00122     try:
00123       sys.ps1
00124     except AttributeError:
00125       sys.ps1 = ">>> "
00126     try:
00127       sys.ps2
00128     except AttributeError:
00129       sys.ps2 = "... "
00130 
00131     # interpreter banner
00132     self.write('Python shell running Python %s on %s.\n' %
00133                 (sys.version, sys.platform))
00134     self.write('Type "copyright", "credits" or "license"'
00135                 ' for more information on Python.\n')
00136     self.write(sys.ps1)
00137 
00138     self.connect(self, SIGNAL("clicked(int,int)"), self.handleClicked)
00139 
00140   def redirectIO(self):
00141     # capture all interactive input/output
00142     sys.stdout   = self
00143     sys.stderr   = self
00144     sys.stdin    = self
00145 
00146   def restoreIO(self):
00147     # restore all interactive input/output to their original values
00148     sys.stdout   = sys.__stdout__
00149     sys.stderr   = sys.__stderr__
00150     sys.stdin    = sys.__stdin__
00151 
00152   def flush(self):
00153     """
00154     Simulate stdin, stdout, and stderr.
00155     """
00156     pass
00157 
00158   def isatty(self):
00159     """
00160     Simulate stdin, stdout, and stderr.
00161     """
00162     return 1
00163 
00164   def readline(self):
00165     """
00166     Simulate stdin, stdout, and stderr.
00167     """
00168     self.reading = 1
00169     self.__clearLine()
00170     self.moveCursor(QTextEdit.MoveEnd, 0)
00171     while self.reading:
00172       qApp.processOneEvent()
00173     if self.line.length() == 0:
00174       return '\n'
00175     else:
00176       return str(self.line)
00177 
00178   def write(self, text):
00179     """
00180     Simulate stdin, stdout, and stderr.
00181     """
00182     # The output of self.append(text) contains to many newline characters,
00183     # so work around QTextEdit's policy for handling newline characters.
00184     hack = self.text()
00185     hack.append(text)
00186     self.setText(hack)
00187     #self.setText(self.text().append(text)) # segmentation fault
00188     self.moveCursor(QTextEdit.MoveEnd, 0)
00189     self.yLast, self.xLast = self.getCursorPosition()
00190 
00191   def writelines(self, text):
00192     """
00193     Simulate stdin, stdout, and stderr.
00194     """
00195     map(self.write, text)
00196     print "DO WE EVER GET HERE? IF YES, OPTIMIZATION POSSIBLE"
00197 
00198   def fakeUser(self, lines):
00199     """
00200     Simulate a user: lines is a sequence of strings, (Python statements).
00201     """
00202     for line in lines:
00203       self.line = QString(line.rstrip())
00204       self.write(self.line)
00205       self.write('\n')
00206       self.__run()
00207 
00208   def __run(self):
00209     """
00210     Append the last line to the history list, let the interpreter execute
00211     the last line(s), and clean up accounting for the interpreter results:
00212     (1) the interpreter succeeds
00213     (2) the interpreter fails, finds no errors and wants more line(s)
00214     (3) the interpreter fails, finds errors and writes them to sys.stderr
00215     """
00216     self.pointer = 0
00217     self.history.append(QString(self.line))
00218     self.lines.append(str(self.line))
00219     source = '\n'.join(self.lines)
00220     self.redirectIO()
00221     self.more = self.interpreter.runsource(source)
00222     self.restoreIO()
00223     if self.more:
00224       self.write(sys.ps2)
00225     else:
00226       self.write(sys.ps1)
00227       self.lines = []
00228     self.__clearLine()
00229 
00230   def __clearLine(self):
00231     """
00232     Clear input line buffer
00233     """
00234     self.line.truncate(0)
00235     self.point = 0
00236 
00237   def __insertText(self, text):
00238     """
00239     Insert text at the current cursor position.
00240     """
00241     y, x = self.getCursorPosition()
00242     self.insertAt(text, y, x)
00243     self.line.insert(self.point, text)
00244     self.point += text.length()
00245     self.setCursorPosition(y, x + text.length())
00246 
00247   def keyPressEvent(self, e):
00248     """
00249     Handle user input a key at a time.
00250     """
00251     text  = e.text()
00252     key   = e.key()
00253     ascii = e.ascii()
00254 
00255     if text.length() and ascii>=32 and ascii<127:
00256       self.__insertText(text)
00257       return
00258 
00259     if e.state() & Qt.ControlButton and key == self.eofKey:
00260       if self.parent is None:
00261         try:
00262           file = open(self.log, "w")
00263           file.write(str(self.text()))
00264           file.close()
00265         except:
00266           pass
00267         sys.exit()
00268       else:
00269         self.restoreIO()
00270         self.parent.getParent().hide()
00271       return
00272 
00273     if e.state() & Qt.ControlButton or e.state() & Qt.ShiftButton:
00274       e.ignore()
00275       return
00276 
00277     if key == Qt.Key_Backspace:
00278       if self.point:
00279         self.doKeyboardAction(QTextEdit.ActionBackspace)
00280         self.point -= 1
00281         self.line.remove(self.point, 1)
00282     elif key == Qt.Key_Delete:
00283       self.doKeyboardAction(QTextEdit.ActionDelete)
00284       self.line.remove(self.point, 1)
00285     elif key == Qt.Key_Return or key == Qt.Key_Enter:
00286       self.write('\n')
00287       if self.reading:
00288         self.reading = 0
00289       else:
00290           self.__run()
00291     elif key == Qt.Key_Tab:
00292       self.__insertText(text)
00293     elif key == Qt.Key_Left:
00294       if self.point:
00295         self.moveCursor(QTextEdit.MoveBackward, 0)
00296         self.point -= 1
00297     elif key == Qt.Key_Right:
00298       if self.point < self.line.length():
00299         self.moveCursor(QTextEdit.MoveForward, 0)
00300         self.point += 1
00301     elif key == Qt.Key_Home:
00302       self.setCursorPosition(self.yLast, self.xLast)
00303       self.point = 0
00304     elif key == Qt.Key_End:
00305       self.moveCursor(QTextEdit.MoveLineEnd, 0)
00306       self.point = self.line.length()
00307     elif key == Qt.Key_Up:
00308       if len(self.history):
00309         if self.pointer == 0:
00310           self.pointer = len(self.history)
00311         self.pointer -= 1
00312         self.__recall()
00313     elif key == Qt.Key_Down:
00314       if len(self.history):
00315         self.pointer += 1
00316         if self.pointer == len(self.history):
00317           self.pointer = 0
00318         self.__recall()
00319     elif key == Qt.Key_Escape:
00320       self.__deleteLine()
00321     else:
00322       e.ignore()
00323 
00324   def __deleteLine(self):
00325     self.setCursorPosition(self.yLast, self.xLast)
00326     self.setSelection(self.yLast, self.xLast,
00327                       self.yLast, self.paragraphLength(self.yLast))
00328     self.removeSelectedText()
00329     self.__clearLine()
00330 
00331   def __recall(self):
00332     """
00333     Display the current item from the command history.
00334     """
00335     self.__deleteLine()
00336     self.__insertText(self.history[self.pointer])
00337 
00338 
00339   def focusNextPrevChild(self, next):
00340     """
00341     Suppress tabbing to the next window in multi-line commands.
00342     """
00343     if next and self.more:
00344       return 0
00345     return QTextEdit.focusNextPrevChild(self, next)
00346 
00347   def handleClicked(self, para, pos):
00348     """
00349     Keep the cursor after the last prompt.
00350     """
00351     if self.hasSelectedText():
00352       if len(self.selectedText()) > 0:
00353         self.clip.setText(self.selectedText())
00354     self.moveCursor(QTextEdit.MoveEnd, 0)
00355     return
00356 
00357   def contentsContextMenuEvent(self,ev):
00358     """
00359     Suppress the right button context menu.
00360     Instead paste the contents of the clipboard.
00361     """
00362     self.__insertText(self.clip.text())
00363     ev.accept()
00364     return

Generated on Fri Jul 21 13:26:31 2006 for LATTE R04-12-00 by doxygen 1.4.3