示例#1
0
文件: label.py 项目: obdasystems/eddy
class LabelExplorerWidget(QtWidgets.QWidget):
    """
    This class implements the Label explorer used to list iris with no labels referencing their simple names.
    """
    sgnItemClicked = QtCore.pyqtSignal('QGraphicsItem')
    sgnItemDoubleClicked = QtCore.pyqtSignal('QGraphicsItem')
    sgnItemRightClicked = QtCore.pyqtSignal('QGraphicsItem')
    sgnFakeItemAdded = QtCore.pyqtSignal('QGraphicsScene', 'QGraphicsItem')
    sgnColourItem = QtCore.pyqtSignal('QStandardItem')

    def __init__(self, project, session, **kwargs):
        """
        Initialize the label explorer widget.
        """
        super().__init__(session, objectName=kwargs.get('objectName'))

        self.project = project
        self.iris = None

        self.iconAttribute = QtGui.QIcon(':/icons/18/ic_treeview_attribute')
        self.iconConcept = QtGui.QIcon(':/icons/18/ic_treeview_concept')
        self.iconInstance = QtGui.QIcon(':/icons/18/ic_treeview_instance')
        self.iconRole = QtGui.QIcon(':/icons/18/ic_treeview_role')
        self.iconValue = QtGui.QIcon(':/icons/18/ic_treeview_value')

        self.search = StringField(self)
        self.search.setAcceptDrops(False)
        self.search.setClearButtonEnabled(True)
        self.search.setPlaceholderText('Search...')
        self.search.setFixedHeight(30)
        self.model = QtGui.QStandardItemModel(self)
        # self.proxy = QtCore.QSortFilterProxyModel(self)
        self.proxy = LabelExplorerFilterProxyModel(self)
        self.proxy.setDynamicSortFilter(False)
        self.proxy.setFilterCaseSensitivity(QtCore.Qt.CaseInsensitive)
        self.proxy.setSortCaseSensitivity(QtCore.Qt.CaseSensitive)
        self.proxy.setSourceModel(self.model)
        self.ontoview = LabelExplorerView(self)
        self.ontoview.setModel(self.proxy)
        self.mainLayout = QtWidgets.QVBoxLayout(self)
        self.mainLayout.setContentsMargins(0, 0, 0, 0)
        self.mainLayout.addWidget(self.search)
        self.mainLayout.addWidget(self.ontoview)

        self.setContentsMargins(0, 0, 0, 0)
        self.setMinimumWidth(216)

        self.setStyleSheet("""
            QLineEdit,
            QLineEdit:editable,
            QLineEdit:hover,
            QLineEdit:pressed,
            QLineEdit:focus {
              border: none;
              border-radius: 0;
              background: #FFFFFF;
              color: #000000;
              padding: 4px 4px 4px 4px;
            }
        """)

        header = self.ontoview.header()
        header.setStretchLastSection(False)
        header.setSectionResizeMode(QtWidgets.QHeaderView.ResizeToContents)

        connect(self.search.textChanged, self.doFilterItem)

        '''
        connect(self.ontoview.doubleClicked, self.onItemDoubleClicked)
        connect(self.ontoview.pressed, self.onItemPressed)

        connect(self.sgnItemDoubleClicked, self.session.doFocusItem)
        connect(self.sgnItemRightClicked, self.session.doFocusItem)

        connect(self.sgnColourItem, self.doColorItems)
        '''

    #############################################
    #   PROPERTIES
    #################################

    @property
    def session(self):
        """
        Returns the reference to the active session.
        :rtype: Session
        """
        return self.parent()

    #############################################
    #   EVENTS
    #################################

    def paintEvent(self, paintEvent):
        """
        This is needed for the widget to pick the stylesheet.
        :type paintEvent: QPaintEvent
        """
        option = QtWidgets.QStyleOption()
        option.initFrom(self)
        painter = QtGui.QPainter(self)
        style = self.style()
        style.drawPrimitive(QtWidgets.QStyle.PE_Widget, option, painter, self)

    #############################################
    #   SLOTS
    #################################

    @QtCore.pyqtSlot(IRI)
    def doAddIRI(self, iri):
        iri_to_add = QtGui.QStandardItem(
            '{}'.format(str(iri)))
        iri_to_add.setData(iri)
        self.model.appendRow(iri_to_add)
        self.proxy.sort(0, QtCore.Qt.AscendingOrder)
        return iri_to_add

    @QtCore.pyqtSlot('QStandardItem', str)
    def doAddLabel(self, q_item, label):
        label_to_add = QtGui.QStandardItem(label)
        label_to_add.setData(label)
        q_item.appendRow(label_to_add)
        self.proxy.sort(0, QtCore.Qt.AscendingOrder)



    @QtCore.pyqtSlot()
    def doClear(self):
        """
        Clear all the nodes in the tree view.
        """
        self.search.clear()
        self.model.clear()
        self.ontoview.update()

    @QtCore.pyqtSlot(str)
    def doFilterItem(self, key):
        """
        Executed when the search box is filled with data.
        :type key: str
        """
        self.proxy.setFilterFixedString(key)
        self.proxy.sort(QtCore.Qt.AscendingOrder)



    #############################################
    #   INTERFACE
    #################################
    def setIRIs(self, iris):
        self.iris = iris
        for iri in self.iris:
            iriItem = self.doAddIRI(iri)
            for label in iri.getAllLabelAnnotationAssertions():
                self.doAddLabel(iriItem, label.getObjectResourceString(True))
        self.proxy.invalidateFilter()
        self.proxy.sort(0, QtCore.Qt.AscendingOrder)

    def sizeHint(self):
        """
        Returns the recommended size for this widget.
        :rtype: QtCore.QSize
        """
        return QtCore.QSize(216, 266)
示例#2
0
class ExplanationExplorerWidget(QtWidgets.QWidget):
    """
    This class implements the Explanation explorer used to list Explanation predicates.
    """
    sgnItemClicked = QtCore.pyqtSignal('QGraphicsItem')
    sgnItemDoubleClicked = QtCore.pyqtSignal('QGraphicsItem')
    sgnItemRightClicked = QtCore.pyqtSignal('QGraphicsItem')

    sgnFakeItemAdded = QtCore.pyqtSignal('QGraphicsScene', 'QGraphicsItem')

    sgnColourItem = QtCore.pyqtSignal('QStandardItem')

    def __init__(self, plugin):
        """
        Initialize the Explanation explorer widget.
        :type plugin: Session
        """
        super().__init__(plugin.session)

        self.plugin = plugin

        self.iconAttribute = QtGui.QIcon(':/icons/18/ic_treeview_attribute')
        self.iconConcept = QtGui.QIcon(':/icons/18/ic_treeview_concept')
        self.iconInstance = QtGui.QIcon(':/icons/18/ic_treeview_instance')
        self.iconRole = QtGui.QIcon(':/icons/18/ic_treeview_role')
        self.iconValue = QtGui.QIcon(':/icons/18/ic_treeview_value')

        self.search = StringField(self)
        self.search.setAcceptDrops(False)
        self.search.setClearButtonEnabled(True)
        self.search.setPlaceholderText('Search...')
        self.search.setFixedHeight(30)
        self.model = QtGui.QStandardItemModel(self)
        self.proxy = QtCore.QSortFilterProxyModel(self)
        self.proxy.setDynamicSortFilter(False)
        self.proxy.setFilterCaseSensitivity(QtCore.Qt.CaseInsensitive)
        self.proxy.setSortCaseSensitivity(QtCore.Qt.CaseSensitive)
        self.proxy.setSourceModel(self.model)
        self.ontoview = ExplanationExplorerView(self)
        self.ontoview.setModel(self.proxy)
        self.mainLayout = QtWidgets.QVBoxLayout(self)
        self.mainLayout.setContentsMargins(0, 0, 0, 0)
        self.mainLayout.addWidget(self.search)
        self.mainLayout.addWidget(self.ontoview)

        self.setContentsMargins(0, 0, 0, 0)
        self.setMinimumWidth(216)

        self.setStyleSheet("""
            QLineEdit,
            QLineEdit:editable,
            QLineEdit:hover,
            QLineEdit:pressed,
            QLineEdit:focus {
              border: none;
              border-radius: 0;
              background: #FFFFFF;
              color: #000000;
              padding: 4px 4px 4px 4px;
            }
        """)

        header = self.ontoview.header()
        header.setStretchLastSection(False)
        header.setSectionResizeMode(QtWidgets.QHeaderView.ResizeToContents)

        connect(self.ontoview.doubleClicked, self.onItemDoubleClicked)
        connect(self.ontoview.pressed, self.onItemPressed)
        connect(self.search.textChanged, self.doFilterItem)
        connect(self.sgnItemDoubleClicked, self.session.doFocusItem)
        connect(self.sgnItemRightClicked, self.session.doFocusItem)

        connect(self.sgnColourItem, self.colour_objects)

    #############################################
    #   PROPERTIES
    #################################

    @property
    def project(self):
        """
        Returns the reference to the active project.
        :rtype: Session
        """
        return self.session.project

    @property
    def session(self):
        """
        Returns the reference to the active session.
        :rtype: Session
        """
        return self.plugin.parent()

    #############################################
    #   EVENTS
    #################################

    def paintEvent(self, paintEvent):
        """
        This is needed for the widget to pick the stylesheet.
        :type paintEvent: QPaintEvent
        """
        option = QtWidgets.QStyleOption()
        option.initFrom(self)
        painter = QtGui.QPainter(self)
        style = self.style()
        style.drawPrimitive(QtWidgets.QStyle.PE_Widget, option, painter, self)

    #############################################
    #   SLOTS
    #################################
    @QtCore.pyqtSlot('QStandardItem')
    def colour_objects(self, item=None):

        self.session.BackgrounddeColourNodesAndEdges(
            call_updateNode=False,
            call_ClearInconsistentEntitiesAndDiagItemsData=False)

        self.project.nodes_or_edges_of_axioms_to_display_in_widget = []
        self.project.nodes_or_edges_of_explanations_to_display_in_widget = []

        row_count = item.rowCount()

        for r in range(0, row_count):

            child = item.child(r, 0)

            node_or_edge_or_axiom = child.data()

            if 'eddy.core.items' in str(type(node_or_edge_or_axiom)):

                # item is an axiom
                # child is a node or an edge

                explanation_item = item.parent()
                explanation_item_row_count = explanation_item.rowCount()

                for r2 in range(0, explanation_item_row_count):

                    child_of_explanation_item = explanation_item.child(r2, 0)
                    child_of_explanation_item_row_count = child_of_explanation_item.rowCount(
                    )

                    for r3 in range(0, child_of_explanation_item_row_count):

                        nephew_or_child = child_of_explanation_item.child(
                            r3, 0)
                        nephew_or_child_data = nephew_or_child.data()

                        if 'eddy.core.items' in str(
                                type(nephew_or_child_data)):

                            if nephew_or_child_data.id == node_or_edge_or_axiom.id:
                                #if (nephew_or_child_data.text() == nephew_or_child_data.text()):
                                #print('nephew_or_child_data not coloured - ',nephew_or_child_data)
                                pass
                            else:
                                self.project.nodes_or_edges_of_explanations_to_display_in_widget.append(
                                    nephew_or_child_data)

                self.project.nodes_or_edges_of_axioms_to_display_in_widget.append(
                    node_or_edge_or_axiom)

            if (str(type(node_or_edge_or_axiom)) == '<class \'str\'>') or (str(
                    type(node_or_edge_or_axiom)) == 'str'):

                # item is an explanation
                # child is an axiom
                # colour all the nodes and edges involved in the axiom
                row_count_2 = child.rowCount()

                for r2 in range(0, row_count_2):

                    grand_child = child.child(r2, 0)
                    node_or_edge = grand_child.data()

                    if 'eddy.core.items' in str(type(node_or_edge)):
                        self.project.nodes_or_edges_of_explanations_to_display_in_widget.append(
                            node_or_edge)

        self.project.colour_items_in_case_of_unsatisfiability_or_inconsistent_ontology(
        )

    @QtCore.pyqtSlot(str)
    def doAddExplanation(self, explanation_number):

        explanation_number_to_add = QtGui.QStandardItem('Explanation - ' +
                                                        explanation_number)
        explanation_number_to_add.setData(explanation_number)
        self.model.appendRow(explanation_number_to_add)
        self.proxy.sort(0, QtCore.Qt.AscendingOrder)

    @QtCore.pyqtSlot('QStandardItem', str)
    def doAddAxiom(self, q_item, axiom):

        axiom_to_add = QtGui.QStandardItem(axiom)
        axiom_to_add.setData(axiom)
        q_item.appendRow(axiom_to_add)
        self.proxy.sort(0, QtCore.Qt.AscendingOrder)

    @QtCore.pyqtSlot('QGraphicsScene', 'QGraphicsItem', 'QStandardItem')
    def doAddNodeOREdge(self, diagram, node_or_edge, q_item):

        icon = None

        if 'eddy.core.items.nodes' in str(type(node_or_edge)):
            button_name = str(node_or_edge.id) + ':' + str(node_or_edge.text())
            icon = self.iconFor(node_or_edge)
        elif 'eddy.core.items.edges' in str(type(node_or_edge)):
            button_name = str(node_or_edge.id) + ':' + str(
                node_or_edge.type()).replace('Item.', '')

        node_or_edge_to_append = QtGui.QStandardItem(button_name)

        if icon is not None:
            node_or_edge_to_append.setIcon(icon)

        node_or_edge_to_append.setData(node_or_edge)
        q_item.appendRow(node_or_edge_to_append)

    @QtCore.pyqtSlot('QGraphicsScene', 'QGraphicsItem')
    def doAddNode(self, diagram, node):
        """
        Add a node in the tree view.
        :type diagram: QGraphicsScene
        :type node: AbstractItem
        """
        if node.type() in {
                Item.ConceptNode, Item.RoleNode, Item.AttributeNode,
                Item.IndividualNode
        }:
            #if (('AttributeNode' in str(type(node))) or ('ConceptNode' in str(type(node))) or ('IndividualNode' in str(type(node))) or ('RoleNode' in str(type(node)))):
            parent = self.parentFor(node)
            if not parent:
                parent = QtGui.QStandardItem(self.parentKey(node))
                parent.setIcon(self.iconFor(node))
                self.model.appendRow(parent)
                self.proxy.sort(0, QtCore.Qt.AscendingOrder)
            child = QtGui.QStandardItem(self.childKey(diagram, node))
            child.setData(node)
            parent.appendRow(child)
            self.proxy.sort(0, QtCore.Qt.AscendingOrder)

    @QtCore.pyqtSlot(str)
    def doFilterItem(self, key):
        """
        Executed when the search box is filled with data.
        :type key: str
        """
        self.proxy.setFilterFixedString(key)
        self.proxy.sort(QtCore.Qt.AscendingOrder)

    @QtCore.pyqtSlot('QGraphicsScene', 'QGraphicsItem')
    def doRemoveNode(self, diagram, node):
        """
        Remove a node from the tree view.
        :type diagram: QGraphicsScene
        :type node: AbstractItem
        """
        if node.type() in {
                Item.ConceptNode, Item.RoleNode, Item.AttributeNode,
                Item.IndividualNode
        }:
            #if (('AttributeNode' in str(type(node))) or ('ConceptNode' in str(type(node))) or ('IndividualNode' in str(type(node))) or ('RoleNode' in str(type(node)))):
            parent = self.parentFor(node)
            if parent:
                child = self.childFor(parent, diagram, node)
                if child:
                    parent.removeRow(child.index().row())
                if not parent.rowCount():
                    self.model.removeRow(parent.index().row())

    @QtCore.pyqtSlot('QModelIndex')
    def onItemDoubleClicked(self, index):
        """
        Executed when an item in the treeview is double clicked.
        :type index: QModelIndex
        """
        # noinspection PyArgumentList
        if QtWidgets.QApplication.mouseButtons() & QtCore.Qt.LeftButton:
            item = self.model.itemFromIndex(self.proxy.mapToSource(index))
            if item and item.data():
                if (str(type(item.data())) == '<class \'str\'>') or (str(
                        type(item.data())) == 'str'):
                    # item is an explanation or an axiom
                    self.sgnColourItem.emit(item)
                else:
                    self.sgnItemDoubleClicked.emit(item.data())

    @QtCore.pyqtSlot('QModelIndex')
    def onItemPressed(self, index):
        """
        Executed when an item in the treeview is clicked.
        :type index: QModelIndex
        """
        # noinspection PyArgumentList
        if QtWidgets.QApplication.mouseButtons() & QtCore.Qt.LeftButton:
            item = self.model.itemFromIndex(self.proxy.mapToSource(index))
            if item and item.data():
                if (str(type(item.data())) == '<class \'str\'>') or (str(
                        type(item.data())) == 'str'):
                    # item is an explanation or an axiom
                    self.sgnColourItem.emit(item)
                else:
                    self.sgnItemClicked.emit(item.data())

    #############################################
    #   INTERFACE
    #################################

    def childFor(self, parent, diagram, node):
        """
        Search the item representing this node among parent children.
        :type parent: QtGui.QStandardItem
        :type diagram: Diagram
        :type node: AbstractNode
        """
        key = self.childKey(diagram, node)
        for i in range(parent.rowCount()):
            child = parent.child(i)
            if child.text() == key:
                return child
        return None

    @staticmethod
    def childKey(diagram, node):
        """
        Returns the child key (text) used to place the given node in the treeview.
        :type diagram: Diagram
        :type node: AbstractNode
        :rtype: str
        """
        predicate = node.text().replace('\n', '')
        diagram = rstrip(diagram.name, File.Graphol.extension)
        return '{0} ({1} - {2})'.format(predicate, diagram, node.id)

    def iconFor(self, node):
        """
        Returns the icon for the given node.
        :type node:
        """
        if node.type() is Item.AttributeNode:
            return self.iconAttribute
        if node.type() is Item.ConceptNode:
            return self.iconConcept
        if node.type() is Item.IndividualNode:
            if node.identity() is Identity.Individual:
                return self.iconInstance
            if node.identity() is Identity.Value:
                return self.iconValue
        if node.type() is Item.RoleNode:
            return self.iconRole

    def parentFor(self, node):
        """
        Search the parent element of the given node.
        :type node: AbstractNode
        :rtype: QtGui.QStandardItem
        """
        for i in self.model.findItems(self.parentKey(node),
                                      QtCore.Qt.MatchExactly):
            n = i.child(0).data()
            if node.type() is n.type():
                return i
        return None

    @staticmethod
    def parentKey(node):
        """
        Returns the parent key (text) used to place the given node in the treeview.
        :type node: AbstractNode
        :rtype: str
        """
        return node.text().replace('\n', '')

    def sizeHint(self):
        """
        Returns the recommended size for this widget.
        :rtype: QtCore.QSize
        """
        return QtCore.QSize(216, 266)
