X-Git-Url: http://git.onelab.eu/?p=sface.git;a=blobdiff_plain;f=sface%2Fxmlwidget.py;fp=sface%2Fxmlwidget.py;h=a52522a512aaa36d414660f03f964feb30d35a09;hp=0000000000000000000000000000000000000000;hb=349fb978a1b7a88e741beef6aea4ac3d98a56efd;hpb=8f437c02a1aedd746d4a7b4c51042483e2939d50 diff --git a/sface/xmlwidget.py b/sface/xmlwidget.py new file mode 100644 index 0000000..a52522a --- /dev/null +++ b/sface/xmlwidget.py @@ -0,0 +1,244 @@ +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) + 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 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) + 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(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)