fix failed parsing of attributes with spaces in them in xml viewer
[sface.git] / sface / xmlwidget.py
index a2d3ec2..be53182 100644 (file)
@@ -1,4 +1,5 @@
 import os
+import shlex
 import sys
 
 from PyQt4.QtCore import *
@@ -85,7 +86,7 @@ class DomModel(QAbstractItemModel):
         if not index.isValid():
             return Qt.ItemIsEnabled
         return Qt.ItemIsEnabled | Qt.ItemIsSelectable
-        
+
     def headerData(self, section, orientation, role):
         return QVariant()
 
@@ -176,7 +177,7 @@ class XmlWindow(QDialog):
         self.model = None
         self.title = title
 
-        self.view = XmlView(self)
+        self.view = self.initView()
         self.delegate = XmlDelegate(self)
         self.view.setItemDelegate(self.delegate)
         self.delegate.insertNodeDelegate('element', ElemNodeDelegate())
@@ -188,6 +189,9 @@ class XmlWindow(QDialog):
 
         self.updateView()
 
+    def initView(self):
+        return XmlView(self)
+
     def show(self):
         self.updateView()
         QDialog.show(self)
@@ -228,6 +232,8 @@ class XmlDelegate(QItemDelegate):
             del self.delegates[nodeType]
     
     def paint(self, painter, option, index):
+        if isinstance(index.model().data(index),QVariant):
+            return
         nodeType = index.model().data(index).property('nodeType')
         delegate = self.delegates.get(str(nodeType.toString()))
         #print "TYPE:", str(type(str(nodeType.toString())))
@@ -244,6 +250,8 @@ class XmlDelegate(QItemDelegate):
 
     def sizeHint(self, option, index):
         fm = option.fontMetrics
+        if isinstance(index.model().data(index),QVariant):
+            return QSize(0, 0)
         text = index.model().data(index).property('content').toString()
         document = QTextDocument()
         document.setDefaultFont(option.font)
@@ -263,25 +271,35 @@ class ElemNodeDelegate(QAbstractItemDelegate):
         highGlobPattern = '&lt;<b>%s</b>%s&gt;'
         highAttPattern = ' <b>%s</b>="%s"'
         def getHtmlText(plainText, globPattern, attPattern):
-            print "PLAIN TEXT:", plainText
+#            print "PLAIN TEXT:", plainText
             tmp = plainText.split(' ', 1)
-            print "TMP:", tmp
+#            print "TMP:", tmp
             elemName = tmp[0]
             AttListHtml = ''
             if len(tmp) > 1:
                 # many elems don't have atts...
-                attList = tmp[1].split()
+                # use shlex.split so we can handle quoted strings with spaces
+                # in them, like <link enpoints="foo bar">. Note that there are
+                # documented problems with shlex.split and unicode, so we
+                # convert any potential unicode to a string first.
+                attList = shlex.split(str(tmp[1]))
                 for att in attList:
-                    tmp = att.split('=')
-                    attName = tmp[0]
-                    attValue = tmp[1][1:-1]
+                    tmp = att.split('=',1)
+                    if len(tmp)>=2:
+                        attName = tmp[0]
+                        attValue = tmp[1]
+                    else:
+                        # this shouldn't happen, but if it does, pretend the
+                        # attribute value is blank.
+                        attName = tmp[0]
+                        attValue = ""
                     AttListHtml += (nonHighAttPattern % (attName, attValue))
             html = (globPattern % (elemName, AttListHtml))
             return html
         def colorize(color, text):
             return '<font color=' + color + '>' + text + '</font>'
         text = str(index.model().data(index).property('content').toString())
-        print "TEXT:", text
+#        print "TEXT:", text
         if option.state & QStyle.State_Selected:
             htmlText = colorize(palette.highlightedText().color().name(),
                                 getHtmlText(text, highGlobPattern, highAttPattern))
@@ -293,7 +311,7 @@ class ElemNodeDelegate(QAbstractItemDelegate):
             if option.state & QStyle.State_Selected \
             else palette.base().color()
         painter.save()
-        print "COLOR:", color.name()
+#        print "COLOR:", color.name()
         # voodoo: if not highlighted, filling the rect
         # with the base color makes no difference
         painter.fillRect(option.rect, color)