示例#3
0
class Explorer(QWidget):
    """
    This class implements the diagram predicate node explorer.
    """
    def __init__(self, mainwindow):
        """
        Initialize the Explorer.
        :type mainwindow: MainWindow
        """
        super().__init__(mainwindow)
        self.expanded = {}
        self.searched = {}
        self.scrolled = {}
        self.mainview = None
        self.iconA = QIcon(':/icons/treeview-icon-attribute')
        self.iconC = QIcon(':/icons/treeview-icon-concept')
        self.iconD = QIcon(':/icons/treeview-icon-datarange')
        self.iconI = QIcon(':/icons/treeview-icon-instance')
        self.iconR = QIcon(':/icons/treeview-icon-role')
        self.iconV = QIcon(':/icons/treeview-icon-value')
        self.search = StringField(self)
        self.search.setAcceptDrops(False)
        self.search.setClearButtonEnabled(True)
        self.search.setPlaceholderText('Search...')
        self.search.setFixedHeight(30)
        self.model = QStandardItemModel(self)
        self.proxy = QSortFilterProxyModel(self)
        self.proxy.setDynamicSortFilter(False)
        self.proxy.setFilterCaseSensitivity(Qt.CaseInsensitive)
        self.proxy.setSortCaseSensitivity(Qt.CaseSensitive)
        self.proxy.setSourceModel(self.model)
        self.view = ExplorerView(mainwindow, self)
        self.view.setModel(self.proxy)
        self.mainLayout = QVBoxLayout(self)
        self.mainLayout.setContentsMargins(0, 0, 0, 0)
        self.mainLayout.addWidget(self.search)
        self.mainLayout.addWidget(self.view)
        self.setContentsMargins(0, 0, 0, 0)
        self.setMinimumWidth(216)
        self.setMinimumHeight(160)

        connect(self.view.doubleClicked, self.itemDoubleClicked)
        connect(self.view.pressed, self.itemPressed)
        connect(self.view.collapsed, self.itemCollapsed)
        connect(self.view.expanded, self.itemExpanded)
        connect(self.search.textChanged, self.filterItem)

    ####################################################################################################################
    #                                                                                                                  #
    #   EVENTS                                                                                                         #
    #                                                                                                                  #
    ####################################################################################################################

    def paintEvent(self, paintEvent):
        """
        This is needed for the widget to pick the stylesheet.
        :type paintEvent: QPaintEvent
        """
        option = QStyleOption()
        option.initFrom(self)
        painter = QPainter(self)
        style = self.style()
        style.drawPrimitive(QStyle.PE_Widget, option, painter, self)

    ####################################################################################################################
    #                                                                                                                  #
    #   SLOTS                                                                                                          #
    #                                                                                                                  #
    ####################################################################################################################

    @pyqtSlot('QGraphicsItem')
    def add(self, item):
        """
        Add a node in the tree view.
        :type item: AbstractItem
        """
        if item.node and item.predicate:
            parent = self.parentFor(item)
            if not parent:
                parent = ParentItem(item)
                parent.setIcon(self.iconFor(item))
                self.model.appendRow(parent)
                self.proxy.sort(0, Qt.AscendingOrder)
            child = ChildItem(item)
            child.setData(item)
            parent.appendRow(child)
            self.proxy.sort(0, Qt.AscendingOrder)

    @pyqtSlot(str)
    def filterItem(self, key):
        """
        Executed when the search box is filled with data.
        :type key: str
        """
        if self.mainview:
            self.proxy.setFilterFixedString(key)
            self.proxy.sort(Qt.AscendingOrder)
            self.searched[self.mainview] = key

    @pyqtSlot('QModelIndex')
    def itemCollapsed(self, index):
        """
        Executed when an item in the tree view is collapsed.
        :type index: QModelIndex
        """
        if self.mainview:
            if self.mainview in self.expanded:
                item = self.model.itemFromIndex(self.proxy.mapToSource(index))
                expanded = self.expanded[self.mainview]
                expanded.remove(item.text())

    @pyqtSlot('QModelIndex')
    def itemDoubleClicked(self, index):
        """
        Executed when an item in the tree view is double clicked.
        :type index: QModelIndex
        """
        item = self.model.itemFromIndex(self.proxy.mapToSource(index))
        node = item.data()
        if node:
            self.selectNode(node)
            self.focusNode(node)

    @pyqtSlot('QModelIndex')
    def itemExpanded(self, index):
        """
        Executed when an item in the tree view is expanded.
        :type index: QModelIndex
        """
        if self.mainview:
            item = self.model.itemFromIndex(self.proxy.mapToSource(index))
            if self.mainview not in self.expanded:
                self.expanded[self.mainview] = set()
            expanded = self.expanded[self.mainview]
            expanded.add(item.text())

    @pyqtSlot('QModelIndex')
    def itemPressed(self, index):
        """
        Executed when an item in the tree view is clicked.
        :type index: QModelIndex
        """
        item = self.model.itemFromIndex(self.proxy.mapToSource(index))
        node = item.data()
        if node:
            self.selectNode(node)

    @pyqtSlot('QGraphicsItem')
    def remove(self, item):
        """
        Remove a node from the tree view.
        :type item: AbstractItem
        """
        if item.node and item.predicate:
            parent = self.parentFor(item)
            if parent:
                child = self.childFor(parent, item)
                if child:
                    parent.removeRow(child.index().row())
                if not parent.rowCount():
                    self.model.removeRow(parent.index().row())

    ####################################################################################################################
    #                                                                                                                  #
    #   AUXILIARY METHODS                                                                                              #
    #                                                                                                                  #
    ####################################################################################################################

    @staticmethod
    def childFor(parent, node):
        """
        Search the item representing this node among parent children.
        :type parent: QStandardItem
        :type node: AbstractNode
        """
        key = ChildItem.key(node)
        for i in range(parent.rowCount()):
            child = parent.child(i)
            if child.text() == key:
                return child
        return None

    def parentFor(self, node):
        """
        Search the parent element of the given node.
        :type node: AbstractNode
        :rtype: QStandardItem
        """
        key = ParentItem.key(node)
        for i in self.model.findItems(key, Qt.MatchExactly):
            n = i.child(0).data()
            if node.item is n.item:
                return i
        return None

    ####################################################################################################################
    #                                                                                                                  #
    #   INTERFACE                                                                                                      #
    #                                                                                                                  #
    ####################################################################################################################

    def browse(self, view):
        """
        Set the widget to inspect the given view.
        :type view: MainView
        """
        self.reset()
        self.mainview = view

        if self.mainview:

            scene = self.mainview.scene()
            connect(scene.index.sgnItemAdded, self.add)
            connect(scene.index.sgnItemRemoved, self.remove)

            for item in scene.index.nodes():
                self.add(item)

            if self.mainview in self.expanded:
                expanded = self.expanded[self.mainview]
                for i in range(self.model.rowCount()):
                    item = self.model.item(i)
                    index = self.proxy.mapFromSource(
                        self.model.indexFromItem(item))
                    self.view.setExpanded(index, item.text() in expanded)

            key = ''
            if self.mainview in self.searched:
                key = self.searched[self.mainview]
            self.search.setText(key)

            if self.mainview in self.scrolled:
                rect = self.rect()
                item = first(self.model.findItems(
                    self.scrolled[self.mainview]))
                for i in range(self.model.rowCount()):
                    self.view.scrollTo(
                        self.proxy.mapFromSource(
                            self.model.indexFromItem(self.model.item(i))))
                    index = self.proxy.mapToSource(
                        self.view.indexAt(rect.topLeft()))
                    if self.model.itemFromIndex(index) is item:
                        break

    def reset(self):
        """
        Clear the widget from inspecting the current view.
        """
        if self.mainview:

            rect = self.rect()
            item = self.model.itemFromIndex(
                self.proxy.mapToSource(self.view.indexAt(rect.topLeft())))
            if item:
                node = item.data()
                key = ParentItem.key(node) if node else item.text()
                self.scrolled[self.mainview] = key
            else:
                self.scrolled.pop(self.mainview, None)

            try:
                scene = self.mainview.scene()
                disconnect(scene.index.sgnItemAdded, self.add)
                disconnect(scene.index.sgnItemRemoved, self.remove)
            except RuntimeError:
                pass
            finally:
                self.mainview = None

        self.model.clear()

    def flush(self, view):
        """
        Flush the cache of the given mainview.
        :type view: MainView
        """
        self.expanded.pop(view, None)
        self.searched.pop(view, None)
        self.scrolled.pop(view, None)

    def iconFor(self, node):
        """
        Returns the icon for the given node.
        :type node:
        """
        if node.item is Item.AttributeNode:
            return self.iconA
        if node.item is Item.ConceptNode:
            return self.iconC
        if node.item is Item.ValueDomainNode:
            return self.iconD
        if node.item is Item.ValueRestrictionNode:
            return self.iconD
        if node.item is Item.IndividualNode:
            if node.identity is Identity.Instance:
                return self.iconI
            if node.identity is Identity.Value:
                return self.iconV
        if node.item is Item.RoleNode:
            return self.iconR

    def focusNode(self, node):
        """
        Focus the given node in the main view.
        :type node: AbstractNode
        """
        if self.mainview:
            self.mainview.centerOn(node)

    def selectNode(self, node):
        """
        Select the given node in the main view.
        :type node: AbstractNode
        """
        if self.mainview:
            scene = self.mainview.scene()
            scene.clearSelection()
            node.setSelected(True)
示例#4
0
class TableExplorerWidget(QtWidgets.QWidget):
    """
    This class implements the schema explorer used to list schema tables.
    """
    sgnGraphicalNodeItemClicked = QtCore.pyqtSignal('QGraphicsItem')
    sgnGraphicalNodeItemActivated = QtCore.pyqtSignal('QGraphicsItem')
    sgnGraphicalNodeItemDoubleClicked = QtCore.pyqtSignal('QGraphicsItem')
    sgnGraphicalNodeItemRightClicked = QtCore.pyqtSignal('QGraphicsItem')
    sgnRelationalTableItemClicked = QtCore.pyqtSignal(RelationalTable)
    sgnRelationalTableItemActivated = QtCore.pyqtSignal(RelationalTable)
    sgnRelationalTableItemDoubleClicked = QtCore.pyqtSignal(RelationalTable)
    sgnRelationalTableItemRightClicked = QtCore.pyqtSignal(RelationalTable)

    def __init__(self, plugin):
        super().__init__(plugin.session)

        self.plugin = plugin
        self.items = [
            EntityType.Class, EntityType.ObjectProperty,
            EntityType.DataProperty
        ]
        self.classIcon = QtGui.QIcon(':/icons/18/ic_treeview_concept')
        self.objPropIcon = QtGui.QIcon(':/icons/18/ic_treeview_role')
        self.dataPropIcon = QtGui.QIcon(':/icons/18/ic_treeview_attribute')
        self.searchShortcut = QtWidgets.QShortcut(
            QtGui.QKeySequence('Ctrl+f+t'), plugin.session)
        self.search = StringField(self)
        self.search.setAcceptDrops(False)
        self.search.setClearButtonEnabled(True)
        self.search.setPlaceholderText('Search...')
        self.search.setToolTip('Search ({})'.format(
            self.searchShortcut.key().toString(QtGui.QKeySequence.NativeText)))
        self.search.setFixedHeight(30)
        self.model = QtGui.QStandardItemModel(self)
        self.proxy = TableExplorerFilterProxyModel(self)
        self.proxy.setDynamicSortFilter(False)
        self.proxy.setFilterCaseSensitivity(QtCore.Qt.CaseInsensitive)
        self.proxy.setSortCaseSensitivity(QtCore.Qt.CaseSensitive)
        self.proxy.setSourceModel(self.model)
        self.tableview = TableExplorerView(self)
        self.tableview.setModel(self.proxy)
        self.mainLayout = QtWidgets.QVBoxLayout(self)
        self.mainLayout.setContentsMargins(0, 0, 0, 0)
        self.mainLayout.addWidget(self.search)
        self.mainLayout.addWidget(self.tableview)
        self.setTabOrder(self.search, self.tableview)
        self.setContentsMargins(0, 0, 0, 0)
        self.setMinimumWidth(216)

        self.setStyleSheet("""
            QLineEdit,
            QLineEdit:editable,
            QLineEdit:hover,
            QLineEdit:pressed,
            QLineEdit:focus {
              border: none;
              border-radius: 0;
              background: #FFFFFF;
              color: #000000;
              padding: 4px 4px 4px 4px;
            }
        """)

        header = self.tableview.header()
        header.setStretchLastSection(False)
        header.setSectionResizeMode(QtWidgets.QHeaderView.ResizeToContents)

        connect(plugin.sgnSchemaChanged, self.onSchemaChanged)
        connect(plugin.sgnNodeAdded, self.doAddNode)
        connect(self.tableview.pressed, self.onItemPressed)
        connect(self.tableview.doubleClicked, self.onItemDoubleClicked)
        connect(self.search.textChanged, self.doFilterItem)
        connect(self.search.returnPressed, self.onReturnPressed)
        connect(self.searchShortcut.activated, self.doFocusSearch)
        connect(self.sgnGraphicalNodeItemActivated, self.plugin.doFocusItem)
        connect(self.sgnGraphicalNodeItemClicked, self.plugin.doFocusItem)
        connect(self.sgnGraphicalNodeItemDoubleClicked,
                self.plugin.doFocusItem)
        connect(self.sgnGraphicalNodeItemRightClicked, self.plugin.doFocusItem)
        connect(self.sgnRelationalTableItemActivated, self.plugin.doFocusTable)
        connect(self.sgnRelationalTableItemClicked, self.plugin.doFocusTable)
        connect(self.sgnRelationalTableItemDoubleClicked,
                self.plugin.doFocusTable)
        connect(self.sgnRelationalTableItemRightClicked,
                self.plugin.doFocusTable)

    #############################################
    #   SLOTS
    #################################

    @QtCore.pyqtSlot(RelationalSchema)
    def onSchemaChanged(self, schema):
        """
        Add a node in the tree view.
        :type schema: RelationalSchema
        """
        self.model.clear()

    @QtCore.pyqtSlot(BlackBirdDiagram, TableNode)
    def doAddNode(self, diagram, node):
        """
        Add a node in the tree view.
        :type diagram: QGraphicsScene
        :type node: TableNode
        """
        parent = self.parentFor(node)
        if not parent:
            parent = QtGui.QStandardItem(self.parentKey(node))
            parent.setIcon(self.iconFor(node.relationalTable))
            parent.setData(node.relationalTable)
            self.model.appendRow(parent)
        child = QtGui.QStandardItem(self.childKey(diagram, node))
        child.setData(node)
        parent.appendRow(child)
        # APPLY FILTERS AND SORT
        if self.sender() != self.plugin:
            self.proxy.invalidateFilter()
            self.proxy.sort(0, QtCore.Qt.AscendingOrder)
        else:
            self.doFilterItem('')

    @QtCore.pyqtSlot('QGraphicsScene', 'QGraphicsItem')
    def doRemoveNode(self, diagram, node):
        """
        Remove a node from the tree view.
        :type diagram: QGraphicsScene
        :type node: AbstractItem
        """
        pass

    @QtCore.pyqtSlot(str)
    def doFilterItem(self, key):
        """
        Executed when the search box is filled with data.
        :type key: str
        """
        self.proxy.setFilterFixedString(key)
        self.proxy.sort(QtCore.Qt.AscendingOrder)

    @QtCore.pyqtSlot()
    def doFocusSearch(self):
        """
        Focus the search bar.
        """
        # RAISE THE ENTIRE WIDGET TREE IF IT IS NOT VISIBLE
        if not self.isVisible():
            widget = self
            while widget != self.session:
                widget.show()
                widget.raise_()
                widget = widget.parent()
        self.search.setFocus()
        self.search.selectAll()

    @QtCore.pyqtSlot()
    def onReturnPressed(self):
        """
        Executed when the Return or Enter key is pressed in the search field.
        """
        self.focusNextChild()

    @QtCore.pyqtSlot('QModelIndex')
    def onItemActivated(self, index):
        """
        Executed when an item in the treeview is activated (e.g. by pressing Return or Enter key).
        :type index: QModelIndex
        """
        # noinspection PyArgumentList
        if QtWidgets.QApplication.mouseButtons() == QtCore.Qt.NoButton:
            item = self.model.itemFromIndex(self.proxy.mapToSource(index))
            if item and item.data():
                if isinstance(item.data(), RelationalTable):
                    self.sgnRelationalTableItemActivated.emit(item.data())
                elif isinstance(item.data(), TableNode):
                    # self.sgnGraphicalNodeItemActivated.emit(item.data())
                    self.sgnRelationalTableItemActivated.emit(
                        item.data().relationalTable)
                # KEEP FOCUS ON THE TREE VIEW UNLESS SHIFT IS PRESSED
                if QtWidgets.QApplication.queryKeyboardModifiers(
                ) & QtCore.Qt.SHIFT:
                    return
                self.tableview.setFocus()
            elif item:
                # EXPAND/COLLAPSE PARENT ITEM
                if self.tableview.isExpanded(index):
                    self.tableview.collapse(index)
                else:
                    self.tableview.expand(index)

    @QtCore.pyqtSlot('QModelIndex')
    def onItemDoubleClicked(self, index):
        """
        Executed when an item in the treeview is double clicked.
        :type index: QModelIndex
        """
        # noinspection PyArgumentList
        if QtWidgets.QApplication.mouseButtons() & QtCore.Qt.LeftButton:
            item = self.model.itemFromIndex(self.proxy.mapToSource(index))
            if item and item.data():
                if isinstance(item.data(), RelationalTable):
                    self.sgnRelationalTableItemDoubleClicked.emit(item.data())
                elif isinstance(item.data(), TableNode):
                    self.sgnGraphicalNodeItemDoubleClicked.emit(item.data())
                    self.sgnRelationalTableItemDoubleClicked.emit(
                        item.data().relationalTable)

    @QtCore.pyqtSlot('QModelIndex')
    def onItemPressed(self, index):
        """
        Executed when an item in the treeview is clicked.
        :type index: QModelIndex
        """
        # noinspection PyArgumentList
        if QtWidgets.QApplication.mouseButtons() & QtCore.Qt.LeftButton:
            item = self.model.itemFromIndex(self.proxy.mapToSource(index))
            if item and item.data():
                if isinstance(item.data(), RelationalTable):
                    self.sgnRelationalTableItemClicked.emit(item.data())
                elif isinstance(item.data(), TableNode):
                    # self.sgnGraphicalNodeItemClicked.emit(item.data())
                    self.sgnRelationalTableItemClicked.emit(
                        item.data().relationalTable)

    #############################################
    #   INTERFACE
    #################################

    def iconFor(self, table):
        """
        Returns the icon for the given node.
        :type table:RelationalTable
        """
        entity = table.entity
        entityType = entity.entityType
        if entityType is EntityType.Class:
            return self.classIcon
        if entityType is EntityType.ObjectProperty:
            return self.objPropIcon
        if entityType is EntityType.DataProperty:
            return self.dataPropIcon

    def parentFor(self, node):
        """
        Search the parent element of the given node.
        :type node: TableNode
        :rtype: QtGui.QStandardItem
        """
        for i in self.model.findItems(self.parentKey(node),
                                      QtCore.Qt.MatchExactly):
            if i.child(0):
                n = i.child(0).data()
                if node.type() is n.type():
                    return i
        return None

    @staticmethod
    def childKey(diagram, node):
        """
        Returns the child key (text) used to place the given node in the treeview.
        :type diagram: Diagram
        :type node: TableNode
        :rtype: str
        """
        diagram = rstrip(diagram.name, File.Graphol.extension)
        return '[{0} - {1}] ({2})'.format(diagram, node.id,
                                          node.relationalTable.name)

    @staticmethod
    def parentKey(node):
        """
        Returns the parent key (text) used to place the given node in the treeview.
        :type node: Union[TableNode,RelationalTable]
        :rtype: str
        """
        if isinstance(node, RelationalTable):
            return node.name
        if isinstance(node, TableNode):
            return node.relationalTable.name

    def sizeHint(self):
        """
        Returns the recommended size for this widget.
        :rtype: QtCore.QSize
        """
        return QtCore.QSize(216, 266)
