示例#1
0
class QTZOCPnumber(QtGui.QWidget):
    
    def __init__(self):
        super(QTZOCPnumber, self).__init__()

         # Set name of Node
        self.nodename = "QT LCDdisplay@%s" % socket.gethostname()

        self.init_zocp()
        self.initUI()

    def init_zocp(self):
        self.z = ZOCP(self.nodename)
        
        self.notifier = QtCore.QSocketNotifier(
                self.z.inbox.getsockopt(zmq.FD), 
                QtCore.QSocketNotifier.Read
                )
        self.notifier.setEnabled(True)
        self.notifier.activated.connect(self.zocp_event)
        self.z.on_peer_signaled = self.on_peer_signaled
        self.z.on_peer_enter = self.on_peer_enter
        self.z.start()

          
    def initUI(self):
        
        self.lcd1 = QtGui.QLCDNumber(self)
        self.lcd2 = QtGui.QLCDNumber(self)
        self.lcd3 = QtGui.QLCDNumber(self)

        # Register the ZOCP variables
        self.z.register_int("display1", 0, access='rs')
        self.z.register_int("display2", 0, access='rs')
        self.z.register_int("display3", 0, access='rs')

        grid = QtGui.QGridLayout()
        grid.setSpacing(10)

        grid.addWidget(self.lcd1, 1, 1)
        grid.addWidget(self.lcd2, 1, 2)
        grid.addWidget(self.lcd3, 1, 3)
        
        self.setLayout(grid) 
        self.setGeometry(300, 300, 150, 70)
        self.setWindowTitle(self.nodename)
        self.show()

        

    def zocp_event(self):
        self.z.run_once(0)

    def on_peer_signaled(self, peer, name, data, *args, **kwargs):
        """
        Called when a peer signals that some of its data is modified.

        peer: id of peer whose data has been changed
        name: name of peer whose data has been changed
        data: changed data, formatted as [emitter, value]
              emitter: name of the emitter on the subscribee
              value: value of the emitter
        """
        zl.debug(" --> ZOCP PEER SIGNALED: %s modified %s" %(name, data))

        # Check if there is data
        if(len(data) > 1):

            if(data[0] == "slider1"):
                self.lcd1.display(data[1])
            elif(data[0] == "slider2"):
                self.lcd2.display(data[1])
            elif(data[0] == "slider3"):
                self.lcd3.display(data[1])


    def on_peer_enter(self, peer, name, *args, **kwargs):
        
        zl.debug(" -----> PEER ENTERED ",name," peer: ",peer)
        # This assumes that for testing the source to connect to is running on the same computer as the 
        # the destination trying to connect to it is.
        sourceTargetName = "QT Sliders@%s" % socket.gethostname()
        if(name == sourceTargetName):
            self.z.signal_subscribe(self.z.uuid(), 'display1', peer, 'slider1')
            self.z.signal_subscribe(self.z.uuid(), 'display2', peer, 'slider2')
            self.z.signal_subscribe(self.z.uuid(), 'display3', peer, 'slider3')
            zl.debug("Nodes are subscribed")


    def closeEvent(self, *args):
        zl.debug(args)
        self.z.stop()
