changeset 78:85bfa15c01f1

Changed to json
author windel
date Mon, 12 Nov 2012 20:25:41 +0100
parents a5f3959bcab7
children 44f075fe71eb
files python/apps/diagrameditor.py
diffstat 1 files changed, 106 insertions(+), 166 deletions(-) [+]
line wrap: on
line diff
--- a/python/apps/diagrameditor.py	Sun Nov 11 14:08:51 2012 +0100
+++ b/python/apps/diagrameditor.py	Mon Nov 12 20:25:41 2012 +0100
@@ -2,8 +2,7 @@
 
 from PyQt4.QtGui import *
 from PyQt4.QtCore import *
-import sys, xml
-import xml.dom.minidom as md
+import sys, json
 
 """
  Author: Windel Bouwman
@@ -32,7 +31,7 @@
 
 class Connection(QGraphicsPathItem):
    """ Implementation of a connection between blocks """
-   def __init__(self, fromPort, toPort):
+   def __init__(self, fromPort=None, toPort=None):
       super(Connection, self).__init__()
       self.pos2 = self.fromPort = self.toPort = None
       self.setFlags(self.ItemIsSelectable | self.ItemClipsToShape)
@@ -45,32 +44,16 @@
       self.vias = []
       self.setFromPort(fromPort)
       self.setToPort(toPort)
-   def mouseDoubleClickEvent(self, event):
-      pos = event.scenePos()
-      pts = [self.getPos1()] + [v.pos() for v in self.vias] + [self.pos2]
-      idx = 0
-      tidx = 0
-      for p1, p2 in zip(pts[0:-1], pts[1:]):
-         l1 = QLineF(p1, p2)
-         l2 = QLineF(p1, pos)
-         l3 = QLineF(pos, p2)
-         d = l2.length() + l3.length() - l1.length()
-         if d < 5:
-            tidx = idx
-         idx += 1
-      self.addHandle(pos, tidx)
-   def addHandle(self, pos, idx=None):
-      hi = HandleItem(self)
-      if idx:
-         self.vias.insert(idx, hi)
-      else:
-         self.vias.append(hi)
-      def callback(p):
-         self.updateLineStukken()
-         return p
-      hi.posChangeCallbacks.append(callback)
-      hi.setPos(pos)
-      self.updateLineStukken()
+   def getDict(self):
+      d = {}
+      d['fromBlock'] = self.fromPort.block.name
+      d['fromPort'] = self.fromPort.name
+      d['toBlock'] = self.toPort.block.name
+      d['toPort'] = self.toPort.name
+      return d
+   def setDict(self, d):
+      print(d)
+   Dict = property(getDict, setDict)
    def myDelete(self):
       scene = self.scene()
       if scene:
@@ -173,6 +156,9 @@
       lx = 3 if self.direction == 'input' else -3 - lw
       self.textItem.setPos(lx, -lh / 2)
    name = property(getName, setName)
+   def getDict(self):
+      return {'name': self.name}
+   Dict = property(getDict)
    def itemChange(self, change, value):
       if change == self.ItemScenePositionHasChanged:
          for cb in self.posCallbacks:
@@ -187,7 +173,6 @@
    # TODO: create a subclass OR make a member porttype
    pass
 
-# Block part:
 class HandleItem(QGraphicsEllipseItem):
    """ A handle that can be moved by the mouse """
    def __init__(self, parent=None):
@@ -209,19 +194,10 @@
             if res:
                value = res
          return value
-      # Call superclass method:
       return super(HandleItem, self).itemChange(change, value)
 
 class BlockItem(QGraphicsRectItem):
-   """ 
-      Represents a block in the diagram
-      Has an x and y and width and height
-      width and height can only be adjusted with a tip in the lower right corner.
-
-      - in and output ports
-      - parameters
-      - description
-   """
+   """ Represents a block in the diagram """
    def __init__(self, name='Untitled', parent=None):
       super(BlockItem, self).__init__(parent)
       self.subModel = DiagramScene()
@@ -271,6 +247,24 @@
    def setName(self, name): self.label.setPlainText(name)
    def getName(self): return self.label.toPlainText()
    name = property(getName, setName)
+   def getDict(self):
+      d = {'x': self.scenePos().x(), 'y': self.scenePos().y()}
+      rect = self.rect()
+      d.update({'width': rect.width(), 'height': rect.height()})
+      d.update({'name': self.name, 'code': self.code})
+      d['inputs'] = [inp.Dict for inp in self.inputs]
+      d['outputs'] = [outp.Dict for outp in self.outputs]
+      return d
+   def setDict(self, d):
+      self.name = d['name']
+      self.code = d['code']
+      self.setPos(d['x'], d['y'])
+      self.sizer.setPos(d['width'], d['height'])
+      for inp in d['inputs']:
+         self.addInput(PortItem(inp['name'], self, 'input'))
+      for outp in d['outputs']:
+         self.addOutput(PortItem(outp['name'], self, 'output'))
+   Dict = property(getDict, setDict)
    def addInput(self, i):
       self.inputs.append(i)
       self.updateSize()
@@ -315,16 +309,21 @@
 class EditorGraphicsView(QGraphicsView):
    def __init__(self, parent=None):
       QGraphicsView.__init__(self, parent)
-      self.dScene = DiagramScene(self)
       self.setDragMode(QGraphicsView.RubberBandDrag)
-      delShort = QShortcut(QKeySequence.Delete, self)
-      delShort.activated.connect(self.dScene.deleteItems)
-   dScene = property(lambda s: s.scene(), lambda s, v: s.setScene(v))
+      self.delShort = QShortcut(QKeySequence.Delete, self)
+   def setModel(self, m):
+      self.setScene(m)
+      self.delShort.activated.connect(m.deleteItems)
+   model = property(lambda s: s.scene(), setModel)
    def save(self):
-      self.diagramScene.saveDiagram('diagram2.usd')
+      filename = 'diagram4.usd'
+      with open(filename, 'w') as f:
+         d = self.model.Dict
+         print(d)
+         f.write(json.dumps(d))
    def load(self):
       filename = QFileDialog.getOpenFileName(self)
-      self.diagramScene.loadDiagram(filename)
+      self.model = loadModel(filename)
    def goDown(self):
       print('Down!')
       block = self.dScene.selected
@@ -335,7 +334,7 @@
          self.zoomAll()
    def zoomAll(self):
       """ zoom to fit all items """
-      rect = self.dScene.itemsBoundingRect()
+      rect = self.model.itemsBoundingRect()
       self.fitInView(rect, Qt.KeepAspectRatio)
    def wheelEvent(self, event):
       pos = event.pos()
@@ -366,115 +365,45 @@
             mimedata.setData('component/name', txt)
       return mimedata
 
+class ModelHierarchyModel(QStandardItemModel):
+   def __init__(self):
+      super(ModelHierarchyModel, self).__init__()
+      self.items = []
+   def flags(self, idx):
+      if idx.isValid():
+         return Qt.ItemIsSelectable | Qt.ItemIsEnabled
+   def data(self):
+      pass
+   def headerData(self, section, orientation, role):
+      if orientation == Qt.Horizontal and role == Qt.DisplayRole:
+         return "Henkie"
+   def rowCount(self, parent):
+      pass
+   def columnCount(self, parent):
+      return 1
+
 class DiagramScene(QGraphicsScene):
-   """ Save and load and deletion of item"""
-   def __init__(self, parent=None):
-      super(DiagramScene, self).__init__(parent)
+   def __init__(self):
+      super(DiagramScene, self).__init__()
       self.startedConnection = None
    blocks = property(lambda sel: [i for i in sel.items() if type(i) is BlockItem])
    connections = property(lambda sel: [i for i in sel.items() if type(i) is Connection])
-   def saveDiagram(self, filename):
-      blocks = self.blocks
-      connections = self.connections
-      doc = md.Document()
-      modelElement = doc.createElement('system')
-      doc.appendChild(modelElement)
-      for block in blocks:
-         blockElement = doc.createElement("block")
-         x, y = block.scenePos().x(), block.scenePos().y()
-         rect = block.rect()
-         w, h = rect.width(), rect.height()
-         blockElement.setAttribute("name", block.name)
-         blockElement.setAttribute("x", str(int(x)))
-         blockElement.setAttribute("y", str(int(y)))
-         blockElement.setAttribute("width", str(int(w)))
-         blockElement.setAttribute("height", str(int(h)))
-         codeNode = doc.createCDATASection(block.code)
-         codeElement = doc.createElement('code')
-         codeElement.appendChild(codeNode)
-         blockElement.appendChild(codeElement)
-         for inp in block.inputs:
-            portElement = doc.createElement("input")
-            portElement.setAttribute("name", inp.name)
-            blockElement.appendChild(portElement)
-         for outp in block.outputs:
-            portElement = doc.createElement("output")
-            portElement.setAttribute("name", outp.name)
-            blockElement.appendChild(portElement)
-         modelElement.appendChild(blockElement)
-      for connection in connections:
-         connectionElement = doc.createElement("connection")
-         fromPort = connection.fromPort.name
-         toPort = connection.toPort.name
-         fromBlock = connection.fromPort.block.name
-         toBlock = connection.toPort.block.name
-         connectionElement.setAttribute("fromBlock", fromBlock)
-         connectionElement.setAttribute("fromPort", fromPort)
-         connectionElement.setAttribute("toBlock", toBlock)
-         connectionElement.setAttribute("toPort", toPort)
-         for via in connection.vias:
-            viaElement = doc.createElement('via')
-            viaElement.setAttribute('x', str(int(via.x())))
-            viaElement.setAttribute('y', str(int(via.y())))
-            connectionElement.appendChild(viaElement)
-         modelElement.appendChild(connectionElement)
-      with open(filename, 'w') as f:
-         f.write(doc.toprettyxml())
-   def loadDiagram(self, filename):
-      try:
-         doc = md.parse(filename)
-      except IOError as e:
-         print('{0} not found'.format(filename))
-         return
-      except xml.parsers.expat.ExpatError as e:
-         print('{0}'.format(e))
-         return
-      sysElements = doc.getElementsByTagName('system')
-      blockElements = doc.getElementsByTagName('block')
-      for sysElement in sysElements:
-         blockElements = sysElement.getElementsByTagName('block')
-         for blockElement in blockElements:
-            x = float(blockElement.getAttribute('x'))
-            y = float(blockElement.getAttribute('y'))
-            w = float(blockElement.getAttribute('width'))
-            h = float(blockElement.getAttribute('height'))
-            name = blockElement.getAttribute('name')
-            block = BlockItem(name)
-            self.addItem(block)
-            block.setPos(x, y)
-            block.sizer.setPos(w, h)
-            codeElements = blockElement.getElementsByTagName('code')
-            if codeElements:
-               cn = codeElements[0].childNodes
-               cdatas = [cd for cd in cn if type(cd) is md.CDATASection]
-               if len(cdatas) > 0:
-                  block.code = cdatas[0].data
-            # Load ports:
-            portElements = blockElement.getElementsByTagName('input')
-            for portElement in portElements:
-               name = portElement.getAttribute('name')
-               inp = PortItem(name, block, 'input')
-               block.addInput(inp)
-            portElements = blockElement.getElementsByTagName('output')
-            for portElement in portElements:
-               name = portElement.getAttribute('name')
-               outp = PortItem(name, block, 'output')
-               block.addOutput(outp)
-         connectionElements = sysElement.getElementsByTagName('connection')
-         for connectionElement in connectionElements:
-            fromBlock = connectionElement.getAttribute('fromBlock')
-            fromPort = connectionElement.getAttribute('fromPort')
-            toBlock = connectionElement.getAttribute('toBlock')
-            toPort = connectionElement.getAttribute('toPort')
-            viaElements = connectionElement.getElementsByTagName('via')
-            fromPort = self.findPort(fromBlock, fromPort)
-            toPort = self.findPort(toBlock, toPort)
-            connection = Connection(fromPort, toPort)
-            for viaElement in viaElements:
-               x = int(viaElement.getAttribute('x'))
-               y = int(viaElement.getAttribute('y'))
-               connection.addHandle(QPointF(x, y))
-            self.addItem(connection)
+   def setDict(self, d):
+      for block in d['blocks']:
+         b = BlockItem()
+         self.addItem(b)
+         b.Dict = block
+      for con in d['connections']:
+         fromPort = self.findPort(con['fromBlock'], con['fromPort'])
+         toPort = self.findPort(con['toBlock'], con['toPort'])
+         c = Connection(fromPort, toPort)
+         self.addItem(c)
+   def getDict(self):
+      d = {}
+      d['blocks'] = [b.Dict for b in self.blocks]
+      d['connections'] = [c.Dict for c in self.connections]
+      return d
+   Dict = property(getDict, setDict)
    def findPort(self, blockname, portname):
       block = self.findBlock(blockname)
       if block:
@@ -482,8 +411,7 @@
             if port.name == portname:
                return port
    def findBlock(self, blockname):
-      items = self.items()
-      blocks = [item for item in items if type(item) is BlockItem]
+      blocks = [item for item in self.items() if type(item) is BlockItem]
       for block in blocks:
          if block.name == blockname:
             return block
@@ -530,18 +458,28 @@
       painter.setBrush(Qt.yellow)
       painter.drawEllipse(20, 20, 20, 20)
       painter.end()
-
       # Fill library:
-      self.libItems = []
-      self.libItems.append( QStandardItem(QIcon(pixmap), 'Block') )
-      self.libItems.append( QStandardItem(QIcon(pixmap), 'Uber Unit') )
-      self.libItems.append( QStandardItem(QIcon(pixmap), 'Device') )
-      for i in self.libItems:
-         self.libraryModel.appendRow(i)
+      for name in ['Block', 'Uber unit', 'Device']:
+         self.libraryModel.appendRow(QStandardItem(QIcon(pixmap), name))
       self.setModel(self.libraryModel)
       self.setViewMode(self.IconMode)
       self.setDragDropMode(self.DragOnly)
 
+class ModelTree(QTreeView):
+   def __init__(self):
+      super(ModelTree, self).__init__()
+      m = ModelHierarchyModel()
+      self.setModel(m)
+
+def loadModel(filename):
+   with open(filename, 'r') as f:
+      data = f.read()
+   d = json.loads(data)
+   print('Loaded json:', d)
+   s = DiagramScene()
+   s.Dict = d
+   return s
+
 class Main(QMainWindow):
    def __init__(self):
       super(Main, self).__init__(None)
@@ -560,11 +498,12 @@
       act('Fit in view', QKeySequence("F8"), self.editor.zoomAll)
       act('Go down', QKeySequence(Qt.Key_Down), self.editor.goDown)
       act('Go up', QKeySequence(Qt.Key_Up), self.editor.goUp)
-      self.library = LibraryWidget() 
-      libraryDock = QDockWidget('Library', self)
-      libraryDock.setWidget(self.library)
-      self.addDockWidget(Qt.LeftDockWidgetArea, libraryDock)
-      self.editor.scene().loadDiagram('diagram2.usd')
+      def addDock(name, widget):
+         dock = QDockWidget(name, self)
+         dock.setWidget(widget)
+         self.addDockWidget(Qt.LeftDockWidgetArea, dock)
+      addDock('Library', LibraryWidget())
+      addDock('Model tree', ModelTree())
    def toggleFullScreen(self):
       self.setWindowState(self.windowState() ^ Qt.WindowFullScreen)
       self.editor.zoomAll()
@@ -577,6 +516,7 @@
    main = Main()
    main.show()
    main.resize(700, 500)
+   main.editor.model = loadModel('diagram4.usd')
    main.editor.zoomAll()
    app.exec_()