示例#5
0
class OntologyExplorerWidget(QtWidgets.QWidget):
    """
    This class implements the ontology explorer used to list ontology predicates.
    """
    sgnItemClicked = QtCore.pyqtSignal('QGraphicsItem')
    sgnItemDoubleClicked = QtCore.pyqtSignal('QGraphicsItem')
    sgnItemRightClicked = QtCore.pyqtSignal('QGraphicsItem')

    def __init__(self, plugin):
        """
        Initialize the ontology explorer widget.
        :type plugin: Session
        """
        super().__init__(plugin.session)

        self.plugin = plugin

        self.iconAttribute = QtGui.QIcon(':/icons/18/ic_treeview_attribute')
        self.iconConcept = QtGui.QIcon(':/icons/18/ic_treeview_concept')
        self.iconInstance = QtGui.QIcon(':/icons/18/ic_treeview_instance')
        self.iconRole = QtGui.QIcon(':/icons/18/ic_treeview_role')
        self.iconValue = QtGui.QIcon(':/icons/18/ic_treeview_value')

        self.search = StringField(self)
        self.search.setAcceptDrops(False)
        self.search.setClearButtonEnabled(True)
        self.search.setPlaceholderText('Search...')
        self.search.setFixedHeight(30)
        self.model = QtGui.QStandardItemModel(self)
        self.proxy = QtCore.QSortFilterProxyModel(self)
        self.proxy.setDynamicSortFilter(False)
        self.proxy.setFilterCaseSensitivity(QtCore.Qt.CaseInsensitive)
        self.proxy.setSortCaseSensitivity(QtCore.Qt.CaseSensitive)
        self.proxy.setSourceModel(self.model)
        self.ontoview = OntologyExplorerView(self)
        self.ontoview.setModel(self.proxy)
        self.mainLayout = QtWidgets.QVBoxLayout(self)
        self.mainLayout.setContentsMargins(0, 0, 0, 0)
        self.mainLayout.addWidget(self.search)
        self.mainLayout.addWidget(self.ontoview)

        self.setContentsMargins(0, 0, 0, 0)
        self.setMinimumWidth(216)

        self.setStyleSheet("""
            QLineEdit,
            QLineEdit:editable,
            QLineEdit:hover,
            QLineEdit:pressed,
            QLineEdit:focus {
              border: none;
              border-radius: 0;
              background: #FFFFFF;
              color: #000000;
              padding: 4px 4px 4px 4px;
            }
        """)

        header = self.ontoview.header()
        header.setStretchLastSection(False)
        header.setSectionResizeMode(QtWidgets.QHeaderView.ResizeToContents)

        connect(self.ontoview.doubleClicked, self.onItemDoubleClicked)
        connect(self.ontoview.pressed, self.onItemPressed)
        connect(self.search.textChanged, self.doFilterItem)
        connect(self.sgnItemDoubleClicked, self.session.doFocusItem)
        connect(self.sgnItemRightClicked, self.session.doFocusItem)

    #############################################
    #   PROPERTIES
    #################################

    @property
    def project(self):
        """
        Returns the reference to the active project.
        :rtype: Session
        """
        return self.session.project

    @property
    def session(self):
        """
        Returns the reference to the active session.
        :rtype: Session
        """
        return self.plugin.parent()

    #############################################
    #   EVENTS
    #################################

    def paintEvent(self, paintEvent):
        """
        This is needed for the widget to pick the stylesheet.
        :type paintEvent: QPaintEvent
        """
        option = QtWidgets.QStyleOption()
        option.initFrom(self)
        painter = QtGui.QPainter(self)
        style = self.style()
        style.drawPrimitive(QtWidgets.QStyle.PE_Widget, option, painter, self)

    #############################################
    #   SLOTS
    #################################

    @QtCore.pyqtSlot('QGraphicsScene', 'QGraphicsItem')
    def doAddNode(self, diagram, node):
        """
        Add a node in the tree view.
        :type diagram: QGraphicsScene
        :type node: AbstractItem
        """
        if node.type() in {
                Item.ConceptNode, Item.RoleNode, Item.AttributeNode,
                Item.IndividualNode
        }:
            parent = self.parentFor(node)
            if not parent:
                parent = QtGui.QStandardItem(self.parentKey(node))
                parent.setIcon(self.iconFor(node))
                self.model.appendRow(parent)
                self.proxy.sort(0, QtCore.Qt.AscendingOrder)
            child = QtGui.QStandardItem(self.childKey(diagram, node))
            child.setData(node)
            parent.appendRow(child)
            self.proxy.sort(0, QtCore.Qt.AscendingOrder)

    @QtCore.pyqtSlot(str)
    def doFilterItem(self, key):
        """
        Executed when the search box is filled with data.
        :type key: str
        """
        self.proxy.setFilterFixedString(key)
        self.proxy.sort(QtCore.Qt.AscendingOrder)

    @QtCore.pyqtSlot('QGraphicsScene', 'QGraphicsItem')
    def doRemoveNode(self, diagram, node):
        """
        Remove a node from the tree view.
        :type diagram: QGraphicsScene
        :type node: AbstractItem
        """
        if node.type() in {
                Item.ConceptNode, Item.RoleNode, Item.AttributeNode,
                Item.IndividualNode
        }:
            parent = self.parentFor(node)
            if parent:
                child = self.childFor(parent, diagram, node)
                if child:
                    parent.removeRow(child.index().row())
                if not parent.rowCount():
                    self.model.removeRow(parent.index().row())

    @QtCore.pyqtSlot('QModelIndex')
    def onItemDoubleClicked(self, index):
        """
        Executed when an item in the treeview is double clicked.
        :type index: QModelIndex
        """
        # noinspection PyArgumentList
        if QtWidgets.QApplication.mouseButtons() & QtCore.Qt.LeftButton:
            item = self.model.itemFromIndex(self.proxy.mapToSource(index))
            if item and item.data():
                self.sgnItemDoubleClicked.emit(item.data())

    @QtCore.pyqtSlot('QModelIndex')
    def onItemPressed(self, index):
        """
        Executed when an item in the treeview is clicked.
        :type index: QModelIndex
        """
        # noinspection PyArgumentList
        if QtWidgets.QApplication.mouseButtons() & QtCore.Qt.LeftButton:
            item = self.model.itemFromIndex(self.proxy.mapToSource(index))
            if item and item.data():
                self.sgnItemClicked.emit(item.data())

    #############################################
    #   INTERFACE
    #################################

    def childFor(self, parent, diagram, node):
        """
        Search the item representing this node among parent children.
        :type parent: QtGui.QStandardItem
        :type diagram: Diagram
        :type node: AbstractNode
        """
        key = self.childKey(diagram, node)
        for i in range(parent.rowCount()):
            child = parent.child(i)
            if child.text() == key:
                return child
        return None

    @staticmethod
    def childKey(diagram, node):
        """
        Returns the child key (text) used to place the given node in the treeview.
        :type diagram: Diagram
        :type node: AbstractNode
        :rtype: str
        """
        predicate = node.text().replace('\n', '')
        diagram = rstrip(diagram.name, File.Graphol.extension)
        return '{0} ({1} - {2})'.format(predicate, diagram, node.id)

    def iconFor(self, node):
        """
        Returns the icon for the given node.
        :type node:
        """
        if node.type() is Item.AttributeNode:
            return self.iconAttribute
        if node.type() is Item.ConceptNode:
            return self.iconConcept
        if node.type() is Item.IndividualNode:
            if node.identity() is Identity.Individual:
                return self.iconInstance
            if node.identity() is Identity.Value:
                return self.iconValue
        if node.type() is Item.RoleNode:
            return self.iconRole

    def parentFor(self, node):
        """
        Search the parent element of the given node.
        :type node: AbstractNode
        :rtype: QtGui.QStandardItem
        """
        for i in self.model.findItems(self.parentKey(node),
                                      QtCore.Qt.MatchExactly):
            n = i.child(0).data()
            if node.type() is n.type():
                return i
        return None

    @staticmethod
    def parentKey(node):
        """
        Returns the parent key (text) used to place the given node in the treeview.
        :type node: AbstractNode
        :rtype: str
        """
        return node.text().replace('\n', '')

    def sizeHint(self):
        """
        Returns the recommended size for this widget.
        :rtype: QtCore.QSize
        """
        return QtCore.QSize(216, 266)