示例#2
0
文件: zne.py 项目: z25/pyZNodeEditor
class QNEMainWindow(QMainWindow):
    def __init__(self, parent):
        super(QNEMainWindow, self).__init__(parent)

        self.logger = logging.getLogger("zne")
        self.logger.setLevel(logging.DEBUG)

        self.setMinimumSize(560,360)
        self.setWindowTitle("ZOCP Node Editor")
        self.setWindowIcon(QIcon('assets/icon.png'))

        self.scene = QGraphicsScene(self)
        self.view = QGraphicsView(self)
        self.view.setScene(self.scene)
        self.setCentralWidget(self.view)

        self.nodesEditor = QNodesEditor(self, self.scene, self.view)

        self.nodesEditor.onAddConnection = self.onAddConnection
        self.nodesEditor.onRemoveConnection = self.onRemoveConnection
        self.nodesEditor.onBlockMoved = self.onBlockMoved

        self.scale = 1
        self.installActions()

        self.initZOCP()

        self.nodes = {}
        self.pendingSubscribers = {}

        QTimer.singleShot(250, lambda: self.scene.invalidate())


    def closeEvent(self, *args):
        self.zocp.stop()


    def installActions(self):
        quitAct = QAction("&Quit", self, shortcut="Ctrl+Q",
            statusTip="Exit the application", triggered=self.close)
        if zconfigmanager_found:
            openAct = QAction("&Open...", self, shortcut="Ctrl+O",
                statusTip="Restore the network from a saved description", triggered=self.readNetwork)
            saveAct = QAction("&Save...", self, shortcut="Ctrl+S",
                statusTip="Write a description of the network to disc", triggered=self.writeNetwork)

        fileMenu = self.menuBar().addMenu("&File")
        if zconfigmanager_found:
            fileMenu.addAction(openAct)
            fileMenu.addAction(saveAct)
            fileMenu.addSeparator()
        fileMenu.addAction(quitAct)

        # for shortcuts
        self.view.addAction(quitAct)

        selectAllAct = QAction("Select &All", self, shortcut="Ctrl+A",
            triggered=self.nodesEditor.selectAll)
        selectNoneAct = QAction("Select &None", self, shortcut="Ctrl+D",
            triggered=self.nodesEditor.selectNone)
        selectInverseAct = QAction("Select &Inverse", self, shortcut="Ctrl+I",
            triggered=self.nodesEditor.selectInverse)
        deleteSelectedAct = QAction("&Delete Selected", self, shortcut="Del",
            triggered=self.nodesEditor.deleteSelected)

        editMenu = self.menuBar().addMenu("&Edit")
        editMenu.addAction(selectAllAct)
        editMenu.addAction(selectNoneAct)
        editMenu.addAction(selectInverseAct)
        editMenu.addSeparator()
        editMenu.addAction(deleteSelectedAct)

        self.view.addAction(selectAllAct)
        self.view.addAction(selectNoneAct)
        self.view.addAction(selectInverseAct)
        self.view.addAction(deleteSelectedAct)

        zoomInAct = QAction("Zoom &In", self, shortcut="Ctrl++",
            triggered=self.zoomIn)
        zoomOutAct = QAction("Zoom &Out", self, shortcut="Ctrl+-",
            triggered=self.zoomOut)
        zoomResetAct = QAction("&Reset Zoom", self, shortcut="Ctrl+0",
            triggered=self.zoomReset)

        viewMenu = self.menuBar().addMenu("&View")
        viewMenu.addAction(zoomInAct)
        viewMenu.addAction(zoomOutAct)
        viewMenu.addSeparator()
        viewMenu.addAction(zoomResetAct)

        self.view.addAction(zoomInAct)
        self.view.addAction(zoomOutAct)
        self.view.addAction(zoomResetAct)

        aboutAct = QAction("&About", self,
             triggered=self.about)

        helpMenu = self.menuBar().addMenu("&Help")
        helpMenu.addAction(aboutAct)

        self.view.addAction(aboutAct)


    def writeNetwork(self):
        fileName, filter = QFileDialog.getSaveFileName(self,
                                                       caption="Save as",
                                                       filter="ZOCP (*.zocp);;JSON (*.json)",
                                                       selectedFilter="ZOCP (*.zocp)")
        if fileName:
            # setup ZOCP node, and run it for some time to discover
            # the current network
            configManager = ZConfigManagerNode("ConfigManager@%s" % socket.gethostname())
            configManager.discover(0.5)

            # write network description to file
            configManager.write(fileName)

            # shut down ZOCP node
            configManager.stop()
            configManager = None


    def readNetwork(self):
        fileName, filter = QFileDialog.getOpenFileName(self,
                                                       caption="Open",
                                                       filter="All files (*.*);;ZOCP (*.zocp);;JSON (*.json)",
                                                       selectedFilter="ZOCP (*.zocp)")
        if fileName:
            # setup ZOCP node, and run it for some time to discover
            # the current network
            configManager = ZConfigManagerNode("ConfigManager@%s" % socket.gethostname())
            configManager.discover(0.5)

            # write network description to file
            configManager.read(fileName)

            # shut down ZOCP node
            configManager.stop()
            configManager = None


    def zoomIn(self):
        if self.scale < 4:
            self.scale *= 1.2
            self.view.scale(1.2, 1.2)


    def zoomOut(self):
        if self.scale > 0.1:
            self.scale /= 1.2
            self.view.scale(1/1.2, 1/1.2)


    def zoomReset(self):
        self.scale = 1
        self.view.setTransform(QTransform())


    def about(self):
        QMessageBox.about(self, "About ZOCP Node Editor",
            "<p>A monitor/editor for ZOCP nodes, implemented in PySide"
             "(Python/Qt4).</p><p>ZOCP is the Z25 Orchestration Control "
             "Protocol, currently in development at "
             "<a href='http://z25.org'>z25.org</a></p>")


    #########################################
    # Node editor callbacks
    #########################################
    def onAddConnection(self, connection, fromPort, toPort):
        fromBlock = fromPort.block()
        toBlock = toPort.block()

        emitter = fromPort.portName()
        emit_peer = fromBlock.uuid()
        receiver = toPort.portName()
        recv_peer = toBlock.uuid()

        self.zocp.signal_subscribe(recv_peer, receiver, emit_peer, emitter)

        self.logger.debug("added subscription from %s on %s to %s on %s" %
               (receiver, fromBlock.name(), emitter, toBlock.name()))


    def onRemoveConnection(self, connection, fromPort, toPort):
        fromBlock = fromPort.block()
        toBlock = toPort.block()

        emitter = fromPort.portName()
        emit_peer = fromBlock.uuid()
        receiver = toPort.portName()
        recv_peer = toBlock.uuid()

        self.zocp.signal_unsubscribe(recv_peer, receiver, emit_peer, emitter)

        self.logger.debug("removed subscription from %s on %s to %s on %s" %
               (receiver, fromBlock.name(), emitter, toBlock.name()))


    def onBlockMoved(self, block):
        pos = block.pos()
        peer = block.uuid()
        self.zocp.peer_set(peer, {"_zne_position": [pos.x(), pos.y()]})


    def onChangeValue(self, block, port, value):
        self.logger.debug("block %s port %s changed to %s" % (block.name(), port.portName(), value))
        peer = block.uuid()
        portName = port.portName()
        capability = self.zocp.peers_capabilities[peer][portName]
        typeHint = capability["typeHint"]
        validValue = True
        if typeHint == "int":
            try:
                value = int(float(value))
            except:
                validValue = False
        elif typeHint == "flt":
            try:
                value = float(value.strip())
            except:
                validValue = False
        elif typeHint == "percent":
            try:
                value = float(value.strip())
            except:
                validValue = False
        elif typeHint == "bool":
            value = (value.strip().lower() in ["true", "yes", "1"])
        elif typeHint == "string":
            pass
        elif typeHint.startswith("vec" ) and typeHint.endswith("f") and len(typeHint) == 5:
            try:
                value = [float(num) for num in ((value.strip())[1:-1]).split(",")]
            except:
                validValue = False

            if validValue:
                if len(value) != int(typeHint[3]):
                    validValue = False

        if validValue:
            self.zocp.peer_set(peer, {portName: {"value": value}})
            port.setValue(str(value))
        else:
            port.setValue(str(capability["value"]))



    #########################################
    # ZOCP implementation
    #########################################
    def initZOCP(self):
        self.zocp = ZOCP("ZOCP Node Editor@%s" % socket.gethostname())
        self.notifier = QSocketNotifier(
            self.zocp.inbox.getsockopt(zmq.FD),
            QSocketNotifier.Read)
        self.notifier.setEnabled(True)
        self.notifier.activated.connect(self.onZOCPEvent)
        self.zocp.on_peer_enter = self.onPeerEnter
        self.zocp.on_peer_exit = self.onPeerExit
        self.zocp.on_peer_modified = self.onPeerModified
        self.zocp.on_peer_signaled = self.onPeerSignaled
        self.zocp.start()

        zl = logging.getLogger("zocp")
        zl.setLevel(logging.INFO)


    def onZOCPEvent(self):
        self.zocp.run_once(0)


    def onPeerEnter(self, peer, name, *args, **kwargs):
        # Subscribe to any and all value changes
        self.zocp.signal_subscribe(self.zocp.uuid(), None, peer, None)

        # Add named block; ports are not known at this point
        block = QNEBlock(None)
        self.scene.addItem(block)
        block.setNodeEditor(self)
        block.setName(name)
        block.setUuid(peer)
        block.addPort(name, False, False, QNEPort.NamePort)
        block.setVisible(False)

        node = {}
        node["block"] = block
        node["ports"] = dict()

        self.nodes[peer.hex] = node


    def onPeerExit(self, peer, name, *args, **kwargs):
        # Unsubscribe from value changes
        self.zocp.signal_unsubscribe(self.zocp.uuid(), None, peer, None)

        # Remove block
        if peer.hex in self.nodes:
            self.nodes[peer.hex]["block"].delete()
            self.nodes.pop(peer.hex)


    def onPeerModified(self, peer, name, data, *args, **kwargs):
        for portname in data:
            portdata = data[portname]

            if portname not in self.nodes[peer.hex]["ports"]:
                if "access" in portdata:
                    hasInput = "s" in portdata["access"]
                    hasOutput = "e" in portdata["access"]
                    port = self.nodes[peer.hex]["block"].addPort(portname, hasInput, hasOutput)
                    port.setValue(str(portdata["value"]))
                    port.setAccess(str(portdata["access"]))
                    self.nodes[peer.hex]["ports"][portname] = port

                else:
                    # Metadata, not a capability
                    if portname == "_zne_position":
                        block = self.nodes[peer.hex]["block"]
                        block.setPos(portdata[0], portdata[1])

            else:
                port = self.nodes[peer.hex]["ports"][portname]
                if "value" in portdata:
                    port.setValue(str(portdata["value"]))
                if "access" in portdata:
                    port.setAccess(str(portdata["access"]))

            if "subscribers" in portdata:
                self.updateSubscribers(port, portdata["subscribers"])

        if len(self.nodes[peer.hex]["ports"]) > 0:
            self.nodes[peer.hex]["block"].setVisible(True)
        self.updatePendingSubscribers(peer)


    def onPeerSignaled(self, peer, name, data, *args, **kwargs):
        [portname, value] = data
        if portname in self.nodes[peer.hex]["ports"]:
            self.nodes[peer.hex]["ports"][portname].setValue(str(value))


    def updateSubscribers(self, port, subscribers):
        port1 = port.outputPort

        # check if any current connections should be removed
        connections = port.connections()
        for connection in connections:
            if(connection.port1() == port1):
                port2 = connection.port2()
            else:
                port2 = connection.port1()

            if not port2.isOutput():
                subscriber = [port2.block().uuid().hex, port2.portName()]
                if subscriber not in subscribers:
                    connection.delete()
                    self.logger.debug("peer removed subscription from %s on %s to %s on %s" %
                        (port1.portName(), port1.block().name(), port2.portName(), port2.block().name()))

        # add new connections for new subscriptions
        for subscriber in subscribers:
            [uuid, portname] = subscriber
            if uuid in self.nodes:
                node = self.nodes[uuid]
                if portname in node["ports"]:
                    port2 = node["ports"][portname]
                    if not port2.isConnected(port1):
                        # create new connection
                        connection = QNEConnection(None)
                        connection.setPort1(port1)
                        connection.setPort2(port2)
                        connection.updatePosFromPorts()
                        connection.updatePath()
                        self.scene.addItem(connection)
                        self.logger.debug("peer added subscription from %s on %s to %s on %s" %
                            (port1.portName(), port1.block().name(), port2.portName(), port2.block().name()))
                    continue

            # if the connection could not be made yet, add it to a list of
            # pending subscriber-connections
            if uuid not in self.pendingSubscribers:
                self.pendingSubscribers[uuid] = []
            self.pendingSubscribers[uuid].append([port1, portname])


    def updatePendingSubscribers(self, peer):
        if peer.hex in self.pendingSubscribers:
            for subscriber in self.pendingSubscribers[peer.hex]:
                [port1, portname] = subscriber
                if peer.hex in self.nodes and portname in self.nodes[peer.hex]["ports"]:
                    port2 = self.nodes[peer.hex]["ports"][portname]

                    connection = QNEConnection(None)
                    connection.setPort1(port1)
                    connection.setPort2(port2)
                    connection.updatePosFromPorts()
                    connection.updatePath()
                    self.scene.addItem(connection)
                else:
                    # TODO: handle case where port is still not available
                    pass

            self.pendingSubscribers.pop(peer.hex)