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)
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)
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)
class AbstractDiagramForm(QtWidgets.QDialog): """ Base class for diagram dialogs. """ __metaclass__ = ABCMeta def __init__(self, project, parent=None): """ Initialize the dialog. :type project: Project :type parent: QtWidgets.QWidget """ super().__init__(parent) self.project = project ############################################# # FORM AREA ################################# self.nameField = StringField(self) self.nameField.setMinimumWidth(400) self.nameField.setMaxLength(64) self.nameField.setPlaceholderText('Name...') connect(self.nameField.textChanged, self.onNameFieldChanged) self.warnLabel = QtWidgets.QLabel(self) self.warnLabel.setContentsMargins(0, 0, 0, 0) self.warnLabel.setProperty('class', 'invalid') self.warnLabel.setVisible(False) ############################################# # CONFIRMATION AREA ################################# self.confirmationBox = QtWidgets.QDialogButtonBox( QtCore.Qt.Horizontal, self) self.confirmationBox.addButton(QtWidgets.QDialogButtonBox.Ok) self.confirmationBox.addButton(QtWidgets.QDialogButtonBox.Cancel) self.confirmationBox.button( QtWidgets.QDialogButtonBox.Ok).setEnabled(False) ############################################# # SETUP DIALOG LAYOUT ################################# self.mainLayout = QtWidgets.QVBoxLayout(self) self.mainLayout.setContentsMargins(10, 10, 10, 10) self.mainLayout.addWidget(self.nameField) self.mainLayout.addWidget(self.warnLabel) self.mainLayout.addWidget(self.confirmationBox, 0, QtCore.Qt.AlignRight) self.setFixedSize(self.sizeHint()) self.setWindowIcon(QtGui.QIcon(':/icons/128/ic_eddy')) connect(self.confirmationBox.accepted, self.accept) connect(self.confirmationBox.rejected, self.reject) ############################################# # SLOTS ################################# @QtCore.pyqtSlot(str) def onNameFieldChanged(self, name): """ Executed when the content of the input field changes. :type name: str """ name = name.strip() if not name: caption = '' enabled = False else: for diagram in self.project.diagrams(): if diagram.name.upper() == name.upper(): caption = "Diagram '{0}' already exists!".format(name) enabled = False break else: caption = '' enabled = True self.warnLabel.setText(caption) self.warnLabel.setVisible(not isEmpty(caption)) self.confirmationBox.button( QtWidgets.QDialogButtonBox.Ok).setEnabled(enabled) self.setFixedSize(self.sizeHint())
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)
class AbstractDiagramForm(QtWidgets.QDialog): """ Base class for diagram dialogs. """ __metaclass__ = ABCMeta def __init__(self, project, parent=None): """ Initialize the dialog. :type project: Project :type parent: QtWidgets.QWidget """ super().__init__(parent) self.project = project ############################################# # FORM AREA ################################# self.nameField = StringField(self) self.nameField.setFont(Font('Roboto', 12)) self.nameField.setMinimumWidth(400) self.nameField.setMaxLength(64) self.nameField.setPlaceholderText('Name...') connect(self.nameField.textChanged, self.onNameFieldChanged) self.warnLabel = QtWidgets.QLabel(self) self.warnLabel.setContentsMargins(0, 0, 0, 0) self.warnLabel.setProperty('class', 'invalid') self.warnLabel.setVisible(False) ############################################# # CONFIRMATION AREA ################################# self.confirmationBox = QtWidgets.QDialogButtonBox(QtCore.Qt.Horizontal, self) self.confirmationBox.addButton(QtWidgets.QDialogButtonBox.Ok) self.confirmationBox.addButton(QtWidgets.QDialogButtonBox.Cancel) self.confirmationBox.setFont(Font('Roboto', 12)) self.confirmationBox.button(QtWidgets.QDialogButtonBox.Ok).setEnabled(False) ############################################# # SETUP DIALOG LAYOUT ################################# self.mainLayout = QtWidgets.QVBoxLayout(self) self.mainLayout.setContentsMargins(10, 10, 10, 10) self.mainLayout.addWidget(self.nameField) self.mainLayout.addWidget(self.warnLabel) self.mainLayout.addWidget(self.confirmationBox, 0, QtCore.Qt.AlignRight) self.setFixedSize(self.sizeHint()) self.setWindowIcon(QtGui.QIcon(':/icons/128/ic_eddy')) connect(self.confirmationBox.accepted, self.accept) connect(self.confirmationBox.rejected, self.reject) ############################################# # SLOTS ################################# @QtCore.pyqtSlot(str) def onNameFieldChanged(self, name): """ Executed when the content of the input field changes. :type name: str """ name = name.strip() if not name: caption = '' enabled = False else: for diagram in self.project.diagrams(): if diagram.name.upper() == name.upper(): caption = "Diagram '{0}' already exists!".format(name) enabled = False break else: caption = '' enabled = True self.warnLabel.setText(caption) self.warnLabel.setVisible(not isEmpty(caption)) self.confirmationBox.button(QtWidgets.QDialogButtonBox.Ok).setEnabled(enabled) self.setFixedSize(self.sizeHint())
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)
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)
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)
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)
def __init__(self, session): """ Initialize the Ontology Manager dialog. :type session: Session """ super().__init__(session) settings = QtCore.QSettings() ############################################# # GENERAL TAB ################################# ## ONTOLOGY PROPERTIES GROUP iriLabel = QtWidgets.QLabel(self, objectName='ontology_iri_label') iriLabel.setText('Ontology IRI') self.addWidget(iriLabel) iriField = StringField(self, objectName='ontology_iri_field') iriField.setPlaceholderText( 'e.g. http://example.com/ontologies/myontology/') self.addWidget(iriField) versionLabel = QtWidgets.QLabel(self, objectName='ontology_version_label') versionLabel.setText('Ontology Version IRI') self.addWidget(versionLabel) versionField = StringField(self, objectName='ontology_version_field') versionField.setPlaceholderText( 'e.g. http://example.com/ontologies/myontology/1.0') self.addWidget(versionField) formlayout = QtWidgets.QFormLayout() formlayout.addRow(self.widget('ontology_iri_label'), self.widget('ontology_iri_field')) formlayout.addRow(self.widget('ontology_version_label'), self.widget('ontology_version_field')) groupbox = QtWidgets.QGroupBox('Ontology IRI', self, objectName='ontology_iri_widget') groupbox.setLayout(formlayout) self.addWidget(groupbox) ## ONTOLOGY IMPORTS GROUP table = QtWidgets.QTableWidget( 0, 2, self, objectName='ontology_imports_table_widget') table.setHorizontalHeaderLabels(['Name', 'Ontology IRI']) table.horizontalHeader().setStretchLastSection(True) table.horizontalHeader().setSectionsClickable(False) table.horizontalHeader().setMinimumSectionSize(130) table.horizontalHeader().setSectionsClickable(False) table.verticalHeader().setVisible(False) table.verticalHeader().setSectionsClickable(False) table.setSelectionBehavior(QtWidgets.QAbstractItemView.SelectRows) self.addWidget(table) addBtn = QtWidgets.QPushButton( 'Add', objectName='ontology_imports_add_button') delBtn = QtWidgets.QPushButton( 'Remove', objectName='ontology_imports_delete_button') connect(addBtn.clicked, self.addOntologyImport) connect(delBtn.clicked, self.removeOntologyImport) self.addWidget(addBtn) self.addWidget(delBtn) boxlayout = QtWidgets.QHBoxLayout() boxlayout.setAlignment(QtCore.Qt.AlignCenter) boxlayout.addWidget(self.widget('ontology_imports_add_button')) boxlayout.addWidget(self.widget('ontology_imports_delete_button')) formlayout = QtWidgets.QFormLayout() formlayout.addRow(self.widget('ontology_imports_table_widget')) formlayout.addRow(boxlayout) groupbox = QtWidgets.QGroupBox('Imported Ontologies', self, objectName='ontology_imports_widget') groupbox.setLayout(formlayout) self.addWidget(groupbox) ## ONTOLOGY ANNOTATIONS GROUP table = QtWidgets.QTableWidget( 0, 3, self, objectName='ontology_annotations_table_widget') table.setHorizontalHeaderLabels(['Annotation', 'Datatype', 'Value']) table.horizontalHeader().setStretchLastSection(True) table.horizontalHeader().setSectionsClickable(False) table.horizontalHeader().setMinimumSectionSize(100) table.horizontalHeader().setSectionsClickable(False) table.verticalHeader().setVisible(False) table.verticalHeader().setSectionsClickable(False) table.setSelectionBehavior(QtWidgets.QAbstractItemView.SelectRows) self.addWidget(table) addBtn = QtWidgets.QPushButton( 'Add', objectName='ontology_annotations_add_button') delBtn = QtWidgets.QPushButton( 'Remove', objectName='ontology_annotations_delete_button') connect(addBtn.clicked, self.addOntologyAnnotation) connect(delBtn.clicked, self.removeOntologyAnnotation) self.addWidget(addBtn) self.addWidget(delBtn) boxlayout = QtWidgets.QHBoxLayout() boxlayout.setAlignment(QtCore.Qt.AlignCenter) boxlayout.addWidget(self.widget('ontology_annotations_add_button')) boxlayout.addWidget(self.widget('ontology_annotations_delete_button')) formlayout = QtWidgets.QFormLayout() formlayout.addRow(self.widget('ontology_annotations_table_widget')) formlayout.addRow(boxlayout) groupbox = QtWidgets.QGroupBox( 'Ontology Annotations', self, objectName='ontology_annotations_widget') groupbox.setLayout(formlayout) self.addWidget(groupbox) ## GENERAL TAB LAYOUT CONFIGURATION layout = QtWidgets.QVBoxLayout() layout.setAlignment(QtCore.Qt.AlignTop) layout.addWidget(self.widget('ontology_iri_widget'), 0, QtCore.Qt.AlignTop) layout.addWidget(self.widget('ontology_imports_widget'), 0, QtCore.Qt.AlignTop) layout.addWidget(self.widget('ontology_annotations_widget'), 0, QtCore.Qt.AlignTop) widget = QtWidgets.QWidget() widget.setLayout(layout) widget.setObjectName('general_widget') self.addWidget(widget) ############################################# # PREFIXES TAB ################################# ## PREFIXES GROUP table = QtWidgets.QTableWidget(1, 2, self, objectName='prefixes_table_widget') table.horizontalHeader().setStretchLastSection(True) table.horizontalHeader().setSectionsClickable(False) table.horizontalHeader().setMinimumSectionSize(100) table.horizontalHeader().setSectionsClickable(False) table.verticalHeader().setVisible(False) table.verticalHeader().setSectionsClickable(False) table.setSelectionBehavior(QtWidgets.QAbstractItemView.SelectRows) self.addWidget(table) addBtn = QtWidgets.QPushButton('Add', objectName='prefixes_add_button') delBtn = QtWidgets.QPushButton('Remove', objectName='prefixes_delete_button') connect(addBtn.clicked, self.addPrefix) connect(delBtn.clicked, self.removePrefix) self.addWidget(addBtn) self.addWidget(delBtn) boxlayout = QtWidgets.QHBoxLayout() boxlayout.setAlignment(QtCore.Qt.AlignCenter) boxlayout.addWidget(self.widget('prefixes_add_button')) boxlayout.addWidget(self.widget('prefixes_delete_button')) formlayout = QtWidgets.QFormLayout() formlayout.addRow(self.widget('prefixes_table_widget')) formlayout.addRow(boxlayout) groupbox = QtWidgets.QGroupBox('Ontology Prefixes', self, objectName='prefixes_group_widget') groupbox.setLayout(formlayout) self.addWidget(groupbox) ## PREFIXES TAB LAYOUT CONFIGURATION layout = QtWidgets.QVBoxLayout() layout.setAlignment(QtCore.Qt.AlignTop) layout.addWidget(self.widget('prefixes_group_widget'), 0, QtCore.Qt.AlignTop) widget = QtWidgets.QWidget() widget.setLayout(layout) widget.setObjectName('prefixes_widget') self.addWidget(widget) ############################################# # ANNOTATIONS TAB ################################# ## ANNOTATIONS GROUP table = QtWidgets.QTableWidget( 0, 2, self, objectName='annotation_properties_table_widget') table.setHorizontalHeaderLabels(['IRI', 'Comment']) table.horizontalHeader().setStretchLastSection(True) table.horizontalHeader().setSectionsClickable(False) table.horizontalHeader().setMinimumSectionSize(100) table.horizontalHeader().setSectionsClickable(False) table.verticalHeader().setVisible(False) table.verticalHeader().setSectionsClickable(False) table.setSelectionBehavior(QtWidgets.QAbstractItemView.SelectRows) self.addWidget(table) addBtn = QtWidgets.QPushButton( 'Add', objectName='annotation_properties_add_button') delBtn = QtWidgets.QPushButton( 'Remove', objectName='annotation_properties_delete_button') connect(addBtn.clicked, self.addAnnotationProperty) connect(delBtn.clicked, self.removeAnnotationProperty) self.addWidget(addBtn) self.addWidget(delBtn) boxlayout = QtWidgets.QHBoxLayout() boxlayout.setAlignment(QtCore.Qt.AlignCenter) boxlayout.addWidget(self.widget('annotation_properties_add_button')) boxlayout.addWidget(self.widget('annotation_properties_delete_button')) formlayout = QtWidgets.QFormLayout() formlayout.addRow(self.widget('annotation_properties_table_widget')) formlayout.addRow(boxlayout) groupbox = QtWidgets.QGroupBox( 'Annotation Properties', self, objectName='annotation_properties_widget') groupbox.setLayout(formlayout) self.addWidget(groupbox) ## ANNOTATIONS TAB LAYOUT CONFIGURATION layout = QtWidgets.QVBoxLayout() layout.setAlignment(QtCore.Qt.AlignTop) layout.addWidget(self.widget('annotation_properties_widget'), 0, QtCore.Qt.AlignTop) widget = QtWidgets.QWidget() widget.setLayout(layout) widget.setObjectName('annotations_widget') self.addWidget(widget) ############################################# # CONFIRMATION BOX ################################# confirmation = QtWidgets.QDialogButtonBox( QtCore.Qt.Horizontal, self, objectName='confirmation_widget') confirmation.addButton(QtWidgets.QDialogButtonBox.Save) confirmation.addButton(QtWidgets.QDialogButtonBox.Cancel) confirmation.setContentsMargins(10, 0, 10, 10) self.addWidget(confirmation) ############################################# # MAIN WIDGET ################################# widget = QtWidgets.QTabWidget(self, objectName='main_widget') widget.addTab(self.widget('general_widget'), 'General') widget.addTab(self.widget('prefixes_widget'), 'Prefixes') widget.addTab(self.widget('annotations_widget'), 'Annotations') self.addWidget(widget) layout = QtWidgets.QVBoxLayout() layout.setContentsMargins(0, 0, 0, 0) layout.addWidget(self.widget('main_widget')) layout.addWidget(self.widget('confirmation_widget'), 0, QtCore.Qt.AlignRight) self.setLayout(layout) self.setMinimumSize(800, 520) self.setWindowIcon(QtGui.QIcon(':/icons/128/ic_eddy')) self.setWindowTitle('Ontology Manager') self.redraw() connect(confirmation.accepted, self.accept) connect(confirmation.rejected, self.reject)
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)