示例#6
0
class OntologyExplorerWidget(QtWidgets.QWidget):
    """
    This class implements the ontology explorer used to list ontology predicates.
    """
    sgnItemActivated = QtCore.pyqtSignal('QGraphicsItem')
    sgnItemClicked = QtCore.pyqtSignal('QGraphicsItem')
    sgnItemDoubleClicked = QtCore.pyqtSignal('QGraphicsItem')
    sgnItemRightClicked = QtCore.pyqtSignal('QGraphicsItem')

    sgnIRIItemActivated = QtCore.pyqtSignal(IRI)
    sgnIRIItemClicked = QtCore.pyqtSignal(IRI)
    sgnIRIItemDoubleClicked = QtCore.pyqtSignal(IRI)
    sgnIRIItemRightClicked = QtCore.pyqtSignal(IRI)

    def __init__(self, plugin):
        """
        Initialize the ontology explorer widget.
        :type plugin: Session
        """
        super().__init__(plugin.session)

        self.plugin = plugin
        self.items = [
            Item.ConceptIRINode, Item.RoleIRINode, Item.AttributeIRINode,
            Item.IndividualIRINode, Item.ValueDomainIRINode
        ]
        self.unsatisfiableItems = list()
        self.unsatisfiableClasses = list()
        self.unsatisfiableObjProps = list()
        self.unsatisfiableDataProps = list()

        self.iconAttribute = QtGui.QIcon(':/icons/18/ic_treeview_attribute')
        self.iconConcept = QtGui.QIcon(':/icons/18/ic_treeview_concept')
        self.iconInstance = QtGui.QIcon(':/icons/18/ic_treeview_instance')
        self.iconRole = QtGui.QIcon(':/icons/18/ic_treeview_role')
        self.iconValue = QtGui.QIcon(':/icons/18/ic_treeview_value')

        self.searchShortcut = QtWidgets.QShortcut(QtGui.QKeySequence('Ctrl+f'),
                                                  self.session)
        self.search = StringField(self)
        self.search.setAcceptDrops(False)
        self.search.setClearButtonEnabled(True)
        self.search.setPlaceholderText('Search...')
        self.search.setToolTip('Search ({})'.format(
            self.searchShortcut.key().toString(QtGui.QKeySequence.NativeText)))
        self.search.setFixedHeight(30)
        self.model = QtGui.QStandardItemModel(self)
        self.proxy = OntologyExplorerFilterProxyModel(self)
        self.proxy.setDynamicSortFilter(False)
        self.proxy.setFilterCaseSensitivity(QtCore.Qt.CaseInsensitive)
        self.proxy.setSortCaseSensitivity(QtCore.Qt.CaseSensitive)
        self.proxy.setSourceModel(self.model)
        self.ontoview = OntologyExplorerView(self)
        self.ontoview.setModel(self.proxy)
        self.mainLayout = QtWidgets.QVBoxLayout(self)
        self.mainLayout.setContentsMargins(0, 0, 0, 0)
        self.mainLayout.addWidget(self.search)
        self.mainLayout.addWidget(self.ontoview)
        self.setTabOrder(self.search, self.ontoview)
        self.setContentsMargins(0, 0, 0, 0)
        self.setMinimumWidth(216)
        self.setStyleSheet("""
            QLineEdit,
            QLineEdit:editable,
            QLineEdit:hover,
            QLineEdit:pressed,
            QLineEdit:focus {
              border: none;
              border-radius: 0;
              background: #FFFFFF;
              color: #000000;
              padding: 4px 4px 4px 4px;
            }
        """)
        header = self.ontoview.header()
        header.setStretchLastSection(False)
        header.setSectionResizeMode(QtWidgets.QHeaderView.ResizeToContents)

        connect(self.ontoview.activated, self.onItemActivated)
        connect(self.ontoview.doubleClicked, self.onItemDoubleClicked)
        connect(self.ontoview.pressed, self.onItemPressed)
        connect(self.search.textChanged, self.doFilterItem)
        connect(self.search.returnPressed, self.onReturnPressed)
        connect(self.searchShortcut.activated, self.doFocusSearch)
        connect(self.sgnItemActivated, self.session.doFocusItem)
        connect(self.sgnItemDoubleClicked, self.session.doFocusItem)
        connect(self.sgnItemRightClicked, self.session.doFocusItem)

        connect(self.session.sgnPrefixAdded, self.onPrefixAdded)
        connect(self.session.sgnPrefixRemoved, self.onPrefixRemoved)
        connect(self.session.sgnPrefixModified, self.onPrefixModified)
        connect(self.session.sgnRenderingModified, self.onRenderingModified)

        connect(self.session.sgnIRIRemovedFromAllDiagrams,
                self.onIRIRemovedFromAllDiagrams)
        connect(self.session.sgnSingleNodeSwitchIRI,
                self.onSingleNodeIRISwitched)

    #############################################
    #   PROPERTIES
    #################################

    @property
    def project(self):
        """
        Returns the reference to the active project.
        :rtype: Session
        """
        return self.session.project

    @property
    def session(self):
        """
        Returns the reference to the active session.
        :rtype: Session
        """
        return self.plugin.parent()

    #############################################
    #   EVENTS
    #################################

    def paintEvent(self, paintEvent):
        """
        This is needed for the widget to pick the stylesheet.
        :type paintEvent: QPaintEvent
        """
        option = QtWidgets.QStyleOption()
        option.initFrom(self)
        painter = QtGui.QPainter(self)
        style = self.style()
        style.drawPrimitive(QtWidgets.QStyle.PE_Widget, option, painter, self)

    #############################################
    #   SLOTS
    #################################

    @QtCore.pyqtSlot(str)
    def onRenderingModified(self, rendering):
        # RESET MODEL DISPLAY DATA
        # Here we force te explorer view to become invisible while we update
        # its model in order to avoid unnecessary UI updates that could
        # otherwise cause the entire application to become unresponsive.
        # This is kind of a hack but it works for the moment.
        self.ontoview.setVisible(False)
        for index in range(self.model.rowCount()):
            item = self.model.item(index)
            data = item.data(OntologyExplorerView.IRIRole)
            if isinstance(data, IRI):
                item.setText(self.parentKeyForIRI(data))
        self.model.dataChanged.emit(
            self.model.index(0, 0),
            self.model.index(self.model.rowCount() - 1, 0))
        self.ontoview.setVisible(True)
        # APPLY FILTERS AND SORT
        self.proxy.invalidateFilter()
        self.proxy.sort(0, QtCore.Qt.AscendingOrder)

    @QtCore.pyqtSlot(str, str)
    def onPrefixAdded(self, _prefix: str, _ns: str):
        settings = QtCore.QSettings()
        rendering = settings.value('ontology/iri/render',
                                   IRIRender.PREFIX.value, str)
        if rendering == IRIRender.PREFIX.value or rendering == IRIRender.LABEL.value:
            self.redrawIRIItem()

    @QtCore.pyqtSlot(str)
    def onPrefixRemoved(self, _: str):
        settings = QtCore.QSettings()
        rendering = settings.value('ontology/iri/render',
                                   IRIRender.PREFIX.value, str)
        if rendering == IRIRender.PREFIX.value or rendering == IRIRender.LABEL.value:
            self.redrawIRIItem()

    @QtCore.pyqtSlot(str)
    def onPrefixModified(self, _: str):
        settings = QtCore.QSettings()
        rendering = settings.value('ontology/iri/render',
                                   IRIRender.PREFIX.value, str)
        if rendering == IRIRender.PREFIX.value or rendering == IRIRender.LABEL.value:
            self.redrawIRIItem()

    @QtCore.pyqtSlot(str)
    def onIRIModified(self, _: str):
        iri = self.sender()
        self.redrawIRIItem(iri)

    @QtCore.pyqtSlot(AnnotationAssertion)
    def onIRIAnnotationAssertionAdded(self, _):
        iri = self.sender()
        settings = QtCore.QSettings()
        rendering = settings.value('ontology/iri/render',
                                   IRIRender.PREFIX.value, str)
        if rendering == IRIRender.PREFIX.value or rendering == IRIRender.LABEL.value:
            self.redrawIRIItem(iri)

    @QtCore.pyqtSlot(AnnotationAssertion)
    def onIRIAnnotationAssertionRemoved(self, _):
        iri = self.sender()
        settings = QtCore.QSettings()
        rendering = settings.value('ontology/iri/render',
                                   IRIRender.PREFIX.value, str)
        if rendering == IRIRender.PREFIX.value or rendering == IRIRender.LABEL.value:
            self.redrawIRIItem(iri)

    @QtCore.pyqtSlot(AnnotationAssertion)
    def onIRIAnnotationAssertionModified(self, _):
        iri = self.sender()
        settings = QtCore.QSettings()
        rendering = settings.value('ontology/iri/render',
                                   IRIRender.PREFIX.value, str)
        if rendering == IRIRender.PREFIX.value or rendering == IRIRender.LABEL.value:
            self.redrawIRIItem(iri)

    @QtCore.pyqtSlot()
    def onNodeIRISwitched(self):
        node = self.sender()
        self.doAddNode(node.diagram, node)

    @QtCore.pyqtSlot(AbstractNode, IRI)
    def onSingleNodeIRISwitched(self, node, oldIRI):
        oldParentK = self.parentKeyForIRI(oldIRI)
        for parent in self.model.findItems(oldParentK, QtCore.Qt.MatchExactly):
            rowCount = parent.rowCount()
            for i in range(rowCount):
                child = parent.child(i)
                if child.data(OntologyExplorerView.IRIRole) is node:
                    parent.removeRow(i)
                    break
            if not parent.rowCount():
                if isinstance(node, (
                        OntologyEntityNode,
                        OntologyEntityResizableNode,
                )):
                    self.disconnectIRISignals(
                        parent.data(OntologyExplorerView.IRIRole))
                self.model.removeRow(parent.index().row())

    @QtCore.pyqtSlot(IRI)
    def onIRIRemovedFromAllDiagrams(self, iri):
        parentK = self.parentKeyForIRI(iri)
        for parent in self.model.findItems(parentK, QtCore.Qt.MatchExactly):
            '''
            removeParent = True
            rowCount = parent.rowCount()
            for i in range(rowCount):
                childData = parent.child(i).data(QtCore.Qt.UserRole)
                if isinstance(childData,OntologyEntityNode) or isinstance(childData, OntologyEntityResizableNode):
                    parent.removeRow(i)
                else:
                    removeParent = False
            if removeParent:
                self.model.removeRow(parent.index().row())
            '''
            self.model.removeRow(parent.index().row())

    @QtCore.pyqtSlot(IRI)
    def onUnsatisfiableClass(self, iri):
        parent = self.parentForIRI(iri)
        if parent:
            parent.setData(OntologyExplorerView.UnsatisfiableBrush,
                           QtCore.Qt.ForegroundRole)
            self.unsatisfiableItems.append(parent)
            self.unsatisfiableClasses.append(parent)

    @QtCore.pyqtSlot(IRI)
    def onUnsatisfiableObjectProperty(self, iri):
        parent = self.parentForIRI(iri)
        if parent:
            parent.setData(OntologyExplorerView.UnsatisfiableBrush,
                           QtCore.Qt.ForegroundRole)
            self.unsatisfiableItems.append(parent)
            self.unsatisfiableObjProps.append(parent)

    @QtCore.pyqtSlot(IRI)
    def onUnsatisfiableDataProperty(self, iri):
        parent = self.parentForIRI(iri)
        if parent:
            parent.setData(OntologyExplorerView.UnsatisfiableBrush,
                           QtCore.Qt.ForegroundRole)
            self.unsatisfiableItems.append(parent)
            self.unsatisfiableDataProps.append(parent)

    @QtCore.pyqtSlot()
    def doResetReasonerHighlight(self):
        for item in self.unsatisfiableItems:
            item.setData(None, QtCore.Qt.ForegroundRole)
        self.unsatisfiableItems = list()
        self.unsatisfiableClasses = list()
        self.unsatisfiableObjProps = list()
        self.unsatisfiableDataProps = list()

    @QtCore.pyqtSlot(ImportedOntology)
    def onImportedOntologyAdded(self, impOnt):
        """
        :param impOnt:ImportedOntology
        :return:
        """
        for classIRI in impOnt.classes:
            parent = self.parentForIRI(classIRI)
            if not parent:
                parent = QtGui.QStandardItem(self.parentKeyForIRI(classIRI))
                parent.setData(classIRI, OntologyExplorerView.IRIRole)
                self.connectIRISignals(classIRI)
                self.model.appendRow(parent)
            child = QtGui.QStandardItem(
                self.childKeyForImported(impOnt, classIRI))
            # CHECK FOR DUPLICATE NODES
            children = [parent.child(i) for i in range(parent.rowCount())]
            if not any([(child.text() == c.text()
                         and c.icon() is self.iconConcept) for c in children]):
                child.setIcon(self.iconConcept)
                childData = [classIRI, Item.ConceptIRINode.value]
                child.setData(childData, OntologyExplorerView.IRIRole)
                parent.appendRow(child)
        for objPropIRI in impOnt.objectProperties:
            parent = self.parentForIRI(objPropIRI)
            if not parent:
                parent = QtGui.QStandardItem(self.parentKeyForIRI(objPropIRI))
                parent.setData(objPropIRI, OntologyExplorerView.IRIRole)
                self.connectIRISignals(objPropIRI)
                self.model.appendRow(parent)
            child = QtGui.QStandardItem(
                self.childKeyForImported(impOnt, objPropIRI))
            # CHECK FOR DUPLICATE NODES
            children = [parent.child(i) for i in range(parent.rowCount())]
            if not any([(child.text() == c.text()
                         and c.icon() is self.iconRole) for c in children]):
                child.setIcon(self.iconRole)
                childData = [objPropIRI, Item.RoleIRINode.value]
                child.setData(childData, OntologyExplorerView.IRIRole)
                parent.appendRow(child)
        for dataPropIRI in impOnt.dataProperties:
            parent = self.parentForIRI(dataPropIRI)
            if not parent:
                parent = QtGui.QStandardItem(self.parentKeyForIRI(dataPropIRI))
                parent.setData(dataPropIRI, OntologyExplorerView.IRIRole)
                self.connectIRISignals(dataPropIRI)
                self.model.appendRow(parent)
            child = QtGui.QStandardItem(
                self.childKeyForImported(impOnt, dataPropIRI))
            # CHECK FOR DUPLICATE NODES
            children = [parent.child(i) for i in range(parent.rowCount())]
            if not any([(child.text() == c.text()
                         and c.icon() is self.iconAttribute)
                        for c in children]):
                child.setIcon(self.iconAttribute)
                childData = [dataPropIRI, Item.AttributeIRINode.value]
                child.setData(childData, OntologyExplorerView.IRIRole)
                parent.appendRow(child)
        for indIRI in impOnt.individuals:
            parent = self.parentForIRI(indIRI)
            if not parent:
                parent = QtGui.QStandardItem(self.parentKeyForIRI(indIRI))
                parent.setData(indIRI, OntologyExplorerView.IRIRole)
                self.connectIRISignals(indIRI)
                self.model.appendRow(parent)
            child = QtGui.QStandardItem(
                self.childKeyForImported(impOnt, indIRI))
            # CHECK FOR DUPLICATE NODES
            children = [parent.child(i) for i in range(parent.rowCount())]
            if not any([(child.text() == c.text()
                         and c.icon() is self.iconInstance)
                        for c in children]):
                child.setIcon(self.iconInstance)
                childData = [indIRI, Item.IndividualIRINode.value]
                child.setData(childData, OntologyExplorerView.IRIRole)
                parent.appendRow(child)
        # APPLY FILTERS AND SORT
        if self.sender() != self.plugin:
            self.proxy.invalidateFilter()
            self.proxy.sort(0, QtCore.Qt.AscendingOrder)

    @QtCore.pyqtSlot(ImportedOntology)
    def onImportedOntologyRemoved(self, impOnt):
        """
        :param impOnt:ImportedOntology
        :return:
        """
        for classIRI in impOnt.classes:
            parent = self.parentForIRI(classIRI)
            if parent:
                child = self.childForImported(parent, impOnt, classIRI)
                if child:
                    parent.removeRow((child.index().row()))
                if not parent.rowCount():
                    self.disconnectIRISignals(classIRI)
                    self.model.removeRow(parent.index().row())
        for objPropIRI in impOnt.objectProperties:
            parent = self.parentForIRI(objPropIRI)
            if parent:
                child = self.childForImported(parent, impOnt, objPropIRI)
                if child:
                    parent.removeRow((child.index().row()))
                if not parent.rowCount():
                    self.disconnectIRISignals(objPropIRI)
                    self.model.removeRow(parent.index().row())
        for dataPropIRI in impOnt.dataProperties:
            parent = self.parentForIRI(dataPropIRI)
            if parent:
                child = self.childForImported(parent, impOnt, dataPropIRI)
                if child:
                    parent.removeRow((child.index().row()))
                if not parent.rowCount():
                    self.disconnectIRISignals(dataPropIRI)
                    self.model.removeRow(parent.index().row())
        for indIRI in impOnt.individuals:
            parent = self.parentForIRI(indIRI)
            if parent:
                child = self.childForImported(parent, impOnt, indIRI)
                if child:
                    parent.removeRow((child.index().row()))
                if not parent.rowCount():
                    self.disconnectIRISignals(indIRI)
                    self.model.removeRow(parent.index().row())
        # APPLY FILTERS AND SORT
        if self.sender() != self.plugin:
            self.proxy.invalidateFilter()
            self.proxy.sort(0, QtCore.Qt.AscendingOrder)

    @QtCore.pyqtSlot('QGraphicsScene', 'QGraphicsItem')
    def doAddNode(self, diagram, node):
        """
        Add a node in the tree view.
        :type diagram: QGraphicsScene
        :type node: AbstractItem
        """
        if node.type() in self.items:
            parent = self.parentFor(node)
            if not parent:
                if not isinstance(node, (
                        OntologyEntityNode,
                        OntologyEntityResizableNode,
                )):
                    parent = QtGui.QStandardItem(self.parentKey(node))
                    parent.setIcon(self.iconFor(node))
                else:
                    parent = QtGui.QStandardItem(self.parentKeyForIRI(
                        node.iri))
                    parent.setData(node.iri, OntologyExplorerView.IRIRole)
                    self.connectIRISignals(node.iri)
                self.model.appendRow(parent)
            child = QtGui.QStandardItem(self.childKey(diagram, node))
            if isinstance(node, (
                    OntologyEntityNode,
                    OntologyEntityResizableNode,
            )):
                child.setIcon(self.iconFor(node))
                connect(node.sgnIRISwitched, self.onNodeIRISwitched)
            child.setData(node, OntologyExplorerView.IRIRole)
            parent.appendRow(child)
            # APPLY FILTERS AND SORT
            if self.sender() != self.plugin:
                self.proxy.invalidateFilter()
                self.proxy.sort(0, QtCore.Qt.AscendingOrder)

    @QtCore.pyqtSlot('QGraphicsScene', 'QGraphicsItem')
    def doRemoveNode(self, diagram, node):
        """
        Remove a node from the tree view.
        :type diagram: QGraphicsScene
        :type node: AbstractItem
        """
        if node.type() in self.items:
            parent = self.parentFor(node)
            if parent:
                child = self.childFor(parent, diagram, node)
                if child:
                    parent.removeRow(child.index().row())
                if not parent.rowCount():
                    if isinstance(node, (
                            OntologyEntityNode,
                            OntologyEntityResizableNode,
                    )):
                        self.disconnectIRISignals(
                            parent.data(OntologyExplorerView.IRIRole))
                    self.model.removeRow(parent.index().row())

    @QtCore.pyqtSlot(str)
    def doFilterItem(self, key):
        """
        Executed when the search box is filled with data.
        :type key: str
        """
        self.proxy.setFilterFixedString(key)
        self.proxy.sort(QtCore.Qt.AscendingOrder)

    @QtCore.pyqtSlot()
    def doFocusSearch(self):
        """
        Focus the search bar.
        """
        # RAISE THE ENTIRE WIDGET TREE IF IT IS NOT VISIBLE
        if not self.isVisible():
            widget = self
            while widget != self.session:
                widget.show()
                widget.raise_()
                widget = widget.parent()
        self.search.setFocus()
        self.search.selectAll()

    @QtCore.pyqtSlot('QModelIndex')
    def onItemActivated(self, index):
        """
        Executed when an item in the treeview is activated (e.g. by pressing Return or Enter key).
        :type index: QModelIndex
        """
        # noinspection PyArgumentList
        if QtWidgets.QApplication.mouseButtons() == QtCore.Qt.NoButton:
            item = self.model.itemFromIndex(self.proxy.mapToSource(index))
            if item and item.data(OntologyExplorerView.IRIRole):
                if isinstance(item.data(OntologyExplorerView.IRIRole), IRI):
                    self.sgnIRIItemActivated.emit(
                        item.data(OntologyExplorerView.IRIRole))
                else:
                    self.sgnItemActivated.emit(
                        item.data(OntologyExplorerView.IRIRole))
                # KEEP FOCUS ON THE TREE VIEW UNLESS SHIFT IS PRESSED
                if QtWidgets.QApplication.queryKeyboardModifiers(
                ) & QtCore.Qt.SHIFT:
                    return
                self.ontoview.setFocus()
            elif item:
                # EXPAND/COLLAPSE PARENT ITEM
                if self.ontoview.isExpanded(index):
                    self.ontoview.collapse(index)
                else:
                    self.ontoview.expand(index)

    @QtCore.pyqtSlot('QModelIndex')
    def onItemDoubleClicked(self, index):
        """
        Executed when an item in the treeview is double clicked.
        :type index: QModelIndex
        """
        # noinspection PyArgumentList
        if QtWidgets.QApplication.mouseButtons() & QtCore.Qt.LeftButton:
            item = self.model.itemFromIndex(self.proxy.mapToSource(index))
            if item and item.data(OntologyExplorerView.IRIRole):
                if isinstance(item.data(OntologyExplorerView.IRIRole), IRI):
                    self.sgnIRIItemDoubleClicked.emit(
                        item.data(OntologyExplorerView.IRIRole))
                elif isinstance(item.data(OntologyExplorerView.IRIRole),
                                AbstractNode):
                    self.sgnItemDoubleClicked.emit(
                        item.data(OntologyExplorerView.IRIRole))

    @QtCore.pyqtSlot('QModelIndex')
    def onItemPressed(self, index):
        """
        Executed when an item in the treeview is clicked.
        :type index: QModelIndex
        """
        # noinspection PyArgumentList
        if QtWidgets.QApplication.mouseButtons() & QtCore.Qt.LeftButton:
            item = self.model.itemFromIndex(self.proxy.mapToSource(index))
            if item and item.data(OntologyExplorerView.IRIRole):
                if isinstance(item.data(OntologyExplorerView.IRIRole), IRI):
                    self.sgnIRIItemClicked.emit(
                        item.data(OntologyExplorerView.IRIRole))
                elif isinstance(item.data(OntologyExplorerView.IRIRole),
                                AbstractNode):
                    self.sgnItemClicked.emit(
                        item.data(OntologyExplorerView.IRIRole))

    @QtCore.pyqtSlot()
    def onReturnPressed(self):
        """
        Executed when the Return or Enter key is pressed in the search field.
        """
        self.focusNextChild()

    #############################################
    #   INTERFACE
    #################################

    def connectNodeSignals(self, node):
        """
        :type node: OntologyEntityNode | OntologyEntityResizableNode
        """
        connect(node.sgnIRISwitched, self.onNodeIRISwitched)

    def connectIRISignals(self, iri):
        """
        :type iri: IRI
        """
        connect(iri.sgnAnnotationAdded, self.onIRIAnnotationAssertionAdded)
        connect(iri.sgnAnnotationRemoved, self.onIRIAnnotationAssertionRemoved)
        connect(iri.sgnAnnotationModified,
                self.onIRIAnnotationAssertionModified)
        connect(iri.sgnIRIModified, self.onIRIModified)

    def disconnectIRISignals(self, iri):
        """
        :type iri: IRI
        """
        disconnect(iri.sgnAnnotationAdded, self.onIRIAnnotationAssertionAdded)
        disconnect(iri.sgnAnnotationRemoved,
                   self.onIRIAnnotationAssertionRemoved)
        disconnect(iri.sgnAnnotationModified,
                   self.onIRIAnnotationAssertionModified)
        disconnect(iri.sgnIRIModified, self.onIRIModified)

    def redrawIRIItem(self, iri=None):
        self.ontoview.setSortingEnabled(False)
        for row in range(self.model.rowCount()):
            currItem = self.model.item(row)
            if iri:
                currIRI = currItem.data(OntologyExplorerView.IRIRole)
                if currIRI is iri:
                    currItem.setText(self.parentKeyForIRI(iri))
                    break
            else:
                if isinstance(currItem.data(OntologyExplorerView.IRIRole),
                              IRI):
                    currItem.setText(
                        self.parentKeyForIRI(
                            currItem.data(OntologyExplorerView.IRIRole)))
        self.ontoview.setSortingEnabled(True)
        if self.sender() != self.plugin:
            self.proxy.invalidateFilter()
            self.proxy.sort(0, QtCore.Qt.AscendingOrder)

    def childFor(self, parent, diagram, node):
        """
        Search the item representing this node among parent children.
        :type parent: QtGui.QStandardItem
        :type diagram: Diagram
        :type node: AbstractNode
        """
        key = self.childKey(diagram, node)
        for i in range(parent.rowCount()):
            child = parent.child(i)
            if child.text() == key:
                return child
        return None

    def childForImported(self, parent, impOnt, iri):
        """
        Search the item representing this node among parent children.
        :type parent: QtGui.QStandardItem
        :type impOnt: ImportedOntology
        :type iri: IRI
        """
        key = self.childKeyForImported(impOnt, iri)
        for i in range(parent.rowCount()):
            child = parent.child(i)
            if child.text() == key:
                return child
        return None

    @staticmethod
    def childKey(diagram, node):
        """
        Returns the child key (text) used to place the given node in the treeview.
        :type diagram: Diagram
        :type node: AbstractNode
        :rtype: str
        """
        diagram = rstrip(diagram.name, File.Graphol.extension)

        if isinstance(node, (OntologyEntityNode, OntologyEntityResizableNode)):
            return '{0} - {1}'.format(diagram, node.id)
        else:
            predicate = node.text().replace('\n', '')
            return '{0} ({1} - {2})'.format(predicate, diagram, node.id)

    @staticmethod
    def childKeyForImported(impOnt, iri):
        """
        Returns the child key (text) used to place the given node in the treeview.
        :type impOnt: ImportedOntology
        :type iri: IRI
        :rtype: str
        """
        return 'Imported from {}'.format(impOnt.docLocation)

    def iconFor(self, node):
        """
        Returns the icon for the given node.
        :type node:
        """
        if node.type() is Item.AttributeIRINode:
            return self.iconAttribute
        if node.type() is Item.ConceptIRINode:
            return self.iconConcept
        if node.type() is Item.IndividualIRINode:
            return self.iconInstance
        if node.type() is Item.RoleIRINode:
            return self.iconRole
        if node.type() is Item.ValueDomainIRINode:
            return self.iconValue

    def parentFor(self, node):
        """
        Search the parent element of the given node.
        :type node: AbstractNode
        :rtype: QtGui.QStandardItem
        """
        if isinstance(node, (
                OntologyEntityNode,
                OntologyEntityResizableNode,
        )):
            parentK = self.parentKeyForIRI(node.iri)
            for i in self.model.findItems(parentK, QtCore.Qt.MatchExactly):
                parentIRI = i.data(OntologyExplorerView.IRIRole)
                if node.iri is parentIRI:
                    return i
        else:
            parentK = self.parentKey(node)
            for i in self.model.findItems(parentK, QtCore.Qt.MatchExactly):
                n = i.child(0).data(OntologyExplorerView.IRIRole)
                if node.type() is n.type():
                    return i
        return None

    def parentForIRI(self, iri):
        """
        Search the parent element of the given iri.
        :type node: IRI
        :rtype: QtGui.QStandardItem
        """
        parentK = self.parentKeyForIRI(iri)
        for i in self.model.findItems(parentK, QtCore.Qt.MatchExactly):
            parentIRI = i.data(OntologyExplorerView.IRIRole)
            if iri is parentIRI:
                return i
        return None

    @staticmethod
    def parentKeyForIRI(iri):
        return IRIRender.iriLabelString(iri).replace('\n', '')

    @staticmethod
    def parentKey(node):
        """
        Returns the parent key (text) used to place the given node in the treeview.
        :type node: AbstractNode
        :type project Project
        :rtype: str
        """
        return node.text().replace('\n', '')

    def sizeHint(self):
        """
        Returns the recommended size for this widget.
        :rtype: QtCore.QSize
        """
        return QtCore.QSize(216, 266)
