From: root Date: Mon, 29 Nov 2010 17:41:56 +0000 (-0500) Subject: fix merge between onelab and princeton repositories X-Git-Tag: sface-0.1-4~4 X-Git-Url: http://git.onelab.eu/?p=sface.git;a=commitdiff_plain;h=1dbdb55c8d56e3c82047dc29a6789183f76d07a7;hp=4aefa573d22829761128561c2366c59ce247cc46 fix merge between onelab and princeton repositories --- diff --git a/sface/logwindow.py b/sface/logwindow.py index c5c41dd..fd252ef 100644 --- a/sface/logwindow.py +++ b/sface/logwindow.py @@ -6,6 +6,8 @@ from PyQt4.QtGui import * from sface.config import config +import time + class LogIO(QObject): def __init__(self, parent, old_stdout): QObject.__init__(self, parent) @@ -17,7 +19,12 @@ class LogIO(QObject): self.parent().update() def getText(self): - return self.io.getvalue() + val = self.io.getvalue() + # looks like there is no other way + # to empty the StringIO + del self.io + self.io = StringIO() + return val class LogWindow(QDialog): def __init__(self, parent=None): @@ -40,10 +47,7 @@ class LogWindow(QDialog): sys.stderr = self.logio def update(self): - self.text.setText(self.logio.getText()) + self.text.insertPlainText(self.logio.getText()) c = self.text.textCursor() c.movePosition(QTextCursor.End) self.text.setTextCursor(c) - - - diff --git a/sface/rspecwindow.py b/sface/rspecwindow.py index a0741c4..f9bca14 100644 --- a/sface/rspecwindow.py +++ b/sface/rspecwindow.py @@ -5,20 +5,14 @@ from PyQt4.QtCore import * from PyQt4.QtGui import * from PyQt4.QtXml import * +from sface.xmlwidget import * from sface.config import config from sface.screens.sfascreen import SfaScreen -class RSpecView(QTreeView): +class RSpecView(XmlView): def __init__(self, parent): - QTreeView.__init__(self, parent) - - self.setAnimated(True) - self.setItemsExpandable(True) - self.setRootIsDecorated(True) - self.setHeaderHidden(True) - self.setAttribute(Qt.WA_MacShowFocusRect, 0) - self.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding) + XmlView.__init__(self, parent) def expandMatchingText(self, txt): self.collapseAll() @@ -48,227 +42,19 @@ class RSpecView(QTreeView): index = model.index(r, 0) search(index) - -class DomModel(QAbstractItemModel): - def __init__(self, document, parent = 0): - QAbstractItemModel.__init__(self, parent) - self.domDocument = document - # one of the children of the rootItem is the 'xml' thing. - # here I delete it. - childList = document.childNodes() - for i in range(childList.count()): - currElem = childList.item(i) - if (currElem.nodeType() == QDomNode.ProcessingInstructionNode): - document.removeChild(currElem) - break - self.rootItem = DomItem(document, 0); - - def data(self, index, role = Qt.DisplayRole): - # sometimes it return a QString, sometimes a QVariant. not good. - if not index.isValid(): - return QVariant() - if role != Qt.DisplayRole: - return QVariant() - node = index.internalPointer().node() - attributeMap = node.attributes() - - col = index.column() - if col == 0: - if node.nodeType() == QDomNode.ElementNode: - qslist = QStringList() - for i in range(attributeMap.count()): - attr = attributeMap.item(i) - elem = ' %s="%s"' % (attr.nodeName(), attr.nodeValue()) - qslist.append(elem) - return QString('<%s%s>'% (node.nodeName(), qslist.join(' '))) - elif node.nodeType() == QDomNode.AttributeNode: - return QString('Whozat?!') - elif node.nodeType() == QDomNode.TextNode: - return node.nodeValue() - elif node.nodeType() == QDomNode.CDATASectionNode: - return QString('unsupported node type') - elif node.nodeType() == QDomNode.EntityReferenceNode: - return QString('unsupported node type') - elif node.nodeType() == QDomNode.EntityNode: - return QString('unsupported node type') - elif node.nodeType() == QDomNode.ProcessingInstructionNode: - return QVariant() - #return node.nodeName() - elif node.nodeType() == QDomNode.CommentNode: - return QString('#').append(node.nodeValue()) - elif node.nodeType() == QDomNode.DocumentNode: - return QString('unsupported node type') - elif node.nodeType() == QDomNode.DocumentTypeNode: - return QString('unsupported node type') - elif node.nodeType() == QDomNode.DocumentFragmentNode: - return QString('unsupported node type') - elif node.nodeType() == QDomNode.NotationNode: - return QString('unsupported node type') - elif node.nodeType() == QDomNode.BaseNode: - return QString('unsupported node type') - elif node.nodeType() == QDomNode.CharacterDataNode: - return QString('unsupported node type') - else: - return QVariant() - else: - return QVariant() - - def flags(self, index): - if not index.isValid(): - return Qt.ItemIsEnabled - return Qt.ItemIsEnabled | Qt.ItemIsSelectable - - def headerData(self, section, orientation, role): - return QVariant() - - def index(self, row, column, parent=None): - if not parent or not parent.isValid(): - parentItem = self.rootItem - else: - parentItem = parent.internalPointer() - - childItem = parentItem.child(row) - # childItem would be None to say "false"? - if childItem: - return self.createIndex(row, column, childItem) - else: - return QModelIndex() - - def parent(self, child): - if not child.isValid(): - return QModelIndex() - childItem = child.internalPointer() - parentItem = childItem.parent() - - if not parentItem or parentItem == self.rootItem: - return QModelIndex() - return self.createIndex(parentItem.row(), 0, parentItem) - - def rowCount(self, parent=None): - if not parent or not parent.isValid(): - parentItem = self.rootItem - else: - parentItem = parent.internalPointer() - - return parentItem.node().childNodes().count() - - def columnCount(self, parent): - # just one column we'll print tag name (and attributes) or the - # tag content - return 1 - - -class DomItem: - # wrapper around PyQt4.QtXml.QDomNode it keeps an hash of - # childrens for performance reasons - - def __init__(self, node, row, parent = 0): - # node is of type PyQt4.QtXml.QDomNode - self.domNode = node - self.parentItem = parent - self.rowNumber = row - self.childItems = {} - - def child(self, i): - if i in self.childItems: - return self.childItems[i] - if i >= 0 and i < self.domNode.childNodes().count(): - childNode = self.domNode.childNodes().item(i) - childItem = DomItem(childNode, i, self) - self.childItems[i] = childItem - return childItem - return None - - def parent(self): - return self.parentItem - - def node(self): - return self.domNode - - def row(self): - return self.rowNumber - - -class RSpecWindow(QDialog): +class RSpecWindow(XmlWindow): def __init__(self, parent=None): - QDialog.__init__(self, parent) - self.setWindowTitle("RSpec View") - - self.document = None - self.model = None - + XmlWindow.__init__(self, parent, 'RSpec Window') self.view = RSpecView(self) - self.delegate = RSpecDelegate(self) - self.view.setItemDelegate(self.delegate) - layout = QVBoxLayout() - layout.addWidget(self.view) - self.setLayout(layout) - self.updateView() - - def show(self): - self.updateView() - QDialog.show(self) - def showNode(self, hostname): self.view.expandMatchingText(hostname) def updateView(self): - del self.document - del self.model - self.document = None - self.model = None + XmlWindow.updateView(self) rspec_file = config.getSliceRSpecFile() if not os.path.exists(rspec_file): return - self.document = QDomDocument("RSpec") self.document.setContent(open(rspec_file,'r').read()) - self.model = DomModel(self.document, self) - - self.view.setModel(self.model) - self.view.expand(self.model.index(0, 0)) #expand first level only - - -class RSpecDelegate(QAbstractItemDelegate): - - def __init__(self, parent=None): - QAbstractItemDelegate.__init__(self, parent) - - def paint(self, painter, option, index): - text = index.model().data(index) - palette = QApplication.palette() - document = QTextDocument() - document.setDefaultFont(option.font) - if option.state & QStyle.State_Selected: - rx = QRegExp(QString('')) - rx.setMinimal(True) - # If selected, I remove the by hand, - # and give the highlight color - document.setHtml(QString("%2") \ - .arg(palette.highlightedText().color().name())\ - .arg(text.replace(rx, QString('')). - replace(QString(''),QString('')))) - else: - document.setHtml(text) - color = palette.highlight().color() \ - if option.state & QStyle.State_Selected \ - else palette.base().color() - painter.save() - # voodoo: if not highlighted, filling the rect - # with the base color makes no difference - painter.fillRect(option.rect, color) - painter.translate(option.rect.x(), option.rect.y()) - document.drawContents(painter) - painter.restore() - - def sizeHint(self, option, index): - fm = option.fontMetrics - text = index.model().data(index) - document = QTextDocument() - document.setDefaultFont(option.font) - document.setHtml(text) - # the +5 is for margin. The +4 is voodoo; - # fm.height just give it too small. - return QSize(document.idealWidth() + 5, fm.height() + 4) diff --git a/sface/sfiprocess.py b/sface/sfiprocess.py index a9ac769..8bb6627 100644 --- a/sface/sfiprocess.py +++ b/sface/sfiprocess.py @@ -5,6 +5,7 @@ import time from PyQt4.QtCore import * from sface.config import config +from sface.xmlrpcwindow import XmlrpcTracker def find_executable(exec_name): """find the given executable in $PATH""" @@ -26,6 +27,12 @@ class SfiProcess(QObject): self.process.setEnvironment(env) self.connect(self.process, SIGNAL("finished(int, QProcess::ExitStatus)"), self.processFinished) + + self.xmlrpctracker = XmlrpcTracker() + # in case self.output is read by the XmlrpcTracker before any + # readyReadStandardOutput signal + self.output = '' + self.connect(self.process, SIGNAL("readyReadStandardOutput()"), self.processStandardOutput) self.connect(self.process, SIGNAL("readyReadStandardError()"), @@ -33,6 +40,9 @@ class SfiProcess(QObject): def __init_command(self, args): self.args = QStringList() + if config.debug: + # this shows xmlrpc conversation, see sfi.py docs. + self.args << QString('-D') for arg in args: self.args << QString(arg) @@ -127,3 +137,5 @@ class SfiProcess(QObject): if config.verbose: command = "%s %s" % (self.exe, self.args.join(" ")) print time.strftime('%M:%S'),"[%.3f s]"%(time.time()-self._trace),command,'Done' + self.xmlrpctracker.getAndPrint(self.output) + diff --git a/sface/xmlrpcwindow.py b/sface/xmlrpcwindow.py new file mode 100644 index 0000000..483d443 --- /dev/null +++ b/sface/xmlrpcwindow.py @@ -0,0 +1,56 @@ +import re +from PyQt4.QtXml import QDomDocument +from sface.xmlwidget import XmlWindow, DomModel + +class XmlrpcTracker(): + def __init__(self): + self.xmlrpcWindow = XmlrpcWindow() + + def getAndPrint(self, rawOutput): + self.store(rawOutput) + self.extractXml() + self.xmlrpcWindow.setData(self.xml) + self.showXmlrpc() + + def showXmlrpc(self): + self.xmlrpcWindow.show() + self.xmlrpcWindow.resize(500, 640) + self.xmlrpcWindow.raise_() + self.xmlrpcWindow.activateWindow() + + def store(self, rawOutput): + self.rawOutput = rawOutput + + def extractXml(self): + pttrnAsk = '.*?' + pttrnAns = '.*?' + answers = re.compile(pttrnAsk, re.DOTALL).findall(self.rawOutput) + replies = re.compile(pttrnAns, re.DOTALL).findall(self.rawOutput) + # cleaning + answers = map(lambda x: x.replace('\\n','\n'), answers) + replies = map(lambda x: x.replace('\\n','\n').replace("'\nbody: '", ''), replies) + replies.reverse() # so that I use pop() as popleft + # A well-formed XML document must have one, and only one, top-level element + self.xml = '' + for ans in answers: + self.xml += ans + replies.pop() + self.xml += '' + + def stats(self): + # statistics: round-trip time, size of the com + pass + +class XmlrpcWindow(XmlWindow): + def __init__(self, parent=None): + # super __init__() calls updateView, + # which assumes you have some data + self.data = '' + XmlWindow.__init__(self, parent, 'XMLRPC window') + + def setData(self, XmlrpcCom): + self.data = XmlrpcCom + + def updateView(self): + XmlWindow.updateView(self) + + self.document.setContent(self.data) diff --git a/sface/xmlwidget.py b/sface/xmlwidget.py new file mode 100644 index 0000000..a2d3ec2 --- /dev/null +++ b/sface/xmlwidget.py @@ -0,0 +1,347 @@ +import os +import sys + +from PyQt4.QtCore import * +from PyQt4.QtGui import * +from PyQt4.QtXml import * + +from sface.config import config +from sface.screens.sfascreen import SfaScreen + +class DomModel(QAbstractItemModel): + def __init__(self, document, parent = 0): + QAbstractItemModel.__init__(self, parent) + self.domDocument = document + # one of the children of the rootItem is the 'xml' thing. + # here I delete it. + childList = document.childNodes() + for i in range(childList.count()): + currElem = childList.item(i) + if (currElem.nodeType() == QDomNode.ProcessingInstructionNode): + document.removeChild(currElem) + break + self.rootItem = DomItem(document, 0); + + def data(self, index, role = Qt.DisplayRole): + # sometimes it return a QString, sometimes a QVariant. not good. + if not index.isValid(): + return QVariant() + if role != Qt.DisplayRole: + return QVariant() + node = index.internalPointer().node() + attributeMap = node.attributes() + + col = index.column() + if col == 0: + if node.nodeType() == QDomNode.ElementNode: + qslist = QStringList() + for i in range(attributeMap.count()): + attr = attributeMap.item(i) + elem = ' %s="%s"' % (attr.nodeName(), attr.nodeValue()) + qslist.append(elem) + ElemNameAndAtts = '%s%s'% (node.nodeName(), qslist.join(' ')) + obj = QObject() + obj.setProperty('nodeType', QString('element')) + obj.setProperty('content', ElemNameAndAtts) + return obj + elif node.nodeType() == QDomNode.AttributeNode: + return QVariant() + elif node.nodeType() == QDomNode.TextNode: + obj = QObject() + obj.setProperty('nodeType', QString('text')) + obj.setProperty('content', node.nodeValue()) + return obj + elif node.nodeType() == QDomNode.CDATASectionNode: + return QString('unsupported node type') + elif node.nodeType() == QDomNode.EntityReferenceNode: + return QString('unsupported node type') + elif node.nodeType() == QDomNode.EntityNode: + return QString('unsupported node type') + elif node.nodeType() == QDomNode.ProcessingInstructionNode: + return QVariant() + elif node.nodeType() == QDomNode.CommentNode: + obj = QObject() + obj.setProperty('nodeType', QString('comment')) + obj.setProperty('content', node.nodeValue()) + return obj + elif node.nodeType() == QDomNode.DocumentNode: + return QString('unsupported node type') + elif node.nodeType() == QDomNode.DocumentTypeNode: + return QString('unsupported node type') + elif node.nodeType() == QDomNode.DocumentFragmentNode: + return QString('unsupported node type') + elif node.nodeType() == QDomNode.NotationNode: + return QString('unsupported node type') + elif node.nodeType() == QDomNode.BaseNode: + return QString('unsupported node type') + elif node.nodeType() == QDomNode.CharacterDataNode: + return QString('unsupported node type') + else: + return QVariant() + else: + return QVariant() + + def flags(self, index): + if not index.isValid(): + return Qt.ItemIsEnabled + return Qt.ItemIsEnabled | Qt.ItemIsSelectable + + def headerData(self, section, orientation, role): + return QVariant() + + def index(self, row, column, parent=None): + if not parent or not parent.isValid(): + parentItem = self.rootItem + else: + parentItem = parent.internalPointer() + + childItem = parentItem.child(row) + # childItem would be None to say "false"? + if childItem: + return self.createIndex(row, column, childItem) + else: + return QModelIndex() + + def parent(self, child): + if not child.isValid(): + return QModelIndex() + childItem = child.internalPointer() + parentItem = childItem.parent() + + if not parentItem or parentItem == self.rootItem: + return QModelIndex() + return self.createIndex(parentItem.row(), 0, parentItem) + + def rowCount(self, parent=None): + if not parent or not parent.isValid(): + parentItem = self.rootItem + else: + parentItem = parent.internalPointer() + + return parentItem.node().childNodes().count() + + def columnCount(self, parent): + # just one column we'll print tag name (and attributes) or the + # tag content + return 1 + + +class DomItem: + # wrapper around PyQt4.QtXml.QDomNode it keeps an hash of + # childrens for performance reasons + + def __init__(self, node, row, parent = 0): + # node is of type PyQt4.QtXml.QDomNode + self.domNode = node + self.parentItem = parent + self.rowNumber = row + self.childItems = {} + + def child(self, i): + if i in self.childItems: + return self.childItems[i] + if i >= 0 and i < self.domNode.childNodes().count(): + childNode = self.domNode.childNodes().item(i) + childItem = DomItem(childNode, i, self) + self.childItems[i] = childItem + return childItem + return None + + def parent(self): + return self.parentItem + + def node(self): + return self.domNode + + def row(self): + return self.rowNumber + +class XmlView(QTreeView): + def __init__(self, parent): + QTreeView.__init__(self, parent) + + self.setAnimated(True) + self.setItemsExpandable(True) + self.setRootIsDecorated(True) + self.setHeaderHidden(True) + self.setAttribute(Qt.WA_MacShowFocusRect, 0) + self.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding) + +class XmlWindow(QDialog): + def __init__(self, parent=None, title='XML Window'): + QDialog.__init__(self, parent) + self.setWindowTitle(title) + + self.document = None + self.model = None + self.title = title + + self.view = XmlView(self) + self.delegate = XmlDelegate(self) + self.view.setItemDelegate(self.delegate) + self.delegate.insertNodeDelegate('element', ElemNodeDelegate()) + self.delegate.insertNodeDelegate('text', TextNodeDelegate()) + self.delegate.insertNodeDelegate('comment', CommentNodeDelegate()) + layout = QVBoxLayout() + layout.addWidget(self.view) + self.setLayout(layout) + + self.updateView() + + def show(self): + self.updateView() + QDialog.show(self) + + def updateView(self): + del self.document + del self.model + self.document = None + self.model = None + + self.document = QDomDocument(self.title) + self.model = DomModel(self.document, self) + + self.view.setModel(self.model) + self.view.expand(self.model.index(0, 0)) #expand first level only + + #move the code below to rspec window + rspec_file = config.getSliceRSpecFile() + if not os.path.exists(rspec_file): + return + + self.document.setContent(open(rspec_file,'r').read()) + + + +class XmlDelegate(QItemDelegate): + + def __init__(self, parent=None): + QAbstractItemDelegate.__init__(self, parent) + self.delegates = {} + + def insertNodeDelegate(self, nodeType, delegate): + delegate.setParent(self) + self.delegates[nodeType] = delegate + + def removeNodeDelegate(self, nodeType, delegate): + if nodeType in self.delegates: + del self.delegates[nodeType] + + def paint(self, painter, option, index): + nodeType = index.model().data(index).property('nodeType') + delegate = self.delegates.get(str(nodeType.toString())) + #print "TYPE:", str(type(str(nodeType.toString()))) + #print "DELEGS DICT:", self.delegates + #print "NODETYPE:", nodeType.toString() + if delegate is not None: + #print "WOW DELEG ISNT NONE" + delegate.paint(painter, option, index) + else: + #print "ELSE BRANCH" + # not sure this will ever work. this delegate + # doesn't know about my QObject strategy. + QItemDelegate.paint(self, painter, option, index) + + def sizeHint(self, option, index): + fm = option.fontMetrics + text = index.model().data(index).property('content').toString() + document = QTextDocument() + document.setDefaultFont(option.font) + document.setHtml(text) + # the +5 is for margin. The +4 is voodoo; + # fm.height just give it too small. + return QSize(document.idealWidth() + 5, fm.height() + 4) + +class ElemNodeDelegate(QAbstractItemDelegate): + def paint(self, painter, option, index): + text = index.model().data(index) + palette = QApplication.palette() + document = QTextDocument() + document.setDefaultFont(option.font) + nonHighGlobPattern = '<%s%s>' + nonHighAttPattern = ' %s="%s"' + highGlobPattern = '<%s%s>' + highAttPattern = ' %s="%s"' + def getHtmlText(plainText, globPattern, attPattern): + print "PLAIN TEXT:", plainText + tmp = plainText.split(' ', 1) + print "TMP:", tmp + elemName = tmp[0] + AttListHtml = '' + if len(tmp) > 1: + # many elems don't have atts... + attList = tmp[1].split() + for att in attList: + tmp = att.split('=') + attName = tmp[0] + attValue = tmp[1][1:-1] + AttListHtml += (nonHighAttPattern % (attName, attValue)) + html = (globPattern % (elemName, AttListHtml)) + return html + def colorize(color, text): + return '' + text + '' + text = str(index.model().data(index).property('content').toString()) + print "TEXT:", text + if option.state & QStyle.State_Selected: + htmlText = colorize(palette.highlightedText().color().name(), + getHtmlText(text, highGlobPattern, highAttPattern)) + document.setHtml(QString(htmlText)) + else: + htmlText = getHtmlText(text, nonHighGlobPattern, nonHighAttPattern) + document.setHtml(QString(htmlText)) + color = palette.highlight().color() \ + if option.state & QStyle.State_Selected \ + else palette.base().color() + painter.save() + print "COLOR:", color.name() + # voodoo: if not highlighted, filling the rect + # with the base color makes no difference + painter.fillRect(option.rect, color) + painter.translate(option.rect.x(), option.rect.y()) + document.drawContents(painter) + painter.restore() + + def sizeHint(self, option, index): + sizeHint(self, option, index) + +class TextNodeDelegate(QAbstractItemDelegate): + def paint(self, painter, option, index): + #print "TEXT DELEG CALLED" + paint(self, painter, option, index) + + def sizeHint(self, option, index): + sizeHint(self, option, index) + +class CommentNodeDelegate(QAbstractItemDelegate): + def paint(self, painter, option, index): + #print "TEXT DELEG CALLED" + paint(self, painter, option, index) + +def paint(self, painter, option, index): + text = index.model().data(index).property('content').toString() + palette = QApplication.palette() + document = QTextDocument() + document.setDefaultFont(option.font) + if option.state & QStyle.State_Selected: + rx = QRegExp(QString('')) + rx.setMinimal(True) + # If selected, I remove the by hand, + # and give the highlight color + document.setHtml(QString("%2") \ + .arg(palette.highlightedText().color().name())\ + .arg(text.replace(rx, QString('')). + replace(QString(''),QString('')))) + else: + document.setHtml(text) + color = palette.highlight().color() \ + if option.state & QStyle.State_Selected \ + else palette.base().color() + painter.save() + # voodoo: if not highlighted, filling the rect + # with the base color makes no difference + painter.fillRect(option.rect, color) + painter.translate(option.rect.x(), option.rect.y()) + document.drawContents(painter) + painter.restore() + +