Example #1
0
    def __init__(self):
        self.modified = False
        self.name = ''
        self.path = ''
        self.lib_paths = []
        self.tree_paths = []
        self.alphabet = None
        self.shapelib = None
        self.libraries = {}
        self.trees = BehaviorTree()
        self.nodes = TreeNodes()
        self.top_level_trees = []
        self.__lib_parser = liparser.LibParser()
        self.__tree_parser = treeparser.TreeParser()
        self.__history = History(self)

        globals.librarySignals.excludeLibrary.connect(self.excludeLibrary)

        globals.librarySignals.removeNode.connect(self.__onRemoveNode)
        globals.librarySignals.renameNode.connect(self.__onRenameNode)
        globals.librarySignals.changeCreator.connect(self.__onChangeCreatorNode)

        globals.librarySignals.renameAttribute.connect(self.__onRenameAttrNode)
        globals.librarySignals.changeAttribute.connect(self.__onChangeAttributeNode)
        globals.librarySignals.addAttribute.connect(self.__onAddAttributeNode)
        globals.librarySignals.deleteAttribute.connect(self.__onDeleteAttributeNode)

        globals.librarySignals.addNewNode.connect(self.__onAddNewNodeToLibrary)
        globals.librarySignals.addNode.connect(self.__onAddNodeToLibrary)
        globals.librarySignals.changeNodeType.connect(self.__onChangeTypeNode)
        globals.librarySignals.changeNodeChildren.connect(self.__onChangeChildrenNode)
        globals.librarySignals.changeNodeDescription.connect(self.__onChangeDescriptionNode)
        globals.librarySignals.changeNodeShape.connect(self.__onShapeChangeNode)

        globals.librarySignals.renameLibrary.connect(self.__onRenameLibraryQuery)

        globals.librarySignals.renameIncomingEvent.connect(self.__onIncomingEventRenameNode)
        globals.librarySignals.renameOutgoingEvent.connect(self.__onOutgoingEventRenameNode)
        globals.librarySignals.addIncomingEvent.connect(self.__onIncomingEventAddNode)
        globals.librarySignals.addOutgoingEvent.connect(self.__onOutgoingEventAddNode)
        globals.librarySignals.deleteIncomingEvent.connect(self.__onIncomingEventDeleteNode)
        globals.librarySignals.deleteOutgoingEvent.connect(self.__onOutgoingEventDeleteNode)
