summaryrefslogtreecommitdiff
path: root/portato/gui/qt/terminal.py
diff options
context:
space:
mode:
Diffstat (limited to 'portato/gui/qt/terminal.py')
-rw-r--r--portato/gui/qt/terminal.py378
1 files changed, 0 insertions, 378 deletions
diff --git a/portato/gui/qt/terminal.py b/portato/gui/qt/terminal.py
deleted file mode 100644
index a70e56b..0000000
--- a/portato/gui/qt/terminal.py
+++ /dev/null
@@ -1,378 +0,0 @@
-# -*- coding: utf-8 -*-
-#
-# File: portato/gui/qt/terminal.py
-# This file is part of the Portato-Project, a graphical portage-frontend.
-#
-# Copyright (C) 2007 René 'Necoro' Neumann
-# This is free software. You may redistribute copies of it under the terms of
-# the GNU General Public License version 2.
-# There is NO WARRANTY, to the extent permitted by law.
-#
-# Written by René 'Necoro' Neumann <necoro@necoro.net>
-
-from PyQt4 import Qt
-
-from Queue import Queue
-from threading import Thread, currentThread
-from os import read, close
-import errno
-
-from portato.gui.wrapper import Console
-from portato.helper import debug
-
-try:
- from curses.ascii import ctrl
-except ImportError: # emulate ctrl-behavior for known values
- def ctrl (val):
- if val == "H": return '\x08'
- elif val == "W": return '\x17'
- else: debug("unknown error passed to emulated ctrl: %s",val)
-
-
-class WriteEvent (Qt.QEvent):
- TYPE = Qt.QEvent.Type(1001)
-
- def __init__ (self, string):
- Qt.QEvent.__init__(self, self.TYPE)
- self.string = string
-
- def get_string(self):
- return self.string
-
-class DeleteEvent (Qt.QEvent):
- TYPE = Qt.QEvent.Type(1002)
- (DEL_CHAR, DEL_WORD, DEL_LINE, DEL_LINE_REVERT) = range(4)
-
- def __init__ (self, type = DEL_CHAR):
- Qt.QEvent.__init__(self, self.TYPE)
- self.del_type = type
-
-class SetPtyEvent (Qt.QEvent):
- TYPE = Qt.QEvent.Type(1003)
-
- def __init__ (self, pty):
- Qt.QEvent.__init__(self, self.TYPE)
- self.pty = pty
-
-class BoldFormat (Qt.QTextCharFormat):
-
- def __init__(self):
- Qt.QTextCharFormat.__init__(self)
- self.setFontWeight(Qt.QFont.Bold)
-
-class UnderlineFormat (Qt.QTextCharFormat):
-
- def __init__(self):
- Qt.QTextCharFormat.__init__(self)
- self.setFontUnderline(True)
-
-class ColorFormat (Qt.QTextCharFormat):
-
- def __init__(self, color):
- Qt.QTextCharFormat.__init__(self)
-
- self.setForeground(Qt.QBrush(Qt.QColor(color)))
-
-# we only support a subset of the commands
-esc_seq = ("\x1b", "[")
-reset_seq = "39;49;00"
-seq_end = "m"
-seq_sep = ";"
-backspace = ctrl("H")
-backword = ctrl("W")
-cr = "\r"
-
-title_seq = ("\x1b", "]")
-title_end = "\x07"
-
-# the attributes
-attr = {}
-attr[0] = None # normal
-attr[1] = BoldFormat() # bold
-attr[4] = UnderlineFormat() # underline
-attr[30] = ColorFormat("white") # should be black - but is inverted
-attr[31] = ColorFormat("red")
-attr[32] = ColorFormat("lime") # lime looks better on black than normal green
-attr[33] = ColorFormat("yellow")
-attr[34] = ColorFormat("blue")
-attr[35] = ColorFormat("magenta")
-attr[36] = ColorFormat("cyan")
-attr[37] = ColorFormat("white")
-attr[39] = None # default - use white too
-
-class QtConsole (Console, Qt.QTextEdit):
- """Self implemented emulation of a terminal emulation.
- This only supports a subset of instructions known to normal terminals."""
-
- def __init__ (self, parent):
- """Constructor.
-
- @param parent: parent widget
- @type parent: Qt.QWidget"""
-
- Qt.QTextEdit.__init__(self, parent)
-
- self.pty = None
- self.running = False
- self.formatQueue = Queue()
- self.title = None
- self.writeQueue = ""
- self.isNotWrapping = False
-
- self.setContextMenuPolicy(Qt.Qt.ActionsContextMenu)
-
- # set black bg
- self.palette().setColor(Qt.QPalette.Base, Qt.QColor("black"))
-
- # set highlighting colors ... XXX: for some reasons this does not work ... Qt sucks
- self.palette().setColor(Qt.QPalette.Highlight, Qt.QColor("white"))
- self.palette().setColor(Qt.QPalette.HighlightedText, Qt.QColor("black"))
-
- self.setBackgroundRole(Qt.QPalette.Base)
- self.setAutoFillBackground(True)
-
- # set standard char format to "white"
- self.stdFormat = self.currentCharFormat()
- self.stdFormat.merge(ColorFormat("white"))
- self.setCurrentCharFormat(self.stdFormat)
-
- self.setReadOnly(True)
-
- def _deletePrev (self, type):
- """Deletes the previous character/word."""
- if type == DeleteEvent.DEL_CHAR: # just the prev char
- self.textCursor().deletePreviousChar()
-
- elif type == DeleteEvent.DEL_WORD:
- self.textCursor().select(Qt.QTextCursor.WordUnderCursor)
- self.textCursor().removeSelectedText()
-
- elif type == DeleteEvent.DEL_LINE:
- self.moveCursor(Qt.QTextCursor.StartOfLine, Qt.QTextCursor.KeepAnchor)
- self.textCursor().removeSelectedText()
- self.setLineWrapMode(Qt.QTextEdit.NoWrap)
- self.isNotWrapping = True
-
- elif type == DeleteEvent.DEL_LINE_REVERT:
- self.setLineWrapMode(Qt.QTextEdit.WidgetWidth)
- self.isNotWrapping = False
-
- def event (self, event):
- if event.type() == WriteEvent.TYPE:
- self._write(event.get_string())
- event.accept()
- return True
-
- elif event.type() == DeleteEvent.TYPE:
- self._deletePrev(event.del_type)
- event.accept()
- return True
-
- elif event.type() == SetPtyEvent.TYPE:
- self.set_pty(event.pty)
- event.accept()
- return True
-
- event.ignore()
- return False
-
- def _write (self, text):
- """Writes some text. A text of "\\x1b" signals _write() to reload
- the current char format.
-
- @param text: the text to print
- @type text: string"""
-
- if text == esc_seq[0]: # \x1b -> reload format
- self.setCurrentCharFormat(self.get_format())
- else:
- if not self.textCursor().atEnd() and not self.isNotWrapping: # move cursor and re-set format
- f = self.currentCharFormat()
- self.moveCursor(Qt.QTextCursor.End)
- self.setCurrentCharFormat(f)
-
- # insert the text
- self.insertPlainText(text)
-
- # scroll down if needed
- if not self.isNotWrapping: self.ensureCursorVisible()
-
- def write(self, text):
- """Convenience function for emitting the writing signal."""
-
- def send (text):
- Qt.QCoreApplication.postEvent(self, WriteEvent(text))
-
- if text is None:
- send(self.writeQueue)
- self.writeQueue = ""
-
- elif text == esc_seq[0]:
- send(self.writeQueue)
- send(text)
- self.writeQueue = ""
-
- elif len(self.writeQueue) == 4:
- send(self.writeQueue+text)
- self.writeQueue = ""
-
- else:
- self.writeQueue = self.writeQueue + text
-
- def start_new_thread (self):
- """Starts a new thread, which will listen for some input.
- @see: QtTerminal.__run()"""
- self.run = True
- self.current = Thread(target=self.__run, name="QtTerminal Listener")
- self.current.setDaemon(True) # close application even if this thread is running
- self.current.start()
-
- def set_pty (self, pty):
- if currentThread().getName() != "MainThread":
- Qt.QCoreApplication.postEvent(self, SetPtyEvent(pty))
- return
-
- if not self.running:
- self.pty = pty
- self.start_new_thread()
- self.running = True
-
- else: # quit current thread
- self.run = False
- self.clear()
- close(self.pty)
-
- self.pty = pty # set this after clearing to lose no chars :)
- self.start_new_thread()
-
- def __run (self):
- """This function is mainly a loop, which looks for some new input at the terminal,
- and parses it for text attributes."""
-
- got_cr = False
-
- while self.run:
- try:
- s = read(self.pty, 1)
- except OSError, e: # bug in Python with the subprocess module
- if e.errno == errno.EINTR:
- continue
- raise
-
- if s == "": break # nothing read -> finish
-
- if self.isNotWrapping and s == "\n":
- self.write(None)
- Qt.QCoreApplication.postEvent(self, DeleteEvent(DeleteEvent.DEL_LINE_REVERT))
-
- if got_cr:
- got_cr = False
- if s == "\n": # got \r\n, which is ok
- self.write(s)
- continue
- else:
- self.write(None)
- Qt.QCoreApplication.postEvent(self, DeleteEvent(DeleteEvent.DEL_LINE))
-
- if s == backspace: # BS
- self.write(None)
- Qt.QCoreApplication.postEvent(self, DeleteEvent())
-
- elif s == backword:
- self.write(None)
- Qt.QCoreApplication.postEvent(self, DeleteEvent(DeleteEvent.DEL_WORD))
-
- elif s == cr: # CR -> make the line being deleted
- got_cr = True
-
- elif s == esc_seq[0]: # -> 0x27
- s = read(self.pty, 1)
- if s == esc_seq[1]: # -> [
- while True:
- _s = read(self.pty, 1)
- s += _s
- if _s == seq_end: break
- self.parse_seq(s[1:-1])
-
- elif s == title_seq[1]: # -> ]
- while True:
- _s = read(self.pty, 1)
- s += _s
- if _s == title_end: break
-
- self.parse_title(s[1:-1])
- else:
- self.write(esc_seq[0]+s)
-
- elif not got_cr:
- self.write(s)
-
- self.write(None)
-
- def parse_seq (self, seq):
- """Parses a sequence of bytes.
- If a new attribute has been encountered, a new format is created and added
- to the internal format queue.
-
- @param seq: sequence to parse
- @type seq: string"""
-
- global attr # the dict of attributes
-
- format = self.virgin_format()
-
- if seq != reset_seq: # resettet -> done
- seq = seq.split(seq_sep)
- for s in seq:
- try:
- s = int(s)
- except ValueError:
- format = self.virgin_format()
- break
-
- try:
- if attr[s] is not None:
- format.merge(attr[s])
- else:
- format = self.virgin_format()
- break
- except KeyError: # no such attribute
- format = self.virgin_format()
- break
-
- self.add_format(format)
- self.write(esc_seq[0]) # write \x1b to signal the occurence of a new format
-
- def parse_title (self, seq):
- if not seq.startswith("0;"):
- return
-
- self.title = seq[2:]
-
- def get_window_title (self):
- return self.title
-
- def add_format (self, format):
- """Adds a format to the queue.
- We have to take a queue, because the write-signals might occur asynchronus,
- so we set a format for the wrong characters.
-
- @param format: the format to add
- @type format: Qt.QTextCharFormat"""
-
- self.formatQueue.put(format)
-
- def get_format (self):
- """Returns a format from the queue.
- We have to take a queue, because the write-signals might occur asynchronus,
- so we set a format for the wrong characters.
-
- @returns: the popped format
- @rtype: Qt.QTextCharFormat"""
-
- return self.formatQueue.get()
-
- def virgin_format (self):
- """The normal standard format. It is necessary to create it as a new one for some
- dubious reasons ... only Qt.QGod knows why."""
- return Qt.QTextCharFormat(self.stdFormat)