示例#7
0
class IriWidget(QtWidgets.QScrollArea):
    """
    This class implements the information box widget.
    """
    def __init__(self, plugin):
        """
        Initialize the info box.
        :type plugin: Info
        """
        super().__init__(plugin.session)

        self.plugin = plugin

        self.mainLayout = QtWidgets.QVBoxLayout(self)
        self.mainLayout.setAlignment(QtCore.Qt.AlignTop)
        self.mainLayout.setContentsMargins(0, 0, 0, 0)
        self.mainLayout.setSpacing(0)

        #############

        self.tableheader_prefixes = Header('Prefix', self)
        self.tableheader_iri = Header(' IRI  ', self)
        self.tableheader_nodes = Header('Nodes ', self)
        """
        self.horizontalbox = QtWidgets.QHBoxLayout(self)   #to be added to main layout
        self.horizontalbox.setAlignment(QtCore.Qt.AlignTop)
        self.horizontalbox.setContentsMargins(0, 0, 0, 0)
        self.horizontalbox.setSpacing(0)
        self.horizontalbox.addWidget(self.tableheader_iri)
        self.horizontalbox.addWidget(self.tableheader_prefixes)
        self.horizontalbox.addWidget(self.tableheader_nodes)
        """
        #############

        self.entry_status = QtWidgets.QStatusBar()
        """
        self.slider = QtWidgets.QSlider()

        self.slider.setCursor(QtGui.QCursor())
        self.slider.setEnabled(True)
        self.slider.setRange(1,100)
        self.slider.setValue(12)
        self.slider.setTickPosition(QtWidgets.QSlider.TicksBothSides)
        self.slider.setTracking(True)
        self.slider.setTickInterval(1)
        self.slider.setMouseTracking(True)
        self.slider.setTracking(True)
        """
        """
        self.entry_button = QtWidgets.QPushButton()
        self.entry_button.setText('+++')
        self.remove_entry_button = QtWidgets.QPushButton()
        self.remove_entry_button.setText('---')
        self.modify_entry_button = QtWidgets.QPushButton()
        self.modify_entry_button.setText('M')
        """
        self.test_IRI_button = QtWidgets.QPushButton()
        self.test_IRI_button.setText('T')
        self.dictionary_display_button = QtWidgets.QPushButton()
        self.dictionary_display_button.setText('D')
        self.hide_or_show_nodes_button = QtWidgets.QPushButton()
        self.hide_or_show_nodes_button.setText('*')

        self.buttons_layout = QtWidgets.QHBoxLayout(self)
        self.buttons_layout.setAlignment(QtCore.Qt.AlignTop)
        self.buttons_layout.setContentsMargins(0, 0, 0, 0)
        self.buttons_layout.setSpacing(0)
        #self.buttons_layout.addWidget(self.entry_button)
        #self.buttons_layout.addWidget(self.remove_entry_button)
        #self.buttons_layout.addWidget(self.modify_entry_button)
        #self.buttons_layout.addWidget(self.test_IRI_button)
        self.buttons_layout.addWidget(self.dictionary_display_button)
        self.buttons_layout.addWidget(self.hide_or_show_nodes_button)

        #connect(self.entry_button.pressed, self.button_add)
        #connect(self.remove_entry_button.pressed, self.button_remove)
        connect(self.dictionary_display_button.pressed,
                self.display_IRIPrefixesNodesDict)
        connect(self.hide_or_show_nodes_button.pressed,
                self.hide_or_show_nodes)
        connect(self.test_IRI_button.pressed, self.test_IRI)
        #connect(self.modify_entry_button.pressed, self.process_entry_from_textboxes_for_button_modify)

        #connect(self.slider.sliderMoved, self.slider_moved)

        self.prefix_input_box = StringField(self)
        self.prefix_input_box.setPlaceholderText('Enter Prefix')
        self.prefix_input_box.setAcceptDrops(False)
        self.prefix_input_box.setClearButtonEnabled(True)
        self.prefix_input_box.setFixedHeight(30)

        self.iri_input_box = StringField(self)
        self.iri_input_box.setPlaceholderText('Enter IRI')
        self.iri_input_box.setAcceptDrops(False)
        self.iri_input_box.setClearButtonEnabled(True)
        self.iri_input_box.setFixedHeight(30)

        self.verticalbox = QtWidgets.QVBoxLayout(
            self)  # to be added to main layout
        self.verticalbox.setAlignment(QtCore.Qt.AlignTop)
        self.verticalbox.setContentsMargins(0, 0, 0, 0)
        self.verticalbox.setSpacing(0)
        #self.verticalbox.addWidget(self.iri_input_box)
        #self.verticalbox.addWidget(self.prefix_input_box)
        self.verticalbox.addLayout(self.buttons_layout)
        #self.verticalbox.addWidget(self.entry_button)
        #self.verticalbox.addWidget(self.remove_entry_button)
        #self.verticalbox.addWidget(self.dictionary_display_button)
        #self.verticalbox.addWidget(self.slider)
        self.verticalbox.addWidget(self.entry_status)

        #############

        self.table = QtWidgets.QTableWidget(self)
        self.table.setContentsMargins(0, 0, 0, 0)
        self.table.horizontalHeader().setVisible(False)
        self.table.verticalHeader().setVisible(False)
        self.table.setMinimumWidth(self.width())
        self.table.setMinimumHeight(self.height() -
                                    self.dictionary_display_button.height())

        connect(self.table.cellPressed, self.try_to_edit_cell)

        self.horizontalbox_3 = QtWidgets.QHBoxLayout(
            self)  #to be added to main layout
        self.horizontalbox_3.setAlignment(QtCore.Qt.AlignTop)
        self.horizontalbox_3.setContentsMargins(0, 0, 0, 0)
        self.horizontalbox_3.setSpacing(0)
        self.horizontalbox_3.addWidget(self.table)

        #############

        self.mainLayout.addLayout(self.verticalbox)
        #self.mainLayout.addLayout(self.horizontalbox)
        self.mainLayout.addLayout(self.horizontalbox_3)

        #############

        self.setContentsMargins(0, 0, 0, 0)
        self.setMinimumSize(QtCore.QSize(216, 120))
        self.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff)
        self.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAsNeeded)
        self.setWidgetResizable(True)

        self.setStyleSheet("""
        IriWidget {
          background: #FFFFFF;
        }
        IriWidget Header {
          background: #5A5050;
          padding-left: 4px;
          color: #FFFFFF;
        }
        """)

        scrollbar = self.verticalScrollBar()
        scrollbar.installEventFilter(self)

        self.ENTRY_MODIFY_OK_var = set()
        self.ENTRY_REMOVE_OK_var = set()
        self.ENTRY_ADD_OK_var = set()
        self.ENTRY_IGNORE_var = set()

        self.ADD_OR_REMOVE = None

        self.SHOW_NODES = True

        self.ITEM_ACTIVATED = None

    #############################################
    #   PROPERTIES
    #################################

    @property
    def project(self):
        """
        Returns the reference to the active project.
        :rtype: Session
        """
        return self.session.project

    @property
    def session(self):
        """
        Returns the reference to the active session.
        :rtype: Session
        """
        return self.plugin.parent()

    #############################################
    #   EVENTS
    #################################

    def eventFilter(self, source, event):
        """
        Filter incoming events.
        :type source: QObject
        :type event: QtCore.QEvent
        """
        if source is self.verticalScrollBar():
            if event.type() in {QtCore.QEvent.Show, QtCore.QEvent.Hide}:
                self.redraw()
        return super().eventFilter(source, event)

    ###############################
    #
    ###############################
    @QtCore.pyqtSlot(str, str, str, str)
    def entry_MODIFY_ok(self, iri_from, prefix_from, iri_to, prefix_to):

        self.ENTRY_MODIFY_OK_var.add(True)

        self.entry_status.showMessage('Successfully modified', 10000)
        print('entry_ADD_ok(self): ', iri_from, ',', prefix_from, ',', iri_to,
              ',', prefix_to)

    @QtCore.pyqtSlot(str, str, str)
    def entry_ADD_ok(self, iri, prefix, message):

        self.ENTRY_ADD_OK_var.add(True)
        self.entry_status.showMessage(message, 10000)
        print('entry_ADD_ok(self): ', iri, ',', prefix, ',', message)

    @QtCore.pyqtSlot(str, str, str)
    def entry_REMOVE_OK(self, iri, prefix, message):

        self.ENTRY_REMOVE_OK_var.add(True)
        self.entry_status.showMessage(message, 10000)
        print('entry_REMOVE_ok(self): ', iri, ',', prefix, ',', message)

    @QtCore.pyqtSlot(str, str, str)
    def entry_NOT_OK(self, iri, prefixes, message):

        self.ENTRY_IGNORE_var.add(True)
        self.entry_status.showMessage(message, 10000)
        print('entry_NOT_OK(self): ', iri, ',', prefixes, ',', message)

    @QtCore.pyqtSlot(int, int)
    def try_to_edit_cell(self, r, c):

        print(r, '-', c)
        self.table.editItem(self.table.item(r, c))

    def test_IRI(self):

        iri_inp = self.iri_input_box.text()
        res = self.project.check_validity_of_IRI(iri_inp)
        print('IRI_valid', res)

    def display_IRIPrefixesNodesDict(self):

        self.project.print_dictionary(self.project.IRI_prefixes_nodes_dict)

    def FillTableWithStandardData(self):

        for iri in self.project.IRI_prefixes_nodes_dict.keys():
            if iri in OWLStandardIRIPrefixPairsDict.std_IRI_prefix_dict.keys():
                item_iri = QtWidgets.QTableWidgetItem()
                item_iri.setText(iri)
                item_iri.setFlags(QtCore.Qt.ItemIsEnabled
                                  | QtCore.Qt.ItemIsSelectable)
                item_iri.setBackground(
                    QtGui.QBrush(QtGui.QColor(50, 50, 205, 50)))
                self.table.setItem(self.table.rowCount() - 1, 0, item_iri)

                prefixes = self.project.IRI_prefixes_nodes_dict[iri][0]
                item_prefixes = QtWidgets.QTableWidgetItem()
                item_prefixes.setText(str(prefixes))
                item_prefixes.setFlags(QtCore.Qt.ItemIsEnabled
                                       | QtCore.Qt.ItemIsSelectable)
                item_prefixes.setBackground(
                    QtGui.QBrush(QtGui.QColor(50, 50, 205, 50)))
                self.table.setItem(self.table.rowCount() - 1, 1, item_prefixes)

                if self.SHOW_NODES is True:

                    nodes = self.project.IRI_prefixes_nodes_dict[iri][1]
                    item_nodes = QtWidgets.QTableWidgetItem()
                    nds_ids = set()
                    for n in nodes:
                        nds_ids.add(n.id_with_diag)
                    item_nodes.setText(str(nds_ids))
                    item_nodes.setFlags(QtCore.Qt.ItemIsEnabled
                                        | QtCore.Qt.ItemIsSelectable)
                    item_nodes.setBackground(
                        QtGui.QBrush(QtGui.QColor(50, 50, 205, 50)))
                    self.table.setItem(self.table.rowCount() - 1, 2,
                                       item_nodes)

                    properties = self.project.IRI_prefixes_nodes_dict[iri][2]
                    item_properties = QtWidgets.QTableWidgetItem()
                    item_properties.setText(str(properties))
                    item_properties.setFlags(QtCore.Qt.ItemIsEnabled
                                             | QtCore.Qt.ItemIsSelectable)
                    self.table.setItem(self.table.rowCount() - 1, 3,
                                       item_properties)

                self.table.setRowCount(self.table.rowCount() + 1)

        iri = self.project.iri
        item_iri = QtWidgets.QTableWidgetItem()
        item_iri.setText(iri)
        item_iri.setFlags(QtCore.Qt.ItemIsEnabled | QtCore.Qt.ItemIsSelectable)
        item_iri.setBackground(QtGui.QBrush(QtGui.QColor(205, 50, 50, 50)))
        self.table.setItem(self.table.rowCount() - 1, 0, item_iri)

        prefixes = self.project.IRI_prefixes_nodes_dict[self.project.iri][0]
        item_prefixes = QtWidgets.QTableWidgetItem()
        item_prefixes.setText(str(prefixes))
        item_prefixes.setFlags(QtCore.Qt.ItemIsEnabled
                               | QtCore.Qt.ItemIsSelectable)
        item_prefixes.setBackground(QtGui.QBrush(QtGui.QColor(205, 50, 50,
                                                              50)))
        self.table.setItem(self.table.rowCount() - 1, 1, item_prefixes)

        if self.SHOW_NODES is True:
            nodes = self.project.IRI_prefixes_nodes_dict[self.project.iri][1]
            item_nodes = QtWidgets.QTableWidgetItem()
            nds_ids = set()
            for n in nodes:
                nds_ids.add(n.id_with_diag)
            item_nodes.setText(str(nds_ids))
            item_nodes.setFlags(QtCore.Qt.ItemIsEnabled
                                | QtCore.Qt.ItemIsSelectable)
            item_nodes.setBackground(
                QtGui.QBrush(QtGui.QColor(205, 50, 50, 50)))
            self.table.setItem(self.table.rowCount() - 1, 2, item_nodes)

            properties = self.project.IRI_prefixes_nodes_dict[
                self.project.iri][2]
            item_properties = QtWidgets.QTableWidgetItem()
            item_properties.setText(str(properties))
            item_properties.setFlags(QtCore.Qt.ItemIsEnabled
                                     | QtCore.Qt.ItemIsSelectable)
            self.table.setItem(self.table.rowCount() - 1, 3, item_properties)

        self.table.setRowCount(self.table.rowCount() + 1)

    #not used
    def update_table_row_containing_iri(self, iri_inp):

        for r in range(0, self.table.rowCount()):
            item = self.table.item(r, 0)
            if item.text() == iri_inp:
                # iri_inp in both table and dictionary
                if iri_inp in self.project.IRI_prefixes_nodes_dict.keys():
                    new_prefixes = self.project.IRI_prefixes_nodes_dict[
                        iri_inp][0]
                    self.table.item(r, 1).setText(str(new_prefixes))
                    if self.table.columnCount() == 3:
                        new_nodes = self.project.IRI_prefixes_nodes_dict[
                            iri_inp][1]
                        nds_ids = set()
                        for n in new_nodes:
                            nds_ids.add(n.id_with_diag)
                        self.table.item(r, 2).setText(str(nds_ids))
                # iri_inp in table and absent in dictionary
                else:
                    self.table.removeRow(r + 1)
                    self.table.setRowCount(self.table.rowCount() - 1)

        if iri_inp in self.project.IRI_prefixes_nodes_dict.keys():
            flag = False
            for r in range(0, self.table.rowCount()):
                item = self.table.item(r, 0)
                if item.text() == iri_inp:
                    flag = True
            if flag is False:
                # iri_inp in dictionary and absent in table
                self.table.setRowCount(self.table.rowCount() + 1)

                item_iri = QtWidgets.QTableWidgetItem()
                item_iri.setText(iri_inp)
                item_iri.setFlags(QtCore.Qt.ItemIsEnabled
                                  | QtCore.Qt.ItemIsSelectable)
                self.table.setItem(self.table.rowCount() - 1, 0, item_iri)

                prefixes = self.project.IRI_prefixes_nodes_dict[iri_inp][0]
                item_prefixes = QtWidgets.QTableWidgetItem()
                item_prefixes.setText(str(prefixes))
                item_prefixes.setFlags(QtCore.Qt.ItemIsEnabled
                                       | QtCore.Qt.ItemIsSelectable)
                self.table.setItem(self.table.rowCount() - 1, 1, item_prefixes)

                if self.SHOW_NODES is True:
                    nodes = self.project.IRI_prefixes_nodes_dict[iri_inp][1]
                    item_nodes = QtWidgets.QTableWidgetItem()
                    nds_ids = set()
                    for n in nodes:
                        nds_ids.add(n.id_with_diag)
                    item_nodes.setText(str(nds_ids))
                    item_nodes.setFlags(QtCore.Qt.ItemIsEnabled
                                        | QtCore.Qt.ItemIsSelectable)
                    self.table.setItem(self.table.rowCount() - 1, 2,
                                       item_nodes)
            else:
                # iri_inp in both table and dictionary (case already coverted above)
                pass

    @QtCore.pyqtSlot(str, str, str)
    def FillTableWithIRIPrefixNodesDictionaryKeysAndValues(
            self, iri_to_update, nodes_to_update, diag_name):

        #if (iri_to_update is None) and (nodes_to_update is None):
        # print('>>>  FillTableWithIRIPrefixNodesDictionaryKeysAndValues')
        # first delete all entries from the dictionary id present
        # add standard IRIs
        # add key value pairs from dict
        self.table.clear()
        self.table.setRowCount(1)

        if self.SHOW_NODES is True:
            self.table.setColumnCount(4)
        else:
            self.table.setColumnCount(2)

        header_iri = QtWidgets.QTableWidgetItem()
        header_iri.setText('IRI')
        header_iri.setFont(Font('Roboto', 15, bold=True))
        header_iri.setTextAlignment(QtCore.Qt.AlignCenter)
        header_iri.setBackground(QtGui.QBrush(QtGui.QColor(90, 80, 80, 200)))
        header_iri.setForeground(QtGui.QBrush(QtGui.QColor(255, 255, 255,
                                                           255)))
        self.table.setItem(self.table.rowCount() - 1, 0, header_iri)

        header_prefixes = QtWidgets.QTableWidgetItem()
        header_prefixes.setText('PREFIXES')
        header_prefixes.setFont(Font('Roboto', 15, bold=True))
        header_prefixes.setTextAlignment(QtCore.Qt.AlignCenter)
        header_prefixes.setBackground(
            QtGui.QBrush(QtGui.QColor(90, 80, 80, 200)))
        header_prefixes.setForeground(
            QtGui.QBrush(QtGui.QColor(255, 255, 255, 255)))
        self.table.setItem(self.table.rowCount() - 1, 1, header_prefixes)

        if self.SHOW_NODES is True:
            header_nodes = QtWidgets.QTableWidgetItem()
            header_nodes.setText('NODES')
            header_nodes.setFont(Font('Roboto', 15, bold=True))
            header_nodes.setTextAlignment(QtCore.Qt.AlignCenter)
            header_nodes.setBackground(
                QtGui.QBrush(QtGui.QColor(90, 80, 80, 200)))
            header_nodes.setForeground(
                QtGui.QBrush(QtGui.QColor(255, 255, 255, 255)))
            self.table.setItem(self.table.rowCount() - 1, 2, header_nodes)

            header_properties = QtWidgets.QTableWidgetItem()
            header_properties.setText('PROPERTIES')
            header_properties.setFont(Font('Roboto', 15, bold=True))
            header_properties.setTextAlignment(QtCore.Qt.AlignCenter)
            header_properties.setBackground(
                QtGui.QBrush(QtGui.QColor(90, 80, 80, 200)))
            header_properties.setForeground(
                QtGui.QBrush(QtGui.QColor(255, 255, 255, 255)))
            self.table.setItem(self.table.rowCount() - 1, 3, header_properties)

        self.table.setRowCount(self.table.rowCount() + 1)

        self.FillTableWithStandardData()

        for iri in sorted(self.project.IRI_prefixes_nodes_dict.keys()):

            if iri in OWLStandardIRIPrefixPairsDict.std_IRI_prefix_dict.keys():
                continue
            if iri == self.project.iri:
                continue

            item_iri = QtWidgets.QTableWidgetItem()
            item_iri.setText(iri)
            item_iri.setFlags(QtCore.Qt.ItemIsEnabled
                              | QtCore.Qt.ItemIsSelectable)
            self.table.setItem(self.table.rowCount() - 1, 0, item_iri)

            prefixes = self.project.IRI_prefixes_nodes_dict[iri][0]
            item_prefixes = QtWidgets.QTableWidgetItem()
            item_prefixes.setText(str(prefixes))
            item_prefixes.setFlags(QtCore.Qt.ItemIsEnabled
                                   | QtCore.Qt.ItemIsSelectable)
            self.table.setItem(self.table.rowCount() - 1, 1, item_prefixes)

            if self.SHOW_NODES is True:
                nodes = self.project.IRI_prefixes_nodes_dict[iri][1]
                item_nodes = QtWidgets.QTableWidgetItem()
                nds_ids = set()
                for n in nodes:
                    nds_ids.add(n.id_with_diag)
                item_nodes.setText(str(nds_ids))
                item_nodes.setFlags(QtCore.Qt.ItemIsEnabled
                                    | QtCore.Qt.ItemIsSelectable)
                self.table.setItem(self.table.rowCount() - 1, 2, item_nodes)

                properties = self.project.IRI_prefixes_nodes_dict[iri][2]
                item_properties = QtWidgets.QTableWidgetItem()
                item_properties.setText(str(properties))
                item_properties.setFlags(QtCore.Qt.ItemIsEnabled
                                         | QtCore.Qt.ItemIsSelectable)
                self.table.setItem(self.table.rowCount() - 1, 3,
                                   item_properties)

            self.table.setRowCount(self.table.rowCount() + 1)
        self.table.setRowCount(self.table.rowCount() - 1)
        """
            #print('>>>  FillTableWithIRIPrefixNodesDictionaryKeysAndValues      END')
        elif(iri_to_update is not None) and (nodes_to_update is None):
            self.update_table_row_containing_iri(iri_to_update)
        elif(iri_to_update is not None) and (nodes_to_update is not None):
            self.update_table_row_containing_iri(iri_to_update)
        """
        self.redraw()

    def hide_or_show_nodes(self):

        if self.SHOW_NODES is True:
            self.SHOW_NODES = False
        else:
            self.SHOW_NODES = True

        self.FillTableWithIRIPrefixNodesDictionaryKeysAndValues(
            None, None, None)

    def button_add(self):

        self.ADD_OR_REMOVE = 'add'
        self.process_entry_from_textboxes_for_button_add_or_remove()
        self.ADD_OR_REMOVE = None

    def button_remove(self):

        self.ADD_OR_REMOVE = 'remove'
        self.process_entry_from_textboxes_for_button_add_or_remove()
        self.ADD_OR_REMOVE = None

    def convert_prefixes_in_table_to_list(self, prefixes_str):

        if prefixes_str is None:
            return None

        prefixes_list = []

        if (prefixes_str[0] == '[') and (prefixes_str[len(prefixes_str) - 1]
                                         == ']'):
            prefixes_str = prefixes_str[1:len(prefixes_str) - 1]
        else:
            pass

        prefixes_str_split = prefixes_str.split(', ')

        for prefix_raw in prefixes_str_split:
            if (prefix_raw[0] == '\'') and (prefix_raw[len(prefix_raw) - 1]
                                            == '\''):
                prefix = prefix_raw[1:len(prefix_raw) - 1]
                if prefix != '':
                    prefixes_list.add(prefix)

        #print('return prefixes_list',prefixes_list)
        return prefixes_list

    def process_entry_from_textboxes_for_button_add_or_remove(self):

        self.ENTRY_ADD_OK_var = set()
        self.ENTRY_REMOVE_OK_var = set()
        self.ENTRY_IGNORE_var = set()

        prefixes = []
        prefixes_inp = self.prefix_input_box.text().strip()
        prefixes_raw = prefixes_inp.split(',')
        for p in prefixes_raw:
            if p.strip() != '':
                prefixes.append(p.strip())

        iri = self.iri_input_box.text().strip()

        self.iri_input_box.clear()
        self.prefix_input_box.clear()

        if iri == '':
            print('iri field is empty')
            self.entry_status.showMessage('iri field is empty', 10000)
            return

        Duplicate_IRI_prefixes_nodes_dict_1 = self.project.copy_IRI_prefixes_nodes_dictionaries(
            self.project.IRI_prefixes_nodes_dict, dict())

        Duplicate_IRI_prefixes_nodes_dict_2 = self.project.copy_IRI_prefixes_nodes_dictionaries(
            self.project.IRI_prefixes_nodes_dict, dict())

        process = False

        if len(prefixes) > 0:
            for prefix in prefixes:
                if self.ADD_OR_REMOVE == 'remove':
                    #self.project.removeIRIPrefixEntry(Duplicate_IRI_prefixes_nodes_dict_1, iri, prefix)
                    self.project.addORremoveIRIPrefixEntry(
                        Duplicate_IRI_prefixes_nodes_dict_1, iri, prefix,
                        'remove_entry')
                    if (False in self.ENTRY_REMOVE_OK_var) or (
                            True in self.ENTRY_IGNORE_var):
                        LOGGER.error(
                            'transaction was not executed correctly; problem with a prefix/IRI'
                        )
                        return
                    else:
                        process = True
                elif self.ADD_OR_REMOVE == 'add':
                    #self.project.addIRIPrefixEntry(Duplicate_IRI_prefixes_nodes_dict_1, iri, prefix)
                    self.project.addORremoveIRIPrefixEntry(
                        Duplicate_IRI_prefixes_nodes_dict_1, iri, prefix,
                        'add_entry')
                    if (False in self.ENTRY_ADD_OK_var) or (
                            True in self.ENTRY_IGNORE_var):
                        LOGGER.error(
                            'transaction was not executed correctly; problem with a prefix/IRI'
                        )
                        return
                    else:
                        process = True
                else:
                    pass
        else:
            if self.ADD_OR_REMOVE == 'remove':
                #self.project.removeIRIPrefixEntry(Duplicate_IRI_prefixes_nodes_dict_1, iri, None)
                self.project.addORremoveIRIPrefixEntry(
                    Duplicate_IRI_prefixes_nodes_dict_1, iri, None,
                    'remove_entry')
                if (False in self.ENTRY_REMOVE_OK_var) or (
                        True in self.ENTRY_IGNORE_var):
                    LOGGER.error(
                        'transaction was not executed correctly; problem with IRI'
                    )
                    return
                else:
                    process = True
            elif self.ADD_OR_REMOVE == 'add':
                #self.project.addIRIPrefixEntry(Duplicate_IRI_prefixes_nodes_dict_1, iri, None)
                self.project.addORremoveIRIPrefixEntry(
                    Duplicate_IRI_prefixes_nodes_dict_1, iri, None,
                    'add_entry')
                if (False in self.ENTRY_ADD_OK_var) or (
                        True in self.ENTRY_IGNORE_var):
                    LOGGER.error(
                        'transaction was not executed correctly; problem with IRI'
                    )
                    return
                else:
                    process = True
            else:
                pass

        if process is True:
            self.session.undostack.push(CommandProjetSetIRIPrefixesNodesDict(self.project,\
                                        Duplicate_IRI_prefixes_nodes_dict_2,Duplicate_IRI_prefixes_nodes_dict_1, [iri], None))

        self.ENTRY_ADD_OK_var = set()
        self.ENTRY_REMOVE_OK_var = set()
        self.ENTRY_IGNORE_var = set()

    def process_entry_from_textboxes_for_button_modify(self):

        self.ENTRY_MODIFY_OK_var = set()
        self.ENTRY_IGNORE_var = set()

        items_selected = []

        for r in range(0, self.table.rowCount()):
            for c in range(0, 2):
                item = self.table.item(r, c)
                if item.isSelected():
                    #print(item.text(), ' is selected')
                    items_selected.append(item)

        range_of_rows = set()

        for i in items_selected:
            range_of_rows.add(i.row())

        if len(range_of_rows) > 1:
            self.entry_status.showMessage(
                'please modify 1 IRI-Prefix pair at a time')
        elif len(range_of_rows) == 1:

            prefixes_input_box_set = set()
            prefixes_inp = self.prefix_input_box.text().strip()
            prefixes_raw = prefixes_inp.split(',')
            for p in prefixes_raw:
                if p.strip() != '':
                    prefixes_input_box_set.add(p.strip())

            iri_input_box = self.iri_input_box.text().strip()

            condition_IRI_item_selected_A = (items_selected[0].column() == 0)
            condition_prefixes_item_selected_A = (
                items_selected[0].column() == 1)

            if len(items_selected) == 2:
                condition_IRI_item_selected_B = (
                    items_selected[1].column() == 0)
                condition_prefixes_item_selected_B = (
                    items_selected[1].column() == 1)
            else:
                condition_IRI_item_selected_B = False
                condition_prefixes_item_selected_B = False

            condition_IRI_item_selected = (condition_IRI_item_selected_A
                                           or condition_IRI_item_selected_B)
            condition_prefixes_item_selected = (
                condition_prefixes_item_selected_A
                or condition_prefixes_item_selected_B)
            condition_iri_input_box_is_empty = (iri_input_box == '')
            condition_prefixes_input_box_is_empty = (
                len(prefixes_input_box_set) == 0)

            item_iri = None
            item_prefixes = None

            if condition_IRI_item_selected_A is True:
                item_iri = items_selected[0].text()
            else:  # condition_IRI_item_selected_A is False
                if condition_IRI_item_selected_B is True:
                    item_iri = items_selected[1].text()

            if condition_prefixes_item_selected_A is True:
                item_prefixes = items_selected[0].text()
            else:  # condition_prefixes_item_selected_A is False
                if condition_prefixes_item_selected_B is True:
                    item_prefixes = items_selected[1].text()

            item_prefixes_list = self.convert_prefixes_in_table_to_list(
                item_prefixes)
            """
            print('item_iri',item_iri)
            print('prefixes_input_box_set', item_prefixes_set)
            print('iri_input_box', iri_input_box)
            print('prefixes_input_box_set', prefixes_input_box_set)

            return
            """
            # caseX1  None->* | *-> None
            if (condition_iri_input_box_is_empty) and (
                    condition_prefixes_input_box_is_empty):
                self.entry_status.showMessage(
                    'Please enter IRI and/or prefix in the respective text fields to modify',
                    10000)
                return

            # caseX2  prefix(es) -> IRI' | IRI -> prefix(es)'
            if ((len(items_selected) == 1)):
                if (condition_prefixes_item_selected and not condition_iri_input_box_is_empty) or \
                        (condition_IRI_item_selected and not condition_prefixes_input_box_is_empty):
                    self.entry_status.showMessage(
                        'IRI cannot be modified to Prefixes or vice versa',
                        10000)
                    return

            Duplicate_IRI_prefixes_nodes_dict_1 = self.project.copy_IRI_prefixes_nodes_dictionaries(
                self.project.IRI_prefixes_nodes_dict, dict())
            Duplicate_IRI_prefixes_nodes_dict_2 = self.project.copy_IRI_prefixes_nodes_dictionaries(
                self.project.IRI_prefixes_nodes_dict, dict())

            process = False

            iris_to_be_updated = []

            # case1
            if (condition_IRI_item_selected is
                    True) and (condition_prefixes_item_selected is False):
                print('case1')
                if not condition_iri_input_box_is_empty:
                    if condition_prefixes_input_box_is_empty is True:
                        # Case1.1     IRI->IRI'         if iri==iri' no need for a transaction
                        if (item_iri == iri_input_box):
                            print('case1.1')
                            self.entry_status.showMessage(
                                'IRIs in selected cell and input box are the same. Nothing to change',
                                10000)
                            return

                        self.project.modifyIRIPrefixesEntry(
                            item_iri, None, iri_input_box, None,
                            Duplicate_IRI_prefixes_nodes_dict_1)
                        iris_to_be_updated.append(item_iri)
                        iris_to_be_updated.append(iri_input_box)

                        if (False in self.ENTRY_MODIFY_OK_var) or (
                                True in self.ENTRY_IGNORE_var):
                            LOGGER.error(
                                'transaction was not executed correctly; problem with a prefix/IRI'
                            )
                            return
                        else:
                            process = True
                    else:
                        # Case1.2     IRI->[IRI',prefix(es)']   IRI=IRI' | IRI!=IRI'
                        #$$$$$$
                        print('case1.2')

                        self.project.modifyIRIPrefixesEntry(
                            item_iri, None, iri_input_box,
                            prefixes_input_box_set,
                            Duplicate_IRI_prefixes_nodes_dict_1)
                        iris_to_be_updated.append(item_iri)
                        iris_to_be_updated.append(iri_input_box)

                        if (False in self.ENTRY_MODIFY_OK_var) or (
                                True in self.ENTRY_IGNORE_var):
                            LOGGER.error(
                                'transaction was not executed correctly; problem with a prefix/IRI'
                            )
                            return
                        else:
                            process = True

            # case2
            if (condition_prefixes_item_selected is
                    True) and (condition_IRI_item_selected is False):
                print('case2')
                if not condition_prefixes_input_box_is_empty:
                    if condition_iri_input_box_is_empty is True:
                        print('case2.1')
                        # case2.1     prefix(es)->prefix(es)'          if prefix(es)==prefix(es)' no need for a transaction
                        if (item_prefixes_list.issubset(prefixes_input_box_set)
                                and prefixes_input_box_set.issubset(
                                    item_prefixes_list)):
                            self.entry_status.showMessage(
                                'prefix(es) in selected cell and input box are the same. Nothing to change',
                                10000)
                            return

                        self.project.modifyIRIPrefixesEntry(
                            None, item_prefixes_list, None,
                            prefixes_input_box_set,
                            Duplicate_IRI_prefixes_nodes_dict_1)

                        for iri_key in Duplicate_IRI_prefixes_nodes_dict_1.keys(
                        ):
                            prefixes_for_iri_key = Duplicate_IRI_prefixes_nodes_dict_1[
                                iri_key][0]
                            C1 = prefixes_for_iri_key.issubset(
                                item_prefixes_list
                            ) and item_prefixes_list.issubset(
                                prefixes_for_iri_key)
                            C2 = prefixes_for_iri_key.issubset(
                                prefixes_input_box_set
                            ) and prefixes_input_box_set.issubset(
                                prefixes_for_iri_key)
                            if C1 or C2:
                                iris_to_be_updated.append(iri_key)

                        if (False in self.ENTRY_MODIFY_OK_var) or (
                                True in self.ENTRY_IGNORE_var):
                            LOGGER.error(
                                'transaction was not executed correctly; problem with a prefix/IRI'
                            )
                            return
                        else:
                            process = True
                    else:
                        print('case2.2')
                        # case2.2     prefix(es)->[IRI',prefix(es)']   prefix->[IRI',prefix(es)'] is an invalid transaction
                        self.entry_status.showMessage(
                            'prefix->[IRI\',prefix(es)\'] is an invalid transaction',
                            10000)
                        return

            # case3
            if (condition_prefixes_item_selected is
                    True) and (condition_IRI_item_selected is True):
                print('case3')
                if (condition_iri_input_box_is_empty is False) and (
                        condition_prefixes_input_box_is_empty is True):
                    # case3.1       [IRI,prefix(es)] -> [IRI']
                    print('case3.1')

                    self.project.modifyIRIPrefixesEntry(
                        item_iri, item_prefixes_list, iri_input_box, None,
                        Duplicate_IRI_prefixes_nodes_dict_1)
                    iris_to_be_updated.append(item_iri)
                    iris_to_be_updated.append(iri_input_box)

                    if (False in self.ENTRY_MODIFY_OK_var) or (
                            True in self.ENTRY_IGNORE_var):
                        LOGGER.error(
                            'transaction was not executed correctly; problem with a prefix/IRI'
                        )
                        return
                    else:
                        process = True
                elif (condition_iri_input_box_is_empty is True) and (
                        condition_prefixes_input_box_is_empty is False):
                    # case3.2       [IRI,prefix(es)] -> [prefix(es)']       if prefix==prefix' no need for a transaction
                    print('case3.2')
                    if (item_prefixes_list.issubset(prefixes_input_box_set)
                            and prefixes_input_box_set.issubset(
                                item_prefixes_list)):
                        self.entry_status.showMessage(
                            'prefix(es) in selected cell and input box are the same. Nothing to change',
                            10000)
                        return

                    self.project.modifyIRIPrefixesEntry(
                        item_iri, item_prefixes_list, None,
                        prefixes_input_box_set,
                        Duplicate_IRI_prefixes_nodes_dict_1)
                    iris_to_be_updated.append(item_iri)

                    for iri_key in Duplicate_IRI_prefixes_nodes_dict_1.keys():
                        prefixes_for_iri_key = Duplicate_IRI_prefixes_nodes_dict_1[
                            iri_key][0]
                        C2 = prefixes_for_iri_key.issubset(
                            prefixes_input_box_set
                        ) and prefixes_input_box_set.issubset(
                            prefixes_for_iri_key)
                        if C2:
                            iris_to_be_updated.append(iri_key)

                    if (False in self.ENTRY_MODIFY_OK_var) or (
                            True in self.ENTRY_IGNORE_var):
                        LOGGER.error(
                            'transaction was not executed correctly; problem with a prefix/IRI'
                        )
                        return
                    else:
                        process = True
                elif (condition_iri_input_box_is_empty is False) and (
                        condition_prefixes_input_box_is_empty is False):
                    # case3.3       [IRI,prefix(es)] -> [IRI',prefix(es)']   if prefix(es)==prefix(es)' and iri==iri' no need for a transaction
                    print('case3.3')
                    if (item_prefixes_list.issubset(prefixes_input_box_set) and
                            prefixes_input_box_set.issubset(item_prefixes_list)
                        ) and (item_iri == iri_input_box):
                        self.entry_status.showMessage(
                            'IRI and prefix(es) in selected cell and input box are the same. Nothing to change',
                            10000)
                        return

                    self.project.modifyIRIPrefixesEntry(
                        item_iri, item_prefixes_list, iri_input_box,
                        prefixes_input_box_set,
                        Duplicate_IRI_prefixes_nodes_dict_1)
                    iris_to_be_updated.append(item_iri)
                    iris_to_be_updated.append(iri_input_box)

                    if (False in self.ENTRY_MODIFY_OK_var) or (
                            True in self.ENTRY_IGNORE_var):
                        LOGGER.error(
                            'transaction was not executed correctly; problem with a prefix/IRI'
                        )
                        return
                    else:
                        process = True
                else:
                    # already covered in caseX1
                    pass

            print('before pushing to stack')

            #self.project.print_dictionary(Duplicate_IRI_prefixes_nodes_dict_1)

            print('before pushing to stack END')

            if process is True:
                self.session.undostack.push(CommandProjetSetIRIPrefixesNodesDict(self.project, \
                            Duplicate_IRI_prefixes_nodes_dict_2, Duplicate_IRI_prefixes_nodes_dict_1, iris_to_be_updated, None))

            self.iri_input_box.clear()
            self.prefix_input_box.clear()

        else:
            self.entry_status.showMessage(
                'please select the cells in the table to modify', 10000)

        self.ENTRY_MODIFY_OK_var = set()
        self.ENTRY_IGNORE_var = set()

    #############################################
    #   INTERFACE
    #################################

    def redraw(self):
        """
        Redraw the content of the widget.
        """
        if self.SHOW_NODES is True:
            self.table.setColumnCount(4)
        else:
            self.table.setColumnCount(2)

        width = self.width()
        scrollbar = self.verticalScrollBar()
        if scrollbar.isVisible():
            width -= scrollbar.width()
        #sizeHint = self.table.sizeHint()
        #height = sizeHint.height()
        height_of_other_objects = (self.dictionary_display_button.height() + self.entry_status.height()+\
                                  self.iri_input_box.height() + self.prefix_input_box.height())
        height = (self.height()) - (height_of_other_objects)
        self.table.setFixedWidth(width)
        #self.table.setFixedHeight(clamp(height, 0))
        self.table.setMinimumHeight(height)

        if self.SHOW_NODES is True:
            self.table.setColumnWidth(0, self.width() / 4)
            self.table.setColumnWidth(1, self.width() / 4)
            self.table.setColumnWidth(2, self.width() / 4)
            self.table.setColumnWidth(3, self.width() / 4)
        else:
            self.table.setColumnWidth(0, 2 * self.width() / 3)
            self.table.setColumnWidth(1, self.width() / 3)

        for r in range(0, self.table.rowCount()):
            self.table.resizeRowToContents(r)

    @QtCore.pyqtSlot()
    def run(self):
        """
        Set the current stacked widget.
        """
        self.FillTableWithIRIPrefixNodesDictionaryKeysAndValues(
            None, None, None)
        self.redraw()
