diff options
Diffstat (limited to 'portato/gui')
-rw-r--r-- | portato/gui/qt/terminal.py | 193 | ||||
-rw-r--r-- | portato/gui/qt/ui/AboutDialog.ui | 6 | ||||
-rw-r--r-- | portato/gui/qt/ui/MainWindow.ui | 7 | ||||
-rw-r--r-- | portato/gui/qt/windows.py | 11 |
4 files changed, 213 insertions, 4 deletions
diff --git a/portato/gui/qt/terminal.py b/portato/gui/qt/terminal.py new file mode 100644 index 0000000..9fbc39c --- /dev/null +++ b/portato/gui/qt/terminal.py @@ -0,0 +1,193 @@ +# -*- 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 QtGui, QtCore + +from threading import Thread, Lock +from os import read + +from portato.gui.wrapper import Console +from portato.helper import debug + +class BoldFormat (QtGui.QTextCharFormat): + + def __init__(self): + QtGui.QTextCharFormat.__init__(self) + self.setFontWeight(QtGui.QFont.Bold) + +class UnderlineFormat (QtGui.QTextCharFormat): + + def __init__(self): + QtGui.QTextCharFormat.__init__(self) + self.setFontUnderline(True) + +class ColorFormat (QtGui.QTextCharFormat): + + def __init__(self, color): + QtGui.QTextCharFormat.__init__(self) + + self.setForeground(QtGui.QBrush(QtGui.QColor(color))) + +# we only support a subset of the commands +esc_seq = ("\x1b", "[") +reset_seq = "39;49;00" +seq_end = "m" +seq_sep = ";" +backspace = 8 +title_seq = ("\x1b", "]") +title_end = "\x07" + +attr = {} +attr[0] = None # normal +attr[1] = BoldFormat() # bold +attr[4] = UnderlineFormat() # underline +attr[30] = ColorFormat("black") +attr[31] = ColorFormat("red") +attr[32] = ColorFormat("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 + +class QtConsole (Console, QtGui.QTextEdit): + + def __init__ (self, parent): + QtGui.QTextEdit.__init__(self, parent) + + self.pty = None + self.running = False + self.stdFormat = self.currentCharFormat() + self.formatQueue = [] + self.formatLock = Lock() + self.title = None + + self.setReadOnly(True) + + QtCore.QObject.connect(self, QtCore.SIGNAL("doSomeWriting"), self._write) + QtCore.QObject.connect(self, QtCore.SIGNAL("deletePrevChar()"), self._deletePrev) + + def _deletePrev (self): + self.textCursor().deletePreviousChar() + + def _write (self, text): + if text == esc_seq[0]: + self.setCurrentCharFormat(self.get_format()) + else: + + if not self.textCursor().atEnd(): # move cursor and re-set format + f = self.currentCharFormat() + self.moveCursor(QtGui.QTextCursor.End) + self.setCurrentCharFormat(f) + + # insert the text + self.textCursor().insertText(text) + + # scroll down if needed + self.ensureCursorVisible() + + def write(self, text): + self.emit(QtCore.SIGNAL("doSomeWriting"), text) + + def set_pty (self, pty): + if not self.running: + self.pty = pty + + t = Thread(target=self.__run) + t.setDaemon(True) # close application even if this thread is running + t.start() + + self.running = True + else: + self.clear() + self.pty = pty # set this after clearing to lose no chars :) + + def __run (self): + while True: + s = read(self.pty, 1) + if s == "": break + + if ord(s) == backspace: + self.emit(QtCore.SIGNAL("deletePrevChar()")) + continue + + if 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]) + continue + + 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]) + continue + else: + self.write(esc_seq[0]+s) + + if s == "\r": continue + self.write(s) + + def parse_seq (self, seq): + global attr + + 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 + + if attr[s] is not None: + format.merge(attr[s]) + else: + format = self.virgin_format() + break + + self.add_format(format) + self.write(esc_seq[0]) + + 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): + self.formatLock.acquire() + self.formatQueue.append(format) + self.formatLock.release() + + def get_format (self): + self.formatLock.acquire() + f = self.formatQueue.pop(0) + self.formatLock.release() + return f + + def virgin_format (self): + return QtGui.QTextCharFormat(self.stdFormat) diff --git a/portato/gui/qt/ui/AboutDialog.ui b/portato/gui/qt/ui/AboutDialog.ui index e7cd4ff..5ed35e2 100644 --- a/portato/gui/qt/ui/AboutDialog.ui +++ b/portato/gui/qt/ui/AboutDialog.ui @@ -1,6 +1,6 @@ <ui version="4.0" > - <class>Dialog</class> - <widget class="QDialog" name="Dialog" > + <class>AboutDialog</class> + <widget class="QDialog" name="AboutDialog" > <property name="windowModality" > <enum>Qt::ApplicationModal</enum> </property> @@ -68,7 +68,7 @@ <connection> <sender>buttonBox</sender> <signal>accepted()</signal> - <receiver>Dialog</receiver> + <receiver>AboutDialog</receiver> <slot>accept()</slot> <hints> <hint type="sourcelabel" > diff --git a/portato/gui/qt/ui/MainWindow.ui b/portato/gui/qt/ui/MainWindow.ui index c982485..c7a5549 100644 --- a/portato/gui/qt/ui/MainWindow.ui +++ b/portato/gui/qt/ui/MainWindow.ui @@ -73,7 +73,7 @@ </widget> <widget class="QTabWidget" name="tabWidget" > <property name="currentIndex" > - <number>1</number> + <number>2</number> </property> <widget class="QWidget" name="pkgTab" > <attribute name="title" > @@ -345,6 +345,11 @@ p, li { white-space: pre-wrap; } </item> </layout> </widget> + <widget class="QWidget" name="consoleTab" > + <attribute name="title" > + <string>Console</string> + </attribute> + </widget> </widget> </widget> </item> diff --git a/portato/gui/qt/windows.py b/portato/gui/qt/windows.py index 475ac45..16152ec 100644 --- a/portato/gui/qt/windows.py +++ b/portato/gui/qt/windows.py @@ -21,6 +21,8 @@ from portato.backend.exceptions import * from portato.gui.gui_helper import Database, Config, EmergeQueue +from terminal import QtConsole + UI_DIR = DATA_DIR+"ui/" app = QtGui.QApplication([]) @@ -229,11 +231,20 @@ class MainWindow (Window): self.db = Database() self.db.populate() + # the two lists self.build_pkg_list() self.build_cat_list() QtCore.QObject.connect(self.selCatListModel, QtCore.SIGNAL("currentChanged(QModelIndex, QModelIndex)"), self.cb_cat_list_selected) QtCore.QObject.connect(self.selPkgListModel, QtCore.SIGNAL("currentChanged(QModelIndex, QModelIndex)"), self.cb_pkg_list_selected) + # build console + self.console = QtConsole(self.consoleTab) + self.consoleLayout = QtGui.QVBoxLayout() + self.consoleLayout.setMargin(0) + self.consoleLayout.setSpacing(0) + self.consoleTab.setLayout(self.consoleLayout) + self.consoleLayout.addWidget(self.console) + QtCore.QObject.connect(self.aboutAction, QtCore.SIGNAL("triggered()"), self.cb_about_triggered) self.show() |