Example #2
0
class Project(object):
    def __init__(self):
        self.modified = False
        self.name = ''
        self.path = ''
        self.lib_paths = []
        self.tree_paths = []
        self.alphabet = None
        self.shapelib = None
        self.libraries = {}
        self.trees = BehaviorTree()
        self.nodes = TreeNodes()
        self.top_level_trees = []
        self.__lib_parser = liparser.LibParser()
        self.__tree_parser = treeparser.TreeParser()
        self.__history = History(self)

        globals.librarySignals.excludeLibrary.connect(self.excludeLibrary)

        globals.librarySignals.removeNode.connect(self.__onRemoveNode)
        globals.librarySignals.renameNode.connect(self.__onRenameNode)
        globals.librarySignals.changeCreator.connect(self.__onChangeCreatorNode)

        globals.librarySignals.renameAttribute.connect(self.__onRenameAttrNode)
        globals.librarySignals.changeAttribute.connect(self.__onChangeAttributeNode)
        globals.librarySignals.addAttribute.connect(self.__onAddAttributeNode)
        globals.librarySignals.deleteAttribute.connect(self.__onDeleteAttributeNode)

        globals.librarySignals.addNewNode.connect(self.__onAddNewNodeToLibrary)
        globals.librarySignals.addNode.connect(self.__onAddNodeToLibrary)
        globals.librarySignals.changeNodeType.connect(self.__onChangeTypeNode)
        globals.librarySignals.changeNodeChildren.connect(self.__onChangeChildrenNode)
        globals.librarySignals.changeNodeDescription.connect(self.__onChangeDescriptionNode)
        globals.librarySignals.changeNodeShape.connect(self.__onShapeChangeNode)

        globals.librarySignals.renameLibrary.connect(self.__onRenameLibraryQuery)

        globals.librarySignals.renameIncomingEvent.connect(self.__onIncomingEventRenameNode)
        globals.librarySignals.renameOutgoingEvent.connect(self.__onOutgoingEventRenameNode)
        globals.librarySignals.addIncomingEvent.connect(self.__onIncomingEventAddNode)
        globals.librarySignals.addOutgoingEvent.connect(self.__onOutgoingEventAddNode)
        globals.librarySignals.deleteIncomingEvent.connect(self.__onIncomingEventDeleteNode)
        globals.librarySignals.deleteOutgoingEvent.connect(self.__onOutgoingEventDeleteNode)

    def activate(self):
        self.__history.activate()

    def deactivate(self):
        self.__history.deactivate()

    def getHistoryUndoActions(self):
        return self.__history.getUndoActions()

    def getHistoryRedoActions(self):
        return self.__history.getRedoActions()

    def gotLibrary(self, libname):
        return libname in self.libraries

    def getLibrary(self, libname):
        if libname in self.libraries:
            return self.libraries[libname]
        return None

    def addLibrary(self, filename):
        loaded_libs = self.__lib_parser.load(self.alphabet, [filename], self.libraries, self.shapelib)
        if loaded_libs:
            path = relativePath(filename, self.path)
            if path is not None:
                globals.historySignals.pushState.emit('Add new libraries from \'{0}\''.format(path))
                self.lib_paths.append(path)

                for libname in loaded_libs:
                    self.libraries[libname] = loaded_libs[libname]

                for uid in self.nodes:
                    node = self.nodes[uid]
                    if not node.isEmpty():
                        node.reparseAttributes()

                for libname in loaded_libs:
                    globals.librarySignals.libraryAdded.emit(libname)

                self.modified = True
                return True

        return False

    def excludeLibrary(self, libname):
        if libname in self.libraries:
            usedBy = self.trees.getBranchesByLibrary(libname, self.nodes)
            if usedBy:
                message = '<font color=\"red\">'
                message += trStr('Library <b>\'{0}\'</b> is used by branches:'.format(libname),
                                 'Библиотека <b>\'{0}\'</b> используется в деревьях:'.format(libname)).text()
                message += '</font>'
                for branchName in usedBy:
                    message += '<br/>- <b>{0}</b>'.format(usedBy[branchName].refname())
                message += '<br/>'
            else:
                message = ''
            message += trStr(
                '<font color=\"red\">Do You really want to exclude library <b>\'{0}\'</b> \
                    from the project?</font>'.format(libname),
                '<font color=\"red\">Вы действительно хотите исключить библиотеку <b>\'{0}\'</b> \
                    из проекта?</font>'.format(libname)).text()
            title = trStr('Excluding library', 'Исключение библиотеки').text()
            if QMessageBox.warning(None, title, message,
                                   QMessageBox.Yes | QMessageBox.No, QMessageBox.No) == QMessageBox.Yes:
                globals.historySignals.pushState.emit('Exclude library \'{0}\' from project'.format(libname))
                self.modified = True
                del self.libraries[libname]
                globals.librarySignals.libraryExcluded.emit(libname)

    def gotTree(self, fullname):
        return fullname in self.trees

    def getTree(self, fullname):
        return self.trees.get(fullname)

    def addTree(self, filename):
        trees, nodes, treesFiles = self.__tree_parser.load([filename], self)
        if treesFiles and treesFiles[0] not in self.tree_paths:
            path = treesFiles[0]
            globals.historySignals.pushState.emit('Include new trees from \'{0}\' into project'.format(path))
            self.tree_paths.append(path)
            for t in trees:
                uid = trees[t]
                bt = nodes[uid]
                if self.trees.add(bt, silent=True):
                    self.nodes.add(bt, recursive=True)
            self.modified = True
            return True
        return False

    def __onRenameNode(self, libname, oldname, newname):
        if libname in self.libraries:
            library = self.libraries[libname]
            print('INFO: Trying to rename node \'{0}\' of library \'{1}\' into \'{2}\'...'
                  .format(oldname, libname, newname))
            if newname in library:
                print('ERROR: Node \'{0}\' already exist in library \'{1}\'!'.format(newname, libname))
                return False
            if oldname not in library:
                print('WARNING: There are no node \'{0}\' in library \'{1}\'.'.format(oldname, libname))
                return False

            globals.historySignals.pushState.emit(
                'Rename \'{0}\' node to \'{1}\' in library \'{2}\''.format(oldname, newname, libname))

            node = library.list[oldname]
            del library.list[oldname]
            node.name = newname
            library.list[newname] = node
            print('OK: Node \'{0}\' of library \'{1}\' has been renamed to \'{2}\'.'.format(oldname, libname, newname))
            self.modified = True

            for uid in self.nodes:
                treeNode = self.nodes[uid]
                treeNode.rename(libname, oldname, newname, recursive=False)

            globals.librarySignals.nodeRenamed.emit(libname, oldname, newname)

    def __onRemoveNode(self, libname, nodename):
        if libname in self.libraries and nodename in self.libraries[libname]:
            usedBy = globals.project.trees.getBranchesByNode(libname, nodename, self.nodes)
            if usedBy:
                message = '<font color=\"red\">'
                message += trStr('Node <b>\'{0}\'</b> is used by branches:'.format(nodename),
                                 'Узел <b>\'{0}\'</b> используется в деревьях:'.format(nodename)).text()
                message += '</font>'
                for branchName in usedBy:
                    message += '<br/>- <b>{0}</b>'.format(usedBy[branchName].refname())
                message += '<br/>'
            else:
                message = ''
            message += trStr('<font color=\"red\">Do You really want to delete \
                             node <b>\'{0}\'</b>?</font>'.format(nodename),

                             '<font color=\"red\">Вы действительно хотите удалить \
                             узел <b>\'{0}\'</b>?</font>'.format(nodename))\
                .text()
            title = trStr('Delete node', 'Удаление узла').text()
            if QMessageBox.warning(None, title, message,
                                   QMessageBox.Yes | QMessageBox.No, QMessageBox.No) == QMessageBox.Yes:
                globals.historySignals.pushState.emit(
                    'Delete \'{0}\' node from library \'{1}\''.format(nodename, libname))
                library = self.libraries[libname]
                print('warning: {0} {1} node \'{2}\' have been removed from \'{3}\' library!'
                      .format(library.list[nodename].nodeType, library.list[nodename].nodeClass, nodename, libname))
                nodeClass = library.list[nodename].nodeClass
                del library.list[nodename]
                self.modified = True
                globals.librarySignals.nodeRemoved.emit(libname, nodename, nodeClass)

    def __onChangeCreatorNode(self, libname, nodename, creator):
        if libname in self.libraries and nodename in self.libraries[libname]:
            if creator:
                print('OK: Creator for node \'{0}\' of library \'{1}\' is set to \'{2}\'.'
                      .format(nodename, libname, creator))
            else:
                print('OK: Creator for node \'{0}\' of library \'{1}\' was removed.'.format(nodename, libname))
            globals.historySignals.pushState.emit(
                'Change creator for node \'{0}\' in library \'{1}\''.format(nodename, libname))
            library = self.libraries[libname]
            creatorOld = library.list[nodename].creator
            library.list[nodename].setCreator(creator)
            self.modified = True
            globals.librarySignals.creatorChanged.emit(libname, nodename, creatorOld, creator)

    def __onRenameAttrNode(self, libname, nodename, oldname, newname, full):
        if libname in self.libraries and nodename in self.libraries[libname]:
            globals.historySignals.pushState.emit(
                'Rename attribute for node \'{0}\' in library \'{1}\''.format(nodename, libname))
            success, attrname = self.libraries[libname].list[nodename].renameAttribute(oldname, newname, full)
            if success:
                self.modified = True

                for uid in self.nodes:
                    treeNode = self.nodes[uid]
                    treeNode.renameAttribute(libname, nodename, oldname, attrname, recursive=False)

                globals.librarySignals.attribueRenamed.emit(libname, nodename, oldname, attrname)
            else:
                globals.historySignals.popState.emit()

    def __onChangeAttributeNode(self, libname, nodename, attributeName, attributeDesc):
        if libname in self.libraries and nodename in self.libraries[libname]:
            node = self.libraries[libname].list[nodename]
            old_attr = node[attributeName]
            globals.historySignals.pushState.emit(
                'Modify attribute for node \'{0}\' in library \'{1}\''.format(nodename, libname))
            if old_attr is not None and node.replaceAttribute(attributeName, attributeDesc):
                self.modified = True

                for uid in self.nodes:
                    treeNode = self.nodes[uid]
                    treeNode.validateAttribute(libname, nodename, attributeName, old_attr, recursive=False)

                globals.librarySignals.attribueChanged.emit(libname, nodename, attributeName, old_attr)
            else:
                globals.historySignals.popState.emit()

    def __onAddAttributeNode(self, libname, nodename, attributeName, attributeDesc):
        if libname in self.libraries and nodename in self.libraries[libname]:
            node = self.libraries[libname].list[nodename]
            globals.historySignals.pushState.emit(
                'Add new attribute for node \'{0}\' in library \'{1}\''.format(nodename, libname))
            if node.addAttribute(attributeDesc):
                self.modified = True

                for uid in self.nodes:
                    treeNode = self.nodes[uid]
                    treeNode.addAttribute(libname, nodename, attributeName, recursive=False)

                globals.librarySignals.attribueAdded.emit(libname, nodename, attributeName)
            else:
                globals.historySignals.popState.emit()

    def __onDeleteAttributeNode(self, libname, nodename, attributeName):
        if libname in self.libraries and nodename in self.libraries[libname]:
            node = self.libraries[libname].list[nodename]
            globals.historySignals.pushState.emit(
                'Delete attribute for node \'{0}\' in library \'{1}\''.format(nodename, libname))
            if node.deleteAttribute(attributeName):
                self.modified = True

                for uid in self.nodes:
                    treeNode = self.nodes[uid]
                    treeNode.deleteAttribute(libname, nodename, attributeName, recursive=False)

                globals.librarySignals.attribueDeleted.emit(libname, nodename, attributeName)
            else:
                globals.historySignals.popState.emit()

    def __onAddNewNodeToLibrary(self, libname, nodeClass, nodeType):
        if libname in self.libraries:
            print('debug: adding new {0} {1} node into {2} library ...'.format(nodeType, nodeClass, libname))
            node_class = globals.project.alphabet[nodeClass]
            if node_class is None:
                print('error: Can\'t create new node for unknown class \'{0}\'!'.format(nodeClass))
                return
            node_type = node_class[nodeType]
            if node_type is None:
                print('error: Can\'t create new node for unknown type \'{0}\' of class \'{1}\'!'
                      .format(nodeType, nodeClass))
                return
            if node_type.isLink():
                print('error: Can\'t create new node for type \'{0}\' of class \'{1}\'! Type \'{0}\' is link!'
                      .format(nodeType, nodeClass))
                return
            nodename = 'NewNode_{0}'.format(datetime.datetime.now().time())
            library = self.libraries[libname]
            while nodename in library:
                sleep(0.01)
                nodename = 'NewNode_{0}'.format(datetime.datetime.now().time())
            newNode = TreeNodeDesc(nodename, nodeClass, nodeType, libname, False)
            newNode.description = 'New node created by user.'
            newNode.shape = globals.project.shapelib.defaultShape()
            color = node_class.defaultState().colorEnabled
            newNode.icon = newNode.shape.icon(color)
            for c in node_type.children:
                child = node_type.children[c]
                if child.obligatory():
                    newNode.childClasses.append(c)

            globals.historySignals.pushState.emit(
                'Add new node \'{0}\' into library \'{1}\''.format(nodename, libname))

            library.list[nodename] = newNode
            print('ok: added new {0} {1} node \'{2}\' into {3} library'.format(nodeType, nodeClass, nodename, libname))
            self.modified = True

            globals.librarySignals.nodeAdded.emit(libname, nodename)

    def __onAddNodeToLibrary(self, libname, node):
        if libname in self.libraries:
            print('debug: adding {0} {1} \'{2}\' node into library \'{3}\' ...'
                  .format(node.nodeType, node.nodeClass, node.name, libname))
            if not node.name:
                print('error: Can\'t add node without name!')
                return
            node_class = globals.project.alphabet[node.nodeClass]
            if node_class is None:
                print('error: Can\'t add node of unknown class \'{0}\'!'.format(node.nodeClass))
                return
            node_type = node_class[node.nodeType]
            if node_type is None:
                print('error: Can\'t add node of unknown type \'{0}\' of class \'{1}\'!'
                      .format(node.nodeType, node.nodeClass))
                return
            if node_type.isLink():
                print('error: Can\'t add node for type \'{0}\' of class \'{1}\'! Type \'{0}\' is link!'
                      .format(node.nodeType, node.nodeClass))
                return

            library = self.libraries[libname]
            if node.name in library:
                nodename = '{0}_{1}'.format(node.name, datetime.datetime.now().time())
                while nodename in library:
                    sleep(0.01)
                    nodename = '{0}_{1}'.format(node.name, datetime.datetime.now().time())
            else:
                nodename = node.name

            node.setName(nodename)
            node.setLibrary(libname)

            globals.historySignals.pushState.emit('Add node \'{0}\' into library \'{1}\''.format(nodename, libname))

            library.list[nodename] = node
            print('ok: added {0} {1} node \'{2}\' into {3} library'
                  .format(node.nodeType, node.nodeClass, nodename, libname))
            self.modified = True

            globals.librarySignals.nodeAdded.emit(libname, nodename)

    def __onRenameLibraryQuery(self, oldName, newName):
        if oldName in self.libraries:
            print('info: Renaming library \'{0}\' to \'{1}\' ...'.format(oldName, newName))

            if newName in self.libraries:
                print('warning: Library with name \'{0}\' already exist! Library \'{1}\' will not be renamed.'
                      .format(newName, oldName))
                print('')
                return

            lib = self.libraries[oldName]
            lib.libname = newName

            for nodeName in lib.list:
                lib.list[nodeName].setLibrary(newName)

            for node in self.nodes:
                if node.libname == oldName:
                    node.setLibName(newName)

            self.libraries[newName] = lib
            del self.libraries[oldName]

            print('ok: Library \'{0}\' renamed to \'{1}\''.format(oldName, newName))
            print('')

            globals.librarySignals.libraryRenamed.emit(oldName, newName)

    def __onChangeTypeNode(self, libname, nodename, typeName):
        if libname in self.libraries and nodename in self.libraries[libname] \
                and self.libraries[libname].list[nodename].nodeType != typeName:
            library = self.libraries[libname]
            node = library.list[nodename]
            print('debug: changing type for {0} {1} node \'{2}\' of library \'{3}\'...'
                  .format(node.nodeType, node.nodeClass, nodename, libname))
            node_class = globals.project.alphabet[node.nodeClass]
            if node_class is None:
                print('error: CRITICAL ERROR: Can\'t find class \'{0}\''.format(node.nodeClass))
                return
            node_type = node_class[typeName]
            if node_type is None:
                print('error: Can\'t change type for node \'{0}\' from \'{1}\' to \'{2}\' \
                        because it is not sub type for \'{3}\' class'
                      .format(nodename, node.nodeType, typeName, node.nodeClass))
                return
            if node_type.isLink():
                print('error: Can\'t change type for node \'{0}\' from \'{1}\' to \'{2}\' because it is link-type.'
                      .format(nodename, node.nodeType, typeName))
                return

            globals.historySignals.pushState.emit(
                'Change type for node \'{0}\' in library \'{1}\''.format(nodename, libname))

            typeOld, node.nodeType = node.nodeType, typeName
            remove_list = []
            for c in node.childClasses:
                if c not in node_type:
                    remove_list.append(c)
            for r in remove_list:
                node.childClasses.remove(r)
            for c in node_type.children:
                if c not in node.childClasses:
                    child = node_type.children[c]
                    if child.obligatory():
                        node.childClasses.append(c)
            print('ok: type of {0}::{1} node was changed from \'{2}\' to \'{3}\''
                  .format(libname, nodename, typeOld, typeName))

            self.modified = True

            for uid in self.nodes:
                treeNode = self.nodes[uid]
                treeNode.changeType(libname, nodename, typeName, recursive=False)

            globals.librarySignals.nodeTypeChanged.emit(libname, nodename, typeOld, typeName)

    def __onChangeChildrenNode(self, libname, nodename, childrenList):
        if libname in self.libraries and nodename in self.libraries[libname]:
            node = self.libraries[libname].list[nodename]
            node_class = globals.project.alphabet[node.nodeClass]
            node_type = node_class[node.nodeType]
            accepted_children = []
            for cls_name in childrenList:
                if cls_name in node_type.children:
                    child = node_type.children[cls_name]
                    if child.used():
                        accepted_children.append(cls_name)
            for cls_name in node_type.children:
                child = node_type.children[cls_name]
                if child.used() and child.obligatory() and cls_name not in accepted_children:
                    # we have to use an obligatory classes
                    accepted_children.append(cls_name)

            globals.historySignals.pushState.emit(
                'Change possible child types for node \'{0}\' in library \'{1}\''.format(nodename, libname))

            node.childClasses = accepted_children
            self.modified = True

            globals.librarySignals.nodeChildrenChanged.emit(libname, nodename)

    def __onChangeDescriptionNode(self, libname, nodename, description):
        if libname in self.libraries and nodename in self.libraries[libname]:
            globals.historySignals.pushState.emit(
                'Change description for node \'{0}\' in library \'{1}\''.format(nodename, libname))
            self.libraries[libname].list[nodename].description = description
            self.modified = True
            globals.librarySignals.nodeDescriptionChanged.emit(libname, nodename, description)

    def __onShapeChangeNode(self, libname, nodename, shapename):
        if libname in self.libraries and nodename in self.libraries[libname]:
            if self.shapelib is not None and shapename in self.shapelib:
                globals.historySignals.pushState.emit(
                    'Change shape for node \'{0}\' in library \'{1}\''.format(nodename, libname))
                node = self.libraries[libname].list[nodename]
                node.shape = self.shapelib[shapename]
                color = globals.project.alphabet[node.nodeClass].defaultState().colorEnabled
                node.icon = node.shape.icon(color)
                self.modified = True
                globals.librarySignals.nodeShapeChanged.emit(libname, nodename, shapename)

    def __onIncomingEventRenameNode(self, libname, nodename, oldname, newname):
        if libname in self.libraries and nodename in self.libraries[libname]:
            node = self.libraries[libname].list[nodename]
            if oldname in node.incomingEvents:
                index = node.incomingEvents.index(oldname)
                if index >= 0:
                    globals.historySignals.pushState.emit('Change incoming event name for \
                        node \'{0}\' in library \'{1}\''.format(nodename, libname))
                    node.incomingEvents[index] = newname
                    self.modified = True

    def __onOutgoingEventRenameNode(self, libname, nodename, oldname, newname):
        if libname in self.libraries and nodename in self.libraries[libname]:
            node = self.libraries[libname].list[nodename]
            if oldname in node.outgoingEvents:
                index = node.outgoingEvents.index(oldname)
                if index >= 0:
                    globals.historySignals.pushState.emit('Change outgoing event name for \
                        node \'{0}\' in library \'{1}\''.format(nodename, libname))
                    node.outgoingEvents[index] = newname
                    self.modified = True

    def __onIncomingEventAddNode(self, libname, nodename, eventName):
        if libname in self.libraries and nodename in self.libraries[libname]:
            node = self.libraries[libname].list[nodename]
            if eventName not in node.incomingEvents:
                globals.historySignals.pushState.emit(
                    'Add new incoming event for node \'{0}\' in library \'{1}\''.format(nodename, libname))
                node.incomingEvents.append(eventName)
                self.modified = True
                globals.librarySignals.nodeEventsCountChanged.emit(libname, nodename)

    def __onOutgoingEventAddNode(self, libname, nodename, eventName):
        if libname in self.libraries and nodename in self.libraries[libname]:
            node = self.libraries[libname].list[nodename]
            if eventName not in node.outgoingEvents:
                globals.historySignals.pushState.emit(
                    'Add new outgoing event for node \'{0}\' in library \'{1}\''.format(nodename, libname))
                node.outgoingEvents.append(eventName)
                self.modified = True
                globals.librarySignals.nodeEventsCountChanged.emit(libname, nodename)

    def __onIncomingEventDeleteNode(self, libname, nodename, eventName):
        if libname in self.libraries and nodename in self.libraries[libname]:
            node = self.libraries[libname].list[nodename]
            if eventName in node.incomingEvents:
                index = node.incomingEvents.index(eventName)
                if index >= 0:
                    globals.historySignals.pushState.emit(
                        'Remove incoming event for node \'{0}\' in library \'{1}\''.format(nodename, libname))
                    node.incomingEvents.pop(index)
                    self.modified = True
                    globals.librarySignals.nodeEventsCountChanged.emit(libname, nodename)

    def __onOutgoingEventDeleteNode(self, libname, nodename, eventName):
        if libname in self.libraries and nodename in self.libraries[libname]:
            node = self.libraries[libname].list[nodename]
            if eventName in node.outgoingEvents:
                index = node.outgoingEvents.index(eventName)
                if index >= 0:
                    globals.historySignals.pushState.emit(
                        'Remove outgoing event for node \'{0}\' in library \'{1}\''.format(nodename, libname))
                    node.outgoingEvents.pop(index)
                    self.modified = True
                    globals.librarySignals.nodeEventsCountChanged.emit(libname, nodename)