class OntologyExplorerWidget(QtWidgets.QWidget):
    """
    This class implements the ontology explorer used to list ontology predicates.
    """
    sgnItemClicked = QtCore.pyqtSignal('QGraphicsItem')
    sgnItemDoubleClicked = QtCore.pyqtSignal('QGraphicsItem')
    sgnItemRightClicked = QtCore.pyqtSignal('QGraphicsItem')

    def __init__(self, plugin):
        """
        Initialize the ontology explorer widget.
        :type plugin: Session
        """
        super().__init__(plugin.session)

        self.plugin = plugin

        self.iconAttribute = QtGui.QIcon(':/icons/18/ic_treeview_attribute')
        self.iconConcept = QtGui.QIcon(':/icons/18/ic_treeview_concept')
        self.iconInstance = QtGui.QIcon(':/icons/18/ic_treeview_instance')
        self.iconRole = QtGui.QIcon(':/icons/18/ic_treeview_role')
        self.iconValue = QtGui.QIcon(':/icons/18/ic_treeview_value')

        self.search = StringField(self)
        self.search.setAcceptDrops(False)
        self.search.setClearButtonEnabled(True)
        self.search.setPlaceholderText('Search...')
        self.search.setFixedHeight(30)
        self.model = QtGui.QStandardItemModel(self)
        self.proxy = QtCore.QSortFilterProxyModel(self)
        self.proxy.setDynamicSortFilter(False)
        self.proxy.setFilterCaseSensitivity(QtCore.Qt.CaseInsensitive)
        self.proxy.setSortCaseSensitivity(QtCore.Qt.CaseSensitive)
        self.proxy.setSourceModel(self.model)
        self.ontoview = OntologyExplorerView(self)
        self.ontoview.setModel(self.proxy)
        self.mainLayout = QtWidgets.QVBoxLayout(self)
        self.mainLayout.setContentsMargins(0, 0, 0, 0)
        self.mainLayout.addWidget(self.search)
        self.mainLayout.addWidget(self.ontoview)

        self.setContentsMargins(0, 0, 0, 0)
        self.setMinimumWidth(216)

        self.setStyleSheet("""
            QLineEdit,
            QLineEdit:editable,
            QLineEdit:hover,
            QLineEdit:pressed,
            QLineEdit:focus {
              border: none;
              border-radius: 0;
              background: #FFFFFF;
              color: #000000;
              padding: 4px 4px 4px 4px;
            }
        """)

        header = self.ontoview.header()
        header.setStretchLastSection(False)
        header.setSectionResizeMode(QtWidgets.QHeaderView.ResizeToContents)

        connect(self.ontoview.doubleClicked, self.onItemDoubleClicked)
        connect(self.ontoview.pressed, self.onItemPressed)
        connect(self.search.textChanged, self.doFilterItem)
        connect(self.sgnItemDoubleClicked, self.session.doFocusItem)
        connect(self.sgnItemRightClicked, self.session.doFocusItem)

    #############################################
    #   PROPERTIES
    #################################

    @property
    def project(self):
        """
        Returns the reference to the active project.
        :rtype: Session
        """
        return self.session.project

    @property
    def session(self):
        """
        Returns the reference to the active session.
        :rtype: Session
        """
        return self.plugin.parent()

    #############################################
    #   EVENTS
    #################################

    def paintEvent(self, paintEvent):
        """
        This is needed for the widget to pick the stylesheet.
        :type paintEvent: QPaintEvent
        """
        option = QtWidgets.QStyleOption()
        option.initFrom(self)
        painter = QtGui.QPainter(self)
        style = self.style()
        style.drawPrimitive(QtWidgets.QStyle.PE_Widget, option, painter, self)

    #############################################
    #   SLOTS
    #################################

    @QtCore.pyqtSlot('QGraphicsScene', 'QGraphicsItem')
    def doAddNode(self, diagram, node):
        """
        Add a node in the tree view.
        :type diagram: QGraphicsScene
        :type node: AbstractItem
        """
        if node.type() in {Item.ConceptNode, Item.RoleNode, Item.AttributeNode, Item.IndividualNode}:
            parent = self.parentFor(node)
            if not parent:
                parent = QtGui.QStandardItem(self.parentKey(node))
                parent.setIcon(self.iconFor(node))
                self.model.appendRow(parent)
                self.proxy.sort(0, QtCore.Qt.AscendingOrder)
            child = QtGui.QStandardItem(self.childKey(diagram, node))
            child.setData(node)
            parent.appendRow(child)
            self.proxy.sort(0, QtCore.Qt.AscendingOrder)

    @QtCore.pyqtSlot(str)
    def doFilterItem(self, key):
        """
        Executed when the search box is filled with data.
        :type key: str
        """
        self.proxy.setFilterFixedString(key)
        self.proxy.sort(QtCore.Qt.AscendingOrder)

    @QtCore.pyqtSlot('QGraphicsScene', 'QGraphicsItem')
    def doRemoveNode(self, diagram, node):
        """
        Remove a node from the tree view.
        :type diagram: QGraphicsScene
        :type node: AbstractItem
        """
        if node.type() in {Item.ConceptNode, Item.RoleNode, Item.AttributeNode, Item.IndividualNode}:
            parent = self.parentFor(node)
            if parent:
                child = self.childFor(parent, diagram, node)
                if child:
                    parent.removeRow(child.index().row())
                if not parent.rowCount():
                    self.model.removeRow(parent.index().row())

    @QtCore.pyqtSlot('QModelIndex')
    def onItemDoubleClicked(self, index):
        """
        Executed when an item in the treeview is double clicked.
        :type index: QModelIndex
        """
        # noinspection PyArgumentList
        if QtWidgets.QApplication.mouseButtons() & QtCore.Qt.LeftButton:
            item = self.model.itemFromIndex(self.proxy.mapToSource(index))
            if item and item.data():
                self.sgnItemDoubleClicked.emit(item.data())

    @QtCore.pyqtSlot('QModelIndex')
    def onItemPressed(self, index):
        """
        Executed when an item in the treeview is clicked.
        :type index: QModelIndex
        """
        # noinspection PyArgumentList
        if QtWidgets.QApplication.mouseButtons() & QtCore.Qt.LeftButton:
            item = self.model.itemFromIndex(self.proxy.mapToSource(index))
            if item and item.data():
                self.sgnItemClicked.emit(item.data())

    #############################################
    #   INTERFACE
    #################################

    def childFor(self, parent, diagram, node):
        """
        Search the item representing this node among parent children.
        :type parent: QtGui.QStandardItem
        :type diagram: Diagram
        :type node: AbstractNode
        """
        key = self.childKey(diagram, node)
        for i in range(parent.rowCount()):
            child = parent.child(i)
            if child.text() == key:
                return child
        return None

    @staticmethod
    def childKey(diagram, node):
        """
        Returns the child key (text) used to place the given node in the treeview.
        :type diagram: Diagram
        :type node: AbstractNode
        :rtype: str
        """
        predicate = node.text().replace('\n', '')
        diagram = rstrip(diagram.name, File.Graphol.extension)
        return '{0} ({1} - {2})'.format(predicate, diagram, node.id)

    def iconFor(self, node):
        """
        Returns the icon for the given node.
        :type node:
        """
        if node.type() is Item.AttributeNode:
            return self.iconAttribute
        if node.type() is Item.ConceptNode:
            return self.iconConcept
        if node.type() is Item.IndividualNode:
            if node.identity() is Identity.Individual:
                return self.iconInstance
            if node.identity() is Identity.Value:
                return self.iconValue
        if node.type() is Item.RoleNode:
            return self.iconRole

    def parentFor(self, node):
        """
        Search the parent element of the given node.
        :type node: AbstractNode
        :rtype: QtGui.QStandardItem
        """
        for i in self.model.findItems(self.parentKey(node), QtCore.Qt.MatchExactly):
            n = i.child(0).data()
            if node.type() is n.type():
                return i
        return None

    @staticmethod
    def parentKey(node):
        """
        Returns the parent key (text) used to place the given node in the treeview.
        :type node: AbstractNode
        :rtype: str
        """
        return node.text().replace('\n', '')

    def sizeHint(self):
        """
        Returns the recommended size for this widget.
        :rtype: QtCore.QSize
        """
        return QtCore.QSize(216, 266)
