X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=sface%2Fxmlwidget.py;h=2c0f53ca951386345026d328c45e5ad31a060ef2;hb=eb6b726661868a93d439c030ead00f4b7a2fe0a7;hp=a52522a512aaa36d414660f03f964feb30d35a09;hpb=349fb978a1b7a88e741beef6aea4ac3d98a56efd;p=sface.git diff --git a/sface/xmlwidget.py b/sface/xmlwidget.py index a52522a..2c0f53c 100644 --- a/sface/xmlwidget.py +++ b/sface/xmlwidget.py @@ -8,6 +8,17 @@ from PyQt4.QtXml import * from sface.config import config from sface.screens.sfascreen import SfaScreen +class nodeData(QVariant): + def __init__(self, *args, **kws): + QVariant.__init__(self, *args, **kws) + self.type = None + + def setType(self, typ): + self.type = typ + + def getType(self): + return self.type + class DomModel(QAbstractItemModel): def __init__(self, document, parent = 0): QAbstractItemModel.__init__(self, parent) @@ -23,7 +34,7 @@ class DomModel(QAbstractItemModel): self.rootItem = DomItem(document, 0); def data(self, index, role = Qt.DisplayRole): - # sometimes it return a QString, sometimes a QVariant. not good. + # for interesting nodes, returns a dict wrapped into a QVariant. if not index.isValid(): return QVariant() if role != Qt.DisplayRole: @@ -37,13 +48,18 @@ class DomModel(QAbstractItemModel): qslist = QStringList() for i in range(attributeMap.count()): attr = attributeMap.item(i) - elem = ' %s="%s"' % (attr.nodeName(), attr.nodeValue()) + elem = ' %s="%s"' % (attr.nodeName(), attr.nodeValue()) qslist.append(elem) - return QString('<%s%s>'% (node.nodeName(), qslist.join(' '))) + ElemNameAndAtts = '%s%s'% (node.nodeName(), qslist.join(' ')) + answer = nodeData(ElemNameAndAtts) + answer.setType('element') + return answer elif node.nodeType() == QDomNode.AttributeNode: - return QString('Whozat?!') + return QVariant() elif node.nodeType() == QDomNode.TextNode: - return node.nodeValue() + answer = nodeData(node.nodeValue()) + answer.setType('text') + return answer elif node.nodeType() == QDomNode.CDATASectionNode: return QString('unsupported node type') elif node.nodeType() == QDomNode.EntityReferenceNode: @@ -52,9 +68,10 @@ class DomModel(QAbstractItemModel): 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()) + answer = nodeData(node.nodeValue()) + answer.setType('comment') + return answer elif node.nodeType() == QDomNode.DocumentNode: return QString('unsupported node type') elif node.nodeType() == QDomNode.DocumentTypeNode: @@ -148,9 +165,15 @@ class DomItem: return self.rowNumber class XmlView(QTreeView): - def __init__(self, parent): + def __init__(self, parent=None): QTreeView.__init__(self, parent) + delegate = XmlDelegate(self) + delegate.insertNodeDelegate('element', ElemNodeDelegate()) + delegate.insertNodeDelegate('text', TextNodeDelegate()) + delegate.insertNodeDelegate('comment', CommentNodeDelegate()) + self.setItemDelegate(delegate) + self.setAnimated(True) self.setItemsExpandable(True) self.setRootIsDecorated(True) @@ -158,70 +181,84 @@ class XmlView(QTreeView): 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): +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): - text = index.model().data(index) + nodeData = index.model().data(index) + nodeType = nodeData.getType() + delegate = self.delegates.get(nodeType) + if delegate is not None: + delegate.paint(painter, option, index) + else: + QItemDelegate.paint(self, painter, option, index) + + def sizeHint(self, option, index): + fm = option.fontMetrics + nodeData = index.model().data(index) + nodeType = nodeData.getType() + text = nodeData.toString() + if nodeType == 'element' or nodeType == 'comment': + numlines = 1 + elif nodeType == 'text': + nl = text.count('\n') + numlines = nl if nl > 0 else 1 + else: + numlines = 1 + 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) * numlines) + +class ElemNodeDelegate(QAbstractItemDelegate): + def paint(self, painter, option, 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): + tmp = plainText.split(' ', 1) + 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 += (attPattern % (attName, attValue)) + html = (globPattern % (elemName, AttListHtml)) + return html + def colorize(color, text): + return '' + text + '' + nodeData = index.model().data(index) + nodeType = nodeData.getType() + # Uff... QString Vs string... + text = str(nodeData.toString()) 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('')))) + htmlText = colorize(palette.highlightedText().color().name(), + getHtmlText(text, highGlobPattern, highAttPattern)) + document.setHtml(QString(htmlText)) else: - document.setHtml(text) + htmlText = getHtmlText(text, nonHighGlobPattern, nonHighAttPattern) + document.setHtml(QString(htmlText)) color = palette.highlight().color() \ if option.state & QStyle.State_Selected \ else palette.base().color() @@ -233,12 +270,66 @@ class XmlDelegate(QAbstractItemDelegate): document.drawContents(painter) painter.restore() - def sizeHint(self, option, index): - fm = option.fontMetrics - text = index.model().data(index) +class TextNodeDelegate(QAbstractItemDelegate): + def paint(self, painter, option, index): + palette = QApplication.palette() document = QTextDocument() document.setDefaultFont(option.font) + def verbatimize(text): + text.replace('\n', '
') + return '
' + text + '' + text + ''
+        nodeData = index.model().data(index)
+        nodeType = nodeData.getType()
+        text = nodeData.toString()
+        if option.state & QStyle.State_Selected:
+            htmlText = colorize(palette.highlightedText().color().name(),
+                                verbatimize(text))
+            document.setHtml(QString(htmlText))
+        else:
+            htmlText = verbatimize(text)
+            document.setHtml(QString(htmlText))
+        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()
+
+class CommentNodeDelegate(QAbstractItemDelegate):
+    def paint(self, painter, option, index): 
+        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)
-        # the +5 is for margin. The +4 is voodoo;
-        # fm.height just give it too small.
-        return QSize(document.idealWidth() + 5, fm.height() + 4)
+    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()
+
+