Mercurial > lcfOS
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_()