示例#9
0
class UnsatisfiableEntityExplorerWidget(QtWidgets.QWidget):
    """
    This class implements the UnsatisfiableEntitiesExplorer
    """
    sgnItemClicked = QtCore.pyqtSignal('QGraphicsItem')
    sgnItemDoubleClicked = QtCore.pyqtSignal('QGraphicsItem')
    sgnItemRightClicked = QtCore.pyqtSignal('QGraphicsItem')

    sgnStringClicked = QtCore.pyqtSignal('QStandardItem')
    sgnStringDoubleClicked = QtCore.pyqtSignal('QStandardItem')
    sgnStringRightClicked = QtCore.pyqtSignal('QStandardItem')

    sgnListClicked = QtCore.pyqtSignal('QStandardItem')
    sgnListDoubleClicked = QtCore.pyqtSignal('QStandardItem')
    sgnListRightClicked = QtCore.pyqtSignal('QStandardItem')

    def __init__(self, plugin):
        """
        Initialize the UnsatisfiableEntitiesExplorer widget.
        :type plugin: Session
        """
        super().__init__(plugin.session)

        self.plugin = plugin

        self.iconAttribute = QtGui.QIcon(':/icons/18/ic_treeview_attribute')
        self.iconConcept = QtGui.QIcon(':/icons/18/ic_treeview_concept')
        self.iconInstance = QtGui.QIcon(':/icons/18/ic_treeview_instance')
        self.iconRole = QtGui.QIcon(':/icons/18/ic_treeview_role')
        self.iconValue = QtGui.QIcon(':/icons/18/ic_treeview_value')

        self.search = StringField(self)
        self.search.setAcceptDrops(False)
        self.search.setClearButtonEnabled(True)
        self.search.setPlaceholderText('Search...')
        self.search.setFixedHeight(30)
        self.model = QtGui.QStandardItemModel(self)
        self.proxy = QtCore.QSortFilterProxyModel(self)
        self.proxy.setDynamicSortFilter(False)
        self.proxy.setFilterCaseSensitivity(QtCore.Qt.CaseInsensitive)
        self.proxy.setSortCaseSensitivity(QtCore.Qt.CaseSensitive)
        self.proxy.setSourceModel(self.model)
        self.ontoview = UnsatisfiableEntityExplorerView(self)
        self.ontoview.setModel(self.proxy)
        self.mainLayout = QtWidgets.QVBoxLayout(self)
        self.mainLayout.setContentsMargins(0, 0, 0, 0)
        self.mainLayout.addWidget(self.search)
        self.mainLayout.addWidget(self.ontoview)

        self.setContentsMargins(0, 0, 0, 0)
        self.setMinimumWidth(216)

        self.setStyleSheet("""
            QLineEdit,
            QLineEdit:editable,
            QLineEdit:hover,
            QLineEdit:pressed,
            QLineEdit:focus {
              border: none;
              border-radius: 0;
              background: #FFFFFF;
              color: #000000;
              padding: 4px 4px 4px 4px;
            }
        """)

        header = self.ontoview.header()
        header.setStretchLastSection(False)
        header.setSectionResizeMode(QtWidgets.QHeaderView.ResizeToContents)

        connect(self.ontoview.doubleClicked, self.onItemDoubleClicked)
        connect(self.ontoview.pressed, self.onItemPressed)
        connect(self.search.textChanged, self.doFilterItem)
        connect(self.sgnItemDoubleClicked, self.session.doFocusItem)
        connect(self.sgnItemRightClicked, self.session.doFocusItem)

        connect(self.sgnStringClicked, self.start_explanation_explorer)
        connect(self.sgnStringDoubleClicked, self.start_explanation_explorer)

        connect(self.sgnListClicked, self.start_explanation_explorer)
        connect(self.sgnListDoubleClicked, self.start_explanation_explorer)

        self.brush_orange = QtGui.QBrush(QtGui.QColor(255, 165, 0, 160))

    #############################################
    #   PROPERTIES
    #################################

    @property
    def project(self):
        """
        Returns the reference to the active project.
        :rtype: Session
        """
        return self.session.project

    @property
    def session(self):
        """
        Returns the reference to the active session.
        :rtype: Session
        """
        return self.plugin.parent()

    #############################################
    #   EVENTS
    #################################

    def paintEvent(self, paintEvent):
        """
        This is needed for the widget to pick the stylesheet.
        :type paintEvent: QPaintEvent
        """
        option = QtWidgets.QStyleOption()
        option.initFrom(self)
        painter = QtGui.QPainter(self)
        style = self.style()
        style.drawPrimitive(QtWidgets.QStyle.PE_Widget, option, painter, self)

    #############################################
    #   SLOTS
    #################################
    @QtCore.pyqtSlot('QGraphicsItem', 'QStandardItem')
    def doAddExplanation_old(self, node, explanation):

        if explanation is not None:
            exp_to_add = QtGui.QStandardItem(explanation)
            exp_to_add.setData(explanation)
            parent = self.parentFor(node)
            parent.appendRow(exp_to_add)

    @QtCore.pyqtSlot('QGraphicsItem', list)
    def doAddExplanation(self, node, explanation):

        if explanation is not None and len(explanation) > 0:
            exp_to_add = QtGui.QStandardItem()
            exp_to_add.setText(
                '<Explanation(s)> \n**(click to open Explanation Explorer)')

            font = QtGui.QFont()
            font.setBold(True)
            font.setItalic(True)
            font.setUnderline(True)

            exp_to_add.setFont(font)

            exp_to_add.setData(explanation)
            parent = self.parentFor(node)
            parent.appendRow(exp_to_add)

    @QtCore.pyqtSlot('QGraphicsScene', 'QGraphicsItem')
    def doAddNode(self, diagram, node):
        """
        Add a node in the tree view.
        :type diagram: QGraphicsScene
        :type node: AbstractItem
        """
        #print('doAddNode    >>>     node',node)

        owl_term_for_node = self.project.getOWLtermfornode(node)

        #print(owl_term_for_node,' - ',node.id_with_diag)
        #print(self.project.nodes_of_unsatisfiable_entities)

        if (node not in self.project.nodes_of_unsatisfiable_entities) and (
            (owl_term_for_node is not None) and
            (owl_term_for_node
             in self.project.nodes_of_unsatisfiable_entities)):
            self.project.nodes_of_unsatisfiable_entities.append(node)

        if (node in self.project.nodes_of_unsatisfiable_entities) or (
            (owl_term_for_node is not None) and
            (owl_term_for_node
             in self.project.nodes_of_unsatisfiable_entities)):
            #if node.type() in {Item.ConceptNode, Item.RoleNode, Item.AttributeNode, Item.IndividualNode}:

            parent = self.parentFor(node)
            if not parent:
                parent = QtGui.QStandardItem(self.parentKey(node))
                parent.setIcon(self.iconFor(node))
                parent.setData(node)
                self.model.appendRow(parent)
                self.proxy.sort(0, QtCore.Qt.AscendingOrder)
            child = QtGui.QStandardItem(self.childKey(diagram, node))
            child.setData(node)
            parent.appendRow(child)
            self.proxy.sort(0, QtCore.Qt.AscendingOrder)

            node.selection.setBrush(self.brush_orange)
            #node.updateNode(valid=False)
            # FORCE CACHE REGENERATION
            node.setCacheMode(node.NoCache)
            node.setCacheMode(node.DeviceCoordinateCache)

            # SCHEDULE REPAINT
            node.update(node.boundingRect())

            node.diagram.sgnUpdated.emit()
        else:
            #print('node not in self.project.nodes_of_unsatisfiable_entities:',node)
            pass

    def start_explanation_explorer(self, item=None):

        parent = item.parent()

        self.session.pmanager.dispose_and_remove_plugin_from_session(
            plugin_id='Explanation_explorer')
        #self.project.uc_as_input_for_explanation_explorer = parent.text()
        self.project.uc_as_input_for_explanation_explorer = str(parent.data())
        #print('self.project.uc_as_input_for_explanation_explorer',self.project.uc_as_input_for_explanation_explorer)
        self.session.pmanager.create_add_and_start_plugin(
            'Explanation_explorer')

    @QtCore.pyqtSlot(str)
    def doFilterItem(self, key):
        """
        Executed when the search box is filled with data.
        :type key: str
        """
        self.proxy.setFilterFixedString(key)
        self.proxy.sort(QtCore.Qt.AscendingOrder)

    @QtCore.pyqtSlot('QGraphicsScene', 'QGraphicsItem')
    def doRemoveNode(self, diagram, node):
        """
        Remove a node from the tree view.
        :type diagram: QGraphicsScene
        :type node: AbstractItem
        """
        #print('doRemoveNode >>>')
        #print('node',node)
        if node.type() in {
                Item.ConceptNode, Item.RoleNode, Item.AttributeNode,
                Item.IndividualNode
        }:
            #if (('AttributeNode' in str(type(node))) or ('ConceptNode' in str(type(node))) or ('IndividualNode' in str(type(node))) or ('RoleNode' in str(type(node)))):
            if node in self.project.nodes_of_unsatisfiable_entities:
                self.project.nodes_of_unsatisfiable_entities.remove(node)
            parent = self.parentFor(node)
            if parent:
                child = self.childFor(parent, diagram, node)
                if child:
                    parent.removeRow(child.index().row())
                if not parent.rowCount():
                    self.model.removeRow(parent.index().row())

    @QtCore.pyqtSlot('QModelIndex')
    def onItemDoubleClicked(self, index):
        """
        Executed when an item in the treeview is double clicked.
        :type index: QModelIndex
        """
        # noinspection PyArgumentList
        if QtWidgets.QApplication.mouseButtons() & QtCore.Qt.LeftButton:
            item = self.model.itemFromIndex(self.proxy.mapToSource(index))

            if item and item.data():

                if (str(type(item.data())) == '<class \'str\'>') or (str(
                        type(item.data())) == 'str'):
                    self.sgnStringDoubleClicked.emit(item)
                elif (str(type(item.data())) == '<class \'list\'>') or (str(
                        type(item.data())) == 'list'):
                    self.sgnListDoubleClicked.emit(item)
                else:
                    self.sgnItemDoubleClicked.emit(item.data())

    @QtCore.pyqtSlot('QModelIndex')
    def onItemPressed(self, index):
        """
        Executed when an item in the treeview is clicked.
        :type index: QModelIndex
        """
        # noinspection PyArgumentList
        if QtWidgets.QApplication.mouseButtons() & QtCore.Qt.LeftButton:
            item = self.model.itemFromIndex(self.proxy.mapToSource(index))

            if item and item.data():

                if (str(type(item.data())) == '<class \'str\'>') or (str(
                        type(item.data())) == 'str'):
                    self.sgnStringClicked.emit(item)
                elif (str(type(item.data())) == '<class \'list\'>') or (str(
                        type(item.data())) == 'list'):
                    self.sgnListClicked.emit(item)
                else:
                    self.sgnItemClicked.emit(item.data())

    #############################################
    #   INTERFACE
    #################################

    def childFor(self, parent, diagram, node):
        """
        Search the item representing this node among parent children.
        :type parent: QtGui.QStandardItem
        :type diagram: Diagram
        :type node: AbstractNode
        """
        key = self.childKey(diagram, node)
        for i in range(parent.rowCount()):
            child = parent.child(i)
            if child.text() == key:
                return child
        return None

    @staticmethod
    def childKey(diagram, node):
        """
        Returns the child key (text) used to place the given node in the treeview.
        :type diagram: Diagram
        :type node: AbstractNode
        :rtype: str
        """
        predicate = node.text().replace('\n', '')
        diagram = rstrip(diagram.name, File.Graphol.extension)
        return '{0} ({1} - {2})'.format(predicate, diagram, node.id)

    def iconFor(self, node):
        """
        Returns the icon for the given node.
        :type node:
        """
        if node.type() is Item.AttributeNode:
            return self.iconAttribute
        if node.type() is Item.ConceptNode:
            return self.iconConcept
        if node.type() is Item.IndividualNode:
            if node.identity() is Identity.Individual:
                return self.iconInstance
            if node.identity() is Identity.Value:
                return self.iconValue
        if node.type() is Item.RoleNode:
            return self.iconRole

    def parentFor(self, node):
        """
        Search the parent element of the given node.
        :type node: AbstractNode
        :rtype: QtGui.QStandardItem
        """
        #print('parentFor(self, node)')
        #print('node',node)
        for i in self.model.findItems(self.parentKey(node),
                                      QtCore.Qt.MatchExactly):
            #print('i',i)
            #n = i.child(0).data()
            if (i.text() == node.text()) or (i.text() == node.text().replace(
                    '\n', '')):
                return i
            #if str(type(n)) != '<class \'list\'>':
            #if node.type() is n.type():
            #return i
        return None

    @staticmethod
    def parentKey(node):
        """
        Returns the parent key (text) used to place the given node in the treeview.
        :type node: AbstractNode
        :rtype: str
        """
        return node.text().replace('\n', '')

    def sizeHint(self):
        """
        Returns the recommended size for this widget.
        :rtype: QtCore.QSize
        """
        return QtCore.QSize(216, 266)
示例#10
0
class OntologyExplorerWidget(QtWidgets.QWidget):
    """
    This class implements the ontology explorer used to list ontology predicates.
    """
    sgnItemActivated = QtCore.pyqtSignal('QGraphicsItem')
    sgnItemClicked = QtCore.pyqtSignal('QGraphicsItem')
    sgnItemDoubleClicked = QtCore.pyqtSignal('QGraphicsItem')
    sgnItemRightClicked = QtCore.pyqtSignal('QGraphicsItem')

    def __init__(self, plugin):
        """
        Initialize the ontology explorer widget.
        :type plugin: Session
        """
        super().__init__(plugin.session)

        self.plugin = plugin
        self.items = [
            Item.ConceptNode, Item.RoleNode, Item.AttributeNode,
            Item.IndividualNode
        ]
        self.status = [Status.DEFAULT, Status.DRAFT, Status.FINAL]

        self.iconAttribute = QtGui.QIcon(':/icons/18/ic_treeview_attribute')
        self.iconConcept = QtGui.QIcon(':/icons/18/ic_treeview_concept')
        self.iconInstance = QtGui.QIcon(':/icons/18/ic_treeview_instance')
        self.iconRole = QtGui.QIcon(':/icons/18/ic_treeview_role')
        self.iconValue = QtGui.QIcon(':/icons/18/ic_treeview_value')

        self.searchShortcut = QtWidgets.QShortcut(QtGui.QKeySequence('Ctrl+f'),
                                                  self.session)
        self.search = StringField(self)
        self.search.setAcceptDrops(False)
        self.search.setClearButtonEnabled(True)
        self.search.setPlaceholderText('Search...')
        self.search.setToolTip('Search ({})'.format(
            self.searchShortcut.key().toString(QtGui.QKeySequence.NativeText)))
        self.search.setFixedHeight(30)
        self.model = QtGui.QStandardItemModel(self)
        self.proxy = OntologyExplorerFilterProxyModel(self)
        self.proxy.setDynamicSortFilter(False)
        self.proxy.setFilterCaseSensitivity(QtCore.Qt.CaseInsensitive)
        self.proxy.setSortCaseSensitivity(QtCore.Qt.CaseSensitive)
        self.proxy.setSourceModel(self.model)
        self.ontoview = OntologyExplorerView(self)
        self.ontoview.setModel(self.proxy)
        self.mainLayout = QtWidgets.QVBoxLayout(self)
        self.mainLayout.setContentsMargins(0, 0, 0, 0)
        self.mainLayout.addWidget(self.search)
        self.mainLayout.addWidget(self.ontoview)
        self.setTabOrder(self.search, self.ontoview)
        self.setContentsMargins(0, 0, 0, 0)
        self.setMinimumWidth(216)

        self.setStyleSheet("""
            QLineEdit,
            QLineEdit:editable,
            QLineEdit:hover,
            QLineEdit:pressed,
            QLineEdit:focus {
              border: none;
              border-radius: 0;
              background: #FFFFFF;
              color: #000000;
              padding: 4px 4px 4px 4px;
            }
        """)

        header = self.ontoview.header()
        header.setStretchLastSection(False)
        header.setSectionResizeMode(QtWidgets.QHeaderView.ResizeToContents)

        connect(self.ontoview.activated, self.onItemActivated)
        connect(self.ontoview.doubleClicked, self.onItemDoubleClicked)
        connect(self.ontoview.pressed, self.onItemPressed)
        connect(self.search.textChanged, self.doFilterItem)
        connect(self.search.returnPressed, self.onReturnPressed)
        connect(self.searchShortcut.activated, self.doFocusSearch)
        connect(self.sgnItemActivated, self.session.doFocusItem)
        connect(self.sgnItemDoubleClicked, self.session.doFocusItem)
        connect(self.sgnItemRightClicked, self.session.doFocusItem)

    #############################################
    #   PROPERTIES
    #################################

    @property
    def project(self):
        """
        Returns the reference to the active project.
        :rtype: Session
        """
        return self.session.project

    @property
    def session(self):
        """
        Returns the reference to the active session.
        :rtype: Session
        """
        return self.plugin.parent()

    #############################################
    #   EVENTS
    #################################

    def paintEvent(self, paintEvent):
        """
        This is needed for the widget to pick the stylesheet.
        :type paintEvent: QPaintEvent
        """
        option = QtWidgets.QStyleOption()
        option.initFrom(self)
        painter = QtGui.QPainter(self)
        style = self.style()
        style.drawPrimitive(QtWidgets.QStyle.PE_Widget, option, painter, self)

    #############################################
    #   SLOTS
    #################################

    @QtCore.pyqtSlot('QGraphicsScene', 'QGraphicsItem')
    def doAddNode(self, diagram, node):
        """
        Add a node in the tree view.
        :type diagram: QGraphicsScene
        :type node: AbstractItem
        """
        if node.type() in self.items:
            parent = self.parentFor(node)
            if not parent:
                parent = QtGui.QStandardItem(self.parentKey(node))
                parent.setIcon(self.iconFor(node))
                self.model.appendRow(parent)
            child = QtGui.QStandardItem(self.childKey(diagram, node))
            child.setData(node)
            # CHECK FOR DUPLICATE NODES
            children = [parent.child(i) for i in range(parent.rowCount())]
            if not any([child.text() == c.text() for c in children]):
                parent.appendRow(child)
            # APPLY FILTERS AND SORT
            if self.sender() != self.plugin:
                self.proxy.invalidateFilter()
                self.proxy.sort(0, QtCore.Qt.AscendingOrder)

    @QtCore.pyqtSlot(str)
    def doFilterItem(self, key):
        """
        Executed when the search box is filled with data.
        :type key: str
        """
        self.proxy.setFilterFixedString(key)
        self.proxy.sort(QtCore.Qt.AscendingOrder)

    @QtCore.pyqtSlot()
    def doFocusSearch(self):
        """
        Focus the search bar.
        """
        # RAISE THE ENTIRE WIDGET TREE IF IT IS NOT VISIBLE
        if not self.isVisible():
            widget = self
            while widget != self.session:
                widget.show()
                widget.raise_()
                widget = widget.parent()
        self.search.setFocus()
        self.search.selectAll()

    @QtCore.pyqtSlot('QGraphicsScene', 'QGraphicsItem')
    def doRemoveNode(self, diagram, node):
        """
        Remove a node from the tree view.
        :type diagram: QGraphicsScene
        :type node: AbstractItem
        """
        if node.type() in self.items:
            parent = self.parentFor(node)
            if parent:
                child = self.childFor(parent, diagram, node)
                if child:
                    parent.removeRow(child.index().row())
                if not parent.rowCount():
                    self.model.removeRow(parent.index().row())

    @QtCore.pyqtSlot('QModelIndex')
    def onItemActivated(self, index):
        """
        Executed when an item in the treeview is activated (e.g. by pressing Return or Enter key).
        :type index: QModelIndex
        """
        # noinspection PyArgumentList
        if QtWidgets.QApplication.mouseButtons() == QtCore.Qt.NoButton:
            item = self.model.itemFromIndex(self.proxy.mapToSource(index))
            if item and item.data():
                self.sgnItemActivated.emit(item.data())
                # KEEP FOCUS ON THE TREE VIEW UNLESS SHIFT IS PRESSED
                if QtWidgets.QApplication.queryKeyboardModifiers(
                ) & QtCore.Qt.SHIFT:
                    return
                self.ontoview.setFocus()
            elif item:
                # EXPAND/COLLAPSE PARENT ITEM
                if self.ontoview.isExpanded(index):
                    self.ontoview.collapse(index)
                else:
                    self.ontoview.expand(index)

    @QtCore.pyqtSlot('QModelIndex')
    def onItemDoubleClicked(self, index):
        """
        Executed when an item in the treeview is double clicked.
        :type index: QModelIndex
        """
        # noinspection PyArgumentList
        if QtWidgets.QApplication.mouseButtons() & QtCore.Qt.LeftButton:
            item = self.model.itemFromIndex(self.proxy.mapToSource(index))
            if item and item.data():
                self.sgnItemDoubleClicked.emit(item.data())

    @QtCore.pyqtSlot('QModelIndex')
    def onItemPressed(self, index):
        """
        Executed when an item in the treeview is clicked.
        :type index: QModelIndex
        """
        # noinspection PyArgumentList
        if QtWidgets.QApplication.mouseButtons() & QtCore.Qt.LeftButton:
            item = self.model.itemFromIndex(self.proxy.mapToSource(index))
            if item and item.data():
                self.sgnItemClicked.emit(item.data())

    @QtCore.pyqtSlot(bool)
    def onMenuButtonClicked(self, checked=False):
        """
        Executed when a button in the widget menu is clicked.
        """
        # UPDATE THE PALETTE LAYOUT
        data = self.sender().data()
        elems = self.proxy.items if isinstance(data,
                                               Item) else self.proxy.status
        if checked:
            elems.add(data)
        else:
            elems.discard(data)
        self.proxy.invalidateFilter()
        self.proxy.sort(0, QtCore.Qt.AscendingOrder)

    @QtCore.pyqtSlot(Item, str)
    def onMetaUpdated(self, item, name):
        """
        Executed when metadata of the predicate for the given item/name combination is updated
        :type item: Item
        :type name: str
        """
        self.proxy.invalidateFilter()
        self.proxy.sort(0, QtCore.Qt.AscendingOrder)

    @QtCore.pyqtSlot()
    def onReturnPressed(self):
        """
        Executed when the Return or Enter key is pressed in the search field.
        """
        self.focusNextChild()

    #############################################
    #   INTERFACE
    #################################

    def childFor(self, parent, diagram, node):
        """
        Search the item representing this node among parent children.
        :type parent: QtGui.QStandardItem
        :type diagram: Diagram
        :type node: AbstractNode
        """
        key = self.childKey(diagram, node)
        for i in range(parent.rowCount()):
            child = parent.child(i)
            if child.text() == key:
                return child
        return None

    @staticmethod
    def childKey(diagram, node):
        """
        Returns the child key (text) used to place the given node in the treeview.
        :type diagram: Diagram
        :type node: AbstractNode
        :rtype: str
        """
        predicate = node.text().replace('\n', '')
        diagram = rstrip(diagram.name, File.Graphol.extension)
        return '{0} ({1} - {2})'.format(predicate, diagram, node.id)

    def iconFor(self, node):
        """
        Returns the icon for the given node.
        :type node:
        """
        if node.type() is Item.AttributeNode:
            return self.iconAttribute
        if node.type() is Item.ConceptNode:
            return self.iconConcept
        if node.type() is Item.IndividualNode:
            if node.identity() is Identity.Individual:
                return self.iconInstance
            if node.identity() is Identity.Value:
                return self.iconValue
        if node.type() is Item.RoleNode:
            return self.iconRole

    def parentFor(self, node):
        """
        Search the parent element of the given node.
        :type node: AbstractNode
        :rtype: QtGui.QStandardItem
        """
        for i in self.model.findItems(self.parentKey(node),
                                      QtCore.Qt.MatchExactly):
            n = i.child(0).data()
            if node.type() is n.type():
                return i
        return None

    @staticmethod
    def parentKey(node):
        """
        Returns the parent key (text) used to place the given node in the treeview.
        :type node: AbstractNode
        :rtype: str
        """
        return node.text().replace('\n', '')

    def sizeHint(self):
        """
        Returns the recommended size for this widget.
        :rtype: QtCore.QSize
        """
        return QtCore.QSize(216, 266)