From 4946caa4561a55166c3d68dedfd238c04f81b7fb Mon Sep 17 00:00:00 2001 From: Manuel Namici Date: Wed, 23 Oct 2024 16:37:27 +0200 Subject: [PATCH 1/8] ui: ontology: rework of annotation assertions tab in ontology manager This was done to allow viewing and editing assertions about subjects that are not part of the graphical graphol project, but can be seen as arbitrary RDF triples representing additional metadata for subjects not mentioned graphically. --- eddy/ui/ontology.py | 359 +++++++++++++++----------------------------- 1 file changed, 122 insertions(+), 237 deletions(-) diff --git a/eddy/ui/ontology.py b/eddy/ui/ontology.py index f44561bf..ec1fe2b7 100644 --- a/eddy/ui/ontology.py +++ b/eddy/ui/ontology.py @@ -40,7 +40,7 @@ from eddy.core.commands.iri import ( CommandCommmonSubstringIRIsRefactor, - CommandIRIRemoveAnnotationAssertion, CommandIRIAddAnnotationAssertion, + CommandIRIRemoveAnnotationAssertion, ) from eddy.core.commands.project import ( CommandProjectAddAnnotationProperty, @@ -54,11 +54,8 @@ CommandProjectSetOntologyIRIAndVersion, ) from eddy.core.common import HasWidgetSystem -from eddy.core.datatypes.graphol import Item from eddy.core.datatypes.system import File - from eddy.core.exporters.metadata import ( - AbstractMetadataExporter, AnnotationsOverridingDialog, CsvTemplateExporter, XlsxTemplateExporter, @@ -72,9 +69,9 @@ AnnotationAssertion, IllegalPrefixError, IllegalNamespaceError, - ImportedOntology, IRI + ImportedOntology, ) -from eddy.ui.dialogs import DiagramSelectionDialog +from eddy.ui.annotation import AnnotationAssertionBuilderDialog from eddy.ui.fields import ( StringField, CheckBox, @@ -447,11 +444,18 @@ def __init__(self, session): searchbar = QtWidgets.QLineEdit(objectName='searchbar_annotations') searchbar.setPlaceholderText("Search...") - searchbar.textChanged.connect(self.searchAnnotationTable) + connect(searchbar.textChanged, self.searchAnnotationTable) self.addWidget(searchbar) - table = QtWidgets.QTableWidget(0, 7, self, objectName='annotation_assertions_table_widget') - table.setHorizontalHeaderLabels(['IRI', 'SimpleName', 'Type', 'AnnotationProperty', 'Datatype', 'Lang', 'Value']) + table = QtWidgets.QTableWidget(0, 6, self, objectName='annotation_assertions_table_widget') + table.setHorizontalHeaderLabels([ + 'IRI', + 'SimpleName', + 'AnnotationProperty', + 'Value', + 'Datatype', + 'Lang', + ]) table.horizontalHeader().setStretchLastSection(True) table.horizontalHeader().setSectionsClickable(False) table.horizontalHeader().setMinimumSectionSize(120) @@ -476,7 +480,6 @@ def __init__(self, session): self.addWidget(editBtn) self.addWidget(delBtn) - boxlayout = QtWidgets.QHBoxLayout() boxlayout.setAlignment(QtCore.Qt.AlignCenter) boxlayout.addWidget(self.widget('annotation_assertions_selectall_button')) @@ -528,14 +531,14 @@ def __init__(self, session): snakeCheckbox = CheckBox('convert snake_case to space separated values', self, checked=self.project.convertSnake, objectName='convert_snake') - snakeCheckbox.clicked.connect(lambda: self.onCaseCheckBoxClicked(snakeCheckbox)) + connect(snakeCheckbox.clicked, self.onCaseCheckBoxClicked) self.addWidget(snakeCheckbox) snakeCheckbox.setEnabled(checked) camelCheckbox = CheckBox('convert camelCase to space separated values', self, checked=self.project.convertCamel, objectName='convert_camel') - camelCheckbox.clicked.connect(lambda: self.onCaseCheckBoxClicked(camelCheckbox)) + connect(camelCheckbox.clicked, self.onCaseCheckBoxClicked) self.addWidget(camelCheckbox) camelCheckbox.setEnabled(checked) @@ -632,10 +635,7 @@ def __init__(self, session): ################################# confirmation = QtWidgets.QDialogButtonBox(QtCore.Qt.Horizontal, self, objectName='confirmation_widget') - #confirmation.addButton(QtWidgets.QDialogButtonBox.Save) - #confirmation.addButton(QtWidgets.QDialogButtonBox.Cancel) - doneBtn = QtWidgets.QPushButton('Done', objectName='done_button') - confirmation.addButton(doneBtn, QtWidgets.QDialogButtonBox.AcceptRole) + confirmation.addButton(QtWidgets.QDialogButtonBox.Ok) confirmation.setContentsMargins(10, 0, 10, 10) self.addWidget(confirmation) @@ -657,6 +657,11 @@ def __init__(self, session): layout.addWidget(self.widget('confirmation_widget'), 0, QtCore.Qt.AlignRight) self.setLayout(layout) self.setMinimumSize(800, 800) + self.restoreGeometry(settings.value( + 'manager/geometry', + QtCore.QByteArray(), + QtCore.QByteArray), + ) self.setWindowIcon(QtGui.QIcon(':/icons/128/ic_eddy')) self.setWindowTitle('Ontology Manager') self.redraw() @@ -683,6 +688,16 @@ def session(self): # SLOTS ################################# + @QtCore.pyqtSlot() + def accept(self) -> None: + """ + Executed when the dialog is accepted. + """ + settings = QtCore.QSettings() + settings.setValue('manager/geometry', self.saveGeometry()) + settings.sync() + super().accept() + @QtCore.pyqtSlot() def redraw(self): """ @@ -799,65 +814,11 @@ def redraw(self): # ANNOTATION ASSERTIONS TAB ################################ - metadataExp = AbstractMetadataExporter(self.project, self.session) - annotationAssertions = metadataExp.metadata() table = self.widget('annotation_assertions_table_widget') - table.clear() - table.setHorizontalHeaderLabels( - ['IRI', 'SimpleName', 'Type', 'AnnotationProperty', 'Datatype', 'Lang', 'Value']) - table.setRowCount(len(annotationAssertions)) - - rowcount = 0 - processed = set() - Types = { - Item.AttributeNode: 'Data Property', - Item.ConceptNode: 'Class', - Item.IndividualNode: 'Named Individual', - Item.RoleNode: 'Object Property', - } - items = Types.keys() - annotations = self.project.getAnnotationPropertyIRIs() - - for diagram in self.project.diagrams(): - for node in self.project.iriOccurrences(diagram=diagram): - if node.type() not in items or node.iri in processed: - continue - for annotation in node.iri.annotationAssertions: - if annotation.assertionProperty in annotations: - - iriItem = QtWidgets.QTableWidgetItem(str(node.iri)) - iriItem.setFlags(QtCore.Qt.ItemIsEnabled | QtCore.Qt.ItemIsSelectable) - table.setItem(rowcount, 0, iriItem) - - simpleNameItem = QtWidgets.QTableWidgetItem(node.iri.getSimpleName()) - simpleNameItem.setFlags(QtCore.Qt.ItemIsEnabled | QtCore.Qt.ItemIsSelectable) - table.setItem(rowcount, 1, simpleNameItem) - - typeItem = QtWidgets.QTableWidgetItem(Types.get(node.type())) - typeItem.setFlags(QtCore.Qt.ItemIsEnabled | QtCore.Qt.ItemIsSelectable) - table.setItem(rowcount, 2, typeItem) - - propItem = QtWidgets.QTableWidgetItem(str(annotation.assertionProperty)) - propItem.setFlags(QtCore.Qt.ItemIsEnabled | QtCore.Qt.ItemIsSelectable) - propItem.setData(QtCore.Qt.UserRole, annotation) - table.setItem(rowcount, 3, propItem) - - datatypeItem = QtWidgets.QTableWidgetItem(str(annotation.datatype) or '') - datatypeItem.setFlags(QtCore.Qt.ItemIsEnabled | QtCore.Qt.ItemIsSelectable) - table.setItem(rowcount, 4, datatypeItem) - - langItem = QtWidgets.QTableWidgetItem(annotation.language or '') - langItem.setFlags(QtCore.Qt.ItemIsEnabled | QtCore.Qt.ItemIsSelectable) - table.setItem(rowcount, 5, langItem) - - valueItem = QtWidgets.QTableWidgetItem(str(annotation.value)) - valueItem.setFlags(QtCore.Qt.ItemIsEnabled | QtCore.Qt.ItemIsSelectable) - table.setItem(rowcount, 6, valueItem) - - rowcount += 1 - - processed.add(node.iri) - + table.clearContents() + for iri in self.project.iris: + for assertion in iri.annotationAssertions: + self._insertAssertionTableRow(assertion) table.resizeColumnsToContents() table.sortItems(0) @@ -1047,9 +1008,9 @@ def addOntologyAnnotation(self, _): :type _: bool """ LOGGER.debug("addOntologyAnnotation called") - assertionBuilder = self.session.doOpenAnnotationAssertionBuilder(self.project.ontologyIRI) + assertionBuilder = AnnotationAssertionBuilderDialog(self.session, self.project.ontologyIRI) connect(assertionBuilder.sgnAnnotationAssertionAccepted, self.redraw) - assertionBuilder.exec_() + assertionBuilder.open() @QtCore.pyqtSlot(bool) def removeOntologyAnnotation(self, _): @@ -1093,12 +1054,13 @@ def editOntologyAnnotation(self, _): for row in range(selectedRange.bottomRow(), selectedRange.topRow() + 1): editItem = table.item(row, 0) assertion = editItem.data(QtCore.Qt.UserRole) - assertionBuilder = self.session.doOpenAnnotationAssertionBuilder( + assertionBuilder = AnnotationAssertionBuilderDialog( + self.session, self.project.ontologyIRI, assertion, ) connect(assertionBuilder.sgnAnnotationAssertionCorrectlyModified,self.redraw) - assertionBuilder.exec_() + assertionBuilder.open() ############################################# # PREFIXES TAB @@ -1499,9 +1461,11 @@ def onLabelUserInputCheckBoxClicked(self): self.widget('convert_camel').setEnabled(False) self.widget('iri_label_button').setEnabled(True) - def onCaseCheckBoxClicked(self, checkbox): + @QtCore.pyqtSlot() + def onCaseCheckBoxClicked(self, _): self.widget('iri_label_button').setEnabled(True) - self.project.convertCase(checkbox) + self.project.convertCase(self.sender()) + @QtCore.pyqtSlot(int) def onLanguageSwitched(self,index): self.widget('iri_label_button').setEnabled(True) @@ -1591,186 +1555,77 @@ def importTemplate(self): return - @QtCore.pyqtSlot(bool) + @QtCore.pyqtSlot() def addAnnotationAssertion(self): - - assertionBuilder = self.session.doOpenAnnotationAssertionBuilder() + assertionBuilder = AnnotationAssertionBuilderDialog(self.session) connect(assertionBuilder.sgnAnnotationAssertionAccepted, self.onAnnotationAssertionAccepted) - assertionBuilder.exec_() - - def onAnnotationAssertionAccepted(self, assertion): - """ - :type assertion:AnnotationAssertion - """ - Types = { - Item.AttributeNode: 'Data Property', - Item.ConceptNode: 'Class', - Item.IndividualNode: 'Named Individual', - Item.RoleNode: 'Object Property', - } - - - table = self.widget('annotation_assertions_table_widget') - rowcount = table.rowCount() - table.setRowCount(rowcount + 1) + assertionBuilder.open() - subjectIRI = str(assertion.subject) - iriItem = QtWidgets.QTableWidgetItem(subjectIRI) - iriItem.setFlags(QtCore.Qt.ItemIsEnabled | QtCore.Qt.ItemIsSelectable) - table.setItem(rowcount, 0, iriItem) - - simpleName = self.project.getIRI(subjectIRI).getSimpleName() - simpleNameItem = QtWidgets.QTableWidgetItem(str(simpleName)) - simpleNameItem.setFlags(QtCore.Qt.ItemIsEnabled | QtCore.Qt.ItemIsSelectable) - table.setItem(rowcount, 1, simpleNameItem) - - for node in self.project.iriOccurrences(): - if node.iri is self.project.getIRI(subjectIRI): - typeItem = QtWidgets.QTableWidgetItem(Types.get(node.type())) - typeItem.setFlags(QtCore.Qt.ItemIsEnabled | QtCore.Qt.ItemIsSelectable) - table.setItem(rowcount, 2, typeItem) - - propertyItem = QtWidgets.QTableWidgetItem(str(assertion.assertionProperty)) - propertyItem.setFlags(QtCore.Qt.ItemIsEnabled | QtCore.Qt.ItemIsSelectable) - propertyItem.setData(QtCore.Qt.UserRole, assertion) - table.setItem(rowcount, 3, propertyItem) - - datatype = assertion.datatype or '' - datatypeItem = QtWidgets.QTableWidgetItem(str(datatype)) - datatypeItem.setFlags(QtCore.Qt.ItemIsEnabled | QtCore.Qt.ItemIsSelectable) - table.setItem(rowcount, 4, QtWidgets.QTableWidgetItem(datatypeItem)) - - language = assertion.language or '' - langItem = QtWidgets.QTableWidgetItem(str(language)) - langItem.setFlags(QtCore.Qt.ItemIsEnabled | QtCore.Qt.ItemIsSelectable) - table.setItem(rowcount, 5, QtWidgets.QTableWidgetItem(langItem)) - - valueItem = QtWidgets.QTableWidgetItem(str(assertion.value)) - valueItem.setFlags(QtCore.Qt.ItemIsEnabled | QtCore.Qt.ItemIsSelectable) - table.setItem(rowcount, 6, QtWidgets.QTableWidgetItem(valueItem)) - - table.scrollToItem(table.item(rowcount, 0)) + @QtCore.pyqtSlot(AnnotationAssertion) + def onAnnotationAssertionAccepted(self, assertion: AnnotationAssertion): + table: QtWidgets.QTableWidget = self.widget('annotation_assertions_table_widget') + self._insertAssertionTableRow(assertion) table.resizeColumnToContents(0) + table.scrollToItem(table.item(table.rowCount(), 0)) + @QtCore.pyqtSlot() def editAnnotationAssertion(self): - table = self.widget('annotation_assertions_table_widget') selectedRanges = table.selectedRanges() for selectedRange in selectedRanges: for row in range(selectedRange.bottomRow(), selectedRange.topRow() + 1): - itemIri = self.project.getIRI(str(table.item(row, 0).text())) - editItem = table.item(row, 3) - assertion = editItem.data(QtCore.Qt.UserRole) - - assertionBuilder = self.session.doOpenAnnotationAssertionBuilder(itemIri, - assertion) + assertion = table.item(row, 2).data(QtCore.Qt.UserRole) + assertionBuilder = AnnotationAssertionBuilderDialog( + self.session, itemIri, assertion) connect(assertionBuilder.sgnAnnotationAssertionCorrectlyModified, self.onAnnotationAssertionModified) - assertionBuilder.exec_() + assertionBuilder.exec_() # Needed here but should be replaced with open() - def onAnnotationAssertionModified(self, assertion): - """ - :type assertion:AnnotationAssertion - """ - Types = { - Item.AttributeNode: 'Data Property', - Item.ConceptNode: 'Class', - Item.IndividualNode: 'Named Individual', - Item.RoleNode: 'Object Property', - } - - table = self.widget('annotation_assertions_table_widget') - rowcount = table.rowCount() - for row in range(0, rowcount): - - propItem = table.item(row, 3) - itemAssertion = propItem.data(QtCore.Qt.UserRole) + @QtCore.pyqtSlot(AnnotationAssertion) + def onAnnotationAssertionModified(self, assertion: AnnotationAssertion): + table: QtWidgets.QTableWidget = self.widget('annotation_assertions_table_widget') + for rowcount in range(table.rowCount()): + itemAssertion = table.item(rowcount, 2).data(QtCore.Qt.UserRole) if itemAssertion is assertion: - - subjectIRI = str(assertion.subject) - iriItem = QtWidgets.QTableWidgetItem(subjectIRI) - iriItem.setFlags(QtCore.Qt.ItemIsEnabled | QtCore.Qt.ItemIsSelectable) - table.setItem(row, 0, iriItem) - - simpleName = self.project.getIRI(subjectIRI).getSimpleName() - simpleNameItem = QtWidgets.QTableWidgetItem(str(simpleName)) - simpleNameItem.setFlags(QtCore.Qt.ItemIsEnabled | QtCore.Qt.ItemIsSelectable) - table.setItem(row, 1, simpleNameItem) - - for node in self.project.iriOccurrences(): - if node.iri is self.project.getIRI(subjectIRI): - typeItem = QtWidgets.QTableWidgetItem(Types.get(node.type())) - typeItem.setFlags(QtCore.Qt.ItemIsEnabled | QtCore.Qt.ItemIsSelectable) - table.setItem(row, 2, typeItem) - - newPropertyItem = QtWidgets.QTableWidgetItem(str(assertion.assertionProperty)) - newPropertyItem.setFlags(QtCore.Qt.ItemIsEnabled | QtCore.Qt.ItemIsSelectable) - newPropertyItem.setData(QtCore.Qt.UserRole, assertion) - table.setItem(row, 3, newPropertyItem) - - datatype = assertion.datatype or '' - datatypeItem = QtWidgets.QTableWidgetItem(str(datatype)) - datatypeItem.setFlags(QtCore.Qt.ItemIsEnabled | QtCore.Qt.ItemIsSelectable) - table.setItem(row, 4, QtWidgets.QTableWidgetItem(datatypeItem)) - - language = assertion.language or '' - langItem = QtWidgets.QTableWidgetItem(str(language)) - langItem.setFlags(QtCore.Qt.ItemIsEnabled | QtCore.Qt.ItemIsSelectable) - table.setItem(row, 5, QtWidgets.QTableWidgetItem(langItem)) - - valueItem = QtWidgets.QTableWidgetItem(str(assertion.value)) - valueItem.setFlags(QtCore.Qt.ItemIsEnabled | QtCore.Qt.ItemIsSelectable) - table.setItem(row, 6, QtWidgets.QTableWidgetItem(valueItem)) - - table.scrollToItem(table.item(row, 0)) + table.removeRow(rowcount) + self._insertAssertionTableRow(assertion, rowcount) break - - @QtCore.pyqtSlot(bool) - def removeAnnotationAssertion(self, _): + @QtCore.pyqtSlot() + def removeAnnotationAssertion(self): """ Removes an annotation assertion from the ontology alphabet. - :type _: bool """ - table = self.widget('annotation_assertions_table_widget') - rowcount = table.rowCount() - - selectedCells = table.selectedItems() - rows = list(set([x.row() for x in selectedCells])) - rows = sorted(rows, reverse=True) - - commands = [] - for row in rows: - itemIri = self.project.getIRI(str(table.item(row, 0).text())) - editItem = table.item(row, 3) - assertion = editItem.data(QtCore.Qt.UserRole) - commands.append(CommandIRIRemoveAnnotationAssertion(self.project, itemIri, assertion)) - + table: QtWidgets.QTableWidget = self.widget('annotation_assertions_table_widget') + # Must remove in reverse order of selection to avoid changing row indexes while removing + selection = sorted([ + r + for s in table.selectedRanges() + for r in range(s.bottomRow(), s.topRow() + 1) + ], reverse=True) self.session.undostack.beginMacro('remove annotation assertions >>') - for command in commands: - if command: - self.session.undostack.push(command) - self.session.undostack.endMacro() - for row in rows: + for row in selection: + itemIri = self.project.getIRI(str(table.item(row, 0).text())) + assertion = table.item(row, 2).data(QtCore.Qt.UserRole) + self.session.undostack.push(CommandIRIRemoveAnnotationAssertion( + self.project, + itemIri, + assertion, + )) table.removeRow(row) - table.setRowCount(rowcount - len(rows)) - - def searchAnnotationTable(self): - - text = self.sender().text() + self.session.undostack.endMacro() + @QtCore.pyqtSlot(str) + def searchAnnotationTable(self, text): table = self.widget('annotation_assertions_table_widget') - - rowCount = table.rowCount() columnCount = table.columnCount() - for row in range(rowCount): + for row in range(table.rowCount()): table.showRow(row) self.hiddenRows = [] - - for row in range(rowCount): + for row in range(table.rowCount()): contains = False for col in range(columnCount): item = table.item(row, col).text() @@ -1780,17 +1635,47 @@ def searchAnnotationTable(self): table.hideRow(row) self.hiddenRows.append(row) + @QtCore.pyqtSlot() def selectAllAnnotationAssertion(self): - table = self.widget('annotation_assertions_table_widget') table.setSelectionMode(QtWidgets.QAbstractItemView.MultiSelection) table.clearSelection() - - rowCount = table.rowCount() - - for row in range(rowCount): + for row in range(table.rowCount()): if row not in self.hiddenRows: table.selectRow(row) - table.setSelectionMode(QtWidgets.QAbstractItemView.ExtendedSelection) + def _insertAssertionTableRow( + self, + assertion: AnnotationAssertion, + row: int = None, + ) -> None: + """ + Insert an annotation assertion into the assertion table. + + :param assertion: the assertion to insert. + :param row: position to insert the row to. + """ + table = self.widget('annotation_assertions_table_widget') + rowcount = row if row is not None else table.rowCount() + table.insertRow(rowcount) + iriItem = QtWidgets.QTableWidgetItem(str(assertion.subject)) + iriItem.setFlags(QtCore.Qt.ItemIsEnabled | QtCore.Qt.ItemIsSelectable) + table.setItem(rowcount, 0, iriItem) + simpleNameItem = QtWidgets.QTableWidgetItem(assertion.subject.getSimpleName()) + simpleNameItem.setFlags(QtCore.Qt.ItemIsEnabled | QtCore.Qt.ItemIsSelectable) + table.setItem(rowcount, 1, simpleNameItem) + propItem = QtWidgets.QTableWidgetItem(str(assertion.assertionProperty)) + propItem.setFlags(QtCore.Qt.ItemIsEnabled | QtCore.Qt.ItemIsSelectable) + propItem.setData(QtCore.Qt.UserRole, assertion) + table.setItem(rowcount, 2, propItem) + valueItem = QtWidgets.QTableWidgetItem(str(assertion.value)) + valueItem.setFlags(QtCore.Qt.ItemIsEnabled | QtCore.Qt.ItemIsSelectable) + table.setItem(rowcount, 3, valueItem) + datatypeItem = QtWidgets.QTableWidgetItem(str(assertion.datatype or '')) + datatypeItem.setFlags(QtCore.Qt.ItemIsEnabled | QtCore.Qt.ItemIsSelectable) + table.setItem(rowcount, 4, datatypeItem) + langItem = QtWidgets.QTableWidgetItem(assertion.language or '') + langItem.setFlags(QtCore.Qt.ItemIsEnabled | QtCore.Qt.ItemIsSelectable) + table.setItem(rowcount, 5, langItem) + From 124d8c3e41d00f52a394d623af371dfb7f46a992 Mon Sep 17 00:00:00 2001 From: Manuel Namici Date: Thu, 24 Oct 2024 09:54:10 +0200 Subject: [PATCH 2/8] ui: annotation: remove unneeded emptyString field No need to have a reference to avoid new instance creation as python does this automatically. --- eddy/ui/annotation.py | 117 +++++++++++++++++++++++------------------- 1 file changed, 65 insertions(+), 52 deletions(-) diff --git a/eddy/ui/annotation.py b/eddy/ui/annotation.py index 76443610..06f88cf9 100644 --- a/eddy/ui/annotation.py +++ b/eddy/ui/annotation.py @@ -33,6 +33,10 @@ ########################################################################## +from __future__ import annotations + +from typing import TYPE_CHECKING + from PyQt5 import ( QtCore, QtWidgets, @@ -64,6 +68,10 @@ resolvePrefix, ) +if TYPE_CHECKING: + from eddy.ui.session import Session + from eddy.core.items.edges.common.base import AxiomEdge + class AnnotationAssertionBuilderDialog(QtWidgets.QDialog, HasWidgetSystem): """ @@ -73,14 +81,14 @@ class AnnotationAssertionBuilderDialog(QtWidgets.QDialog, HasWidgetSystem): sgnAnnotationAssertionCorrectlyModified = QtCore.pyqtSignal(AnnotationAssertion) sgnAnnotationAssertionRejected = QtCore.pyqtSignal() - emptyString = '' - - def __init__(self,session,iri=None,assertion=None): + def __init__( + self, + session: Session, + iri: IRI = None, + assertion: AnnotationAssertion = None, + ) -> None: """ Initialize the annotation assertion builder dialog (subject IRI = iri). - :type iri: IRI - :type session: Session - :type assertion: AnnotationAssertion """ super().__init__(session) self.session = session @@ -96,17 +104,22 @@ def __init__(self,session,iri=None,assertion=None): combobox.setFocusPolicy(QtCore.Qt.StrongFocus) combobox.setScrollEnabled(True) if not self.iri: - combobox.addItem(self.emptyString) + combobox.addItem('') classes = self.project.itemIRIs(Item.ConceptNode) objProperties = self.project.itemIRIs(Item.RoleNode) dataProperties = self.project.itemIRIs(Item.AttributeNode) indiv = self.project.itemIRIs(Item.IndividualNode) datatypes = self.project.itemIRIs(Item.ValueDomainNode) - items = list(set(classes) | set(objProperties) | set(dataProperties) | set(indiv) | set( - datatypes)) + items = list( + set(classes) + | set(indiv) + | set(objProperties) + | set(dataProperties) + | set(datatypes) + ) sortedItems = sorted(items, key=str) combobox.addItems([str(x) for x in sortedItems]) - combobox.setCurrentText(self.emptyString) + combobox.setCurrentText('') else: items = [self.iri] sortedItems = sorted(items, key=str) @@ -123,11 +136,11 @@ def __init__(self,session,iri=None,assertion=None): combobox.setEditable(False) combobox.setFocusPolicy(QtCore.Qt.StrongFocus) combobox.setScrollEnabled(True) - combobox.addItem(self.emptyString) + combobox.addItem('') sortedItems = sorted(self.project.getAnnotationPropertyIRIs(), key=str) combobox.addItems([str(x) for x in sortedItems]) if not self.assertion: - combobox.setCurrentText(self.emptyString) + combobox.setCurrentText('') else: combobox.setCurrentText(str(self.assertion.assertionProperty)) self.addWidget(combobox) @@ -154,17 +167,17 @@ def __init__(self,session,iri=None,assertion=None): combobox.setEditable(False) combobox.setFocusPolicy(QtCore.Qt.StrongFocus) combobox.setScrollEnabled(True) - combobox.addItem(self.emptyString) + combobox.addItem('') sortedItems = sorted(self.project.getDatatypeIRIs(), key=str) combobox.addItems([str(x) for x in sortedItems]) if not self.assertion: - combobox.setCurrentText(self.emptyString) + combobox.setCurrentText('') else: if self.assertion.datatype: combobox.setCurrentText(str(self.assertion.datatype)) else: - combobox.setCurrentText(self.emptyString) + combobox.setCurrentText('') self.addWidget(combobox) connect(combobox.currentIndexChanged,self.onTypeSwitched) @@ -175,15 +188,15 @@ def __init__(self,session,iri=None,assertion=None): combobox.setEditable(True) combobox.setFocusPolicy(QtCore.Qt.StrongFocus) combobox.setScrollEnabled(True) - combobox.addItem(self.emptyString) + combobox.addItem('') combobox.addItems([x for x in self.project.getLanguages()]) if not self.assertion: - combobox.setCurrentText(self.emptyString) + combobox.setCurrentText('') else: if self.assertion.language: combobox.setCurrentText(str(self.assertion.language)) else: - combobox.setCurrentText(self.emptyString) + combobox.setCurrentText('') self.addWidget(combobox) formlayout = QtWidgets.QFormLayout(self) @@ -293,11 +306,11 @@ def __init__(self,session,iri=None,assertion=None): def redraw(self): combobox = self.widget('property_switch') combobox.clear() - combobox.addItem(self.emptyString) + combobox.addItem('') sortedItems = sorted(self.project.getAnnotationPropertyIRIs(), key=str) combobox.addItems([str(x) for x in sortedItems]) if not self.assertion: - combobox.setCurrentText(self.emptyString) + combobox.setCurrentText('') else: combobox.setCurrentText(str(self.assertion.assertionProperty)) @@ -309,32 +322,32 @@ def redraw(self): combobox = self.widget('type_switch') combobox.clear() - combobox.addItem(self.emptyString) + combobox.addItem('') sortedItems = sorted(self.project.getDatatypeIRIs(), key=str) combobox.addItems([str(x) for x in sortedItems]) if not self.assertion or self.assertion.isIRIValued(): - combobox.setCurrentText(self.emptyString) + combobox.setCurrentText('') else: if self.assertion.datatype: combobox.setCurrentText(str(self.assertion.datatype)) else: - combobox.setCurrentText(self.emptyString) + combobox.setCurrentText('') combobox = self.widget('lang_switch') combobox.clear() - combobox.addItem(self.emptyString) + combobox.addItem('') combobox.addItems([x for x in self.project.getLanguages()]) if not self.assertion or self.assertion.isIRIValued(): - combobox.setCurrentText(self.emptyString) + combobox.setCurrentText('') else: if self.assertion.language: combobox.setCurrentText(str(self.assertion.language)) else: - combobox.setCurrentText(self.emptyString) + combobox.setCurrentText('') combobox = self.widget('iri_prefix_switch') combobox.clear() - combobox.addItem(self.emptyString) + combobox.addItem('') combobox.addItems( [x + ':' + ' <' + y + '>' for x, y in self.project.prefixDictItems()]) @@ -346,7 +359,7 @@ def redraw(self): combobox.setCurrentText( shortest.prefix + ':' + ' <' + self.project.getNamespace(shortest.prefix) + '>') else: - combobox.setCurrentText(self.emptyString) + combobox.setCurrentText('') inputField = self.widget('iri_input_field') if shortest: @@ -367,7 +380,7 @@ def onSubjectSwitched(self, index): subIRI = self.widget('subject_switch').itemText(index) propIRI = self.widget('property_switch').currentText() confirmation = self.widget('confirmation_widget') - if subIRI != self.emptyString and propIRI != self.emptyString: + if subIRI != '' and propIRI != '': confirmation.button(QtWidgets.QDialogButtonBox.Save).setEnabled(True) else: confirmation.button(QtWidgets.QDialogButtonBox.Save).setEnabled(False) @@ -377,7 +390,7 @@ def onPropertySwitched(self, index): propIRI = self.widget('property_switch').itemText(index) subIRI = self.widget('subject_switch').currentText() confirmation = self.widget('confirmation_widget') - if subIRI != self.emptyString and propIRI != self.emptyString: + if subIRI != '' and propIRI != '': confirmation.button(QtWidgets.QDialogButtonBox.Save).setEnabled(True) else: confirmation.button(QtWidgets.QDialogButtonBox.Save).setEnabled(False) @@ -470,14 +483,14 @@ class AnnotationBuilderDialog(QtWidgets.QDialog, HasWidgetSystem): sgnAnnotationCorrectlyModified = QtCore.pyqtSignal(Annotation) sgnAnnotationRejected = QtCore.pyqtSignal() - emptyString = '' - - def __init__(self, edge, session, annotation=None): + def __init__( + self, + edge: AxiomEdge, + session: Session, + annotation: Annotation = None, + ) -> None: """ Initialize the annotation builder dialog - :type edge: AxiomEdge - :type session: Session - :type assertion: Annotation """ super().__init__(session) self.session = session @@ -492,11 +505,11 @@ def __init__(self, edge, session, annotation=None): combobox.setEditable(False) combobox.setFocusPolicy(QtCore.Qt.StrongFocus) combobox.setScrollEnabled(True) - combobox.addItem(self.emptyString) + combobox.addItem('') sortedItems = sorted(self.project.getAnnotationPropertyIRIs(), key=str) combobox.addItems([str(x) for x in sortedItems]) if not self.annotation: - combobox.setCurrentText(self.emptyString) + combobox.setCurrentText('') else: combobox.setCurrentText(str(self.annotation.assertionProperty)) self.addWidget(combobox) @@ -515,17 +528,17 @@ def __init__(self, edge, session, annotation=None): combobox.setEditable(False) combobox.setFocusPolicy(QtCore.Qt.StrongFocus) combobox.setScrollEnabled(True) - combobox.addItem(self.emptyString) + combobox.addItem('') sortedItems = sorted(self.project.getDatatypeIRIs(), key=str) combobox.addItems([str(x) for x in sortedItems]) if not self.annotation: - combobox.setCurrentText(self.emptyString) + combobox.setCurrentText('') else: if self.annotation.datatype: combobox.setCurrentText(str(self.annotation.datatype)) else: - combobox.setCurrentText(self.emptyString) + combobox.setCurrentText('') self.addWidget(combobox) connect(combobox.currentIndexChanged, self.onTypeSwitched) @@ -536,15 +549,15 @@ def __init__(self, edge, session, annotation=None): combobox.setEditable(True) combobox.setFocusPolicy(QtCore.Qt.StrongFocus) combobox.setScrollEnabled(True) - combobox.addItem(self.emptyString) + combobox.addItem('') combobox.addItems([x for x in self.project.getLanguages()]) if not self.annotation: - combobox.setCurrentText(self.emptyString) + combobox.setCurrentText('') else: if self.annotation.language: combobox.setCurrentText(str(self.annotation.language)) else: - combobox.setCurrentText(self.emptyString) + combobox.setCurrentText('') self.addWidget(combobox) ############################################# @@ -581,11 +594,11 @@ def __init__(self, edge, session, annotation=None): def redraw(self): combobox = self.widget('property_switch') combobox.clear() - combobox.addItem(self.emptyString) + combobox.addItem('') sortedItems = sorted(self.project.getAnnotationPropertyIRIs(), key=str) combobox.addItems([str(x) for x in sortedItems]) if not self.annotation: - combobox.setCurrentText(self.emptyString) + combobox.setCurrentText('') else: combobox.setCurrentText(str(self.annotation.assertionProperty)) @@ -596,28 +609,28 @@ def redraw(self): combobox = self.widget('type_switch') combobox.clear() - combobox.addItem(self.emptyString) + combobox.addItem('') sortedItems = sorted(self.project.getDatatypeIRIs(), key=str) combobox.addItems([str(x) for x in sortedItems]) if not self.annotation: - combobox.setCurrentText(self.emptyString) + combobox.setCurrentText('') else: if self.annotation.datatype: combobox.setCurrentText(str(self.annotation.datatype)) else: - combobox.setCurrentText(self.emptyString) + combobox.setCurrentText('') combobox = self.widget('lang_switch') combobox.clear() - combobox.addItem(self.emptyString) + combobox.addItem('') combobox.addItems([x for x in self.project.getLanguages()]) if not self.annotation: - combobox.setCurrentText(self.emptyString) + combobox.setCurrentText('') else: if self.annotation.language: combobox.setCurrentText(str(self.annotation.language)) else: - combobox.setCurrentText(self.emptyString) + combobox.setCurrentText('') @QtCore.pyqtSlot(int) def onPropertySwitched(self, index): From 84a779e7b55c72112e1e393af6c6190cc9ee1976 Mon Sep 17 00:00:00 2001 From: Manuel Namici Date: Mon, 18 Nov 2024 19:29:31 +0100 Subject: [PATCH 3/8] ui: annotation: update assertion builder for non graphical annotations Datatype and lang combos have the following behaviour now: * If there is a datatype selected, disable the lang selector * If there is a lang tag entered, disable the datatype selector In RDF there cannot be a datatype and a lang string for any literal, even if OWL 2 allows the rdf:PlainLiteral to have one, but this is implicit, so stop the user from asserting that. --- eddy/ui/annotation.py | 155 ++++++++++++++++++++++++++---------------- 1 file changed, 97 insertions(+), 58 deletions(-) diff --git a/eddy/ui/annotation.py b/eddy/ui/annotation.py index 06f88cf9..d0554048 100644 --- a/eddy/ui/annotation.py +++ b/eddy/ui/annotation.py @@ -39,6 +39,7 @@ from PyQt5 import ( QtCore, + QtGui, QtWidgets, ) from rfc3987 import parse @@ -56,6 +57,7 @@ Annotation, AnnotationAssertion, IRI, + OWL2Datatype, ) from eddy.ui.fields import ComboBox from eddy.ui.iri import ( @@ -96,58 +98,72 @@ def __init__( self.iri = iri self.assertion = assertion - comboBoxLabel = QtWidgets.QLabel(self, objectName='subject_combobox_label') - comboBoxLabel.setText('Subject') + 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') + + # Occurrences in diagrams + self.classes = sorted(self.project.itemIRIs(Item.ConceptNode), key=str) + self.objectProperties = sorted(self.project.itemIRIs(Item.RoleNode), key=str) + self.dataProperties = sorted(self.project.itemIRIs(Item.AttributeNode), key=str) + self.individuals = sorted(self.project.itemIRIs(Item.IndividualNode), key=str) + self.datatypes = sorted(self.project.itemIRIs(Item.ValueDomainNode), key=str) + self.annotations = sorted(self.project.getAnnotationPropertyIRIs(), key=str) + + self.subjects = QtGui.QStandardItemModel(self) + self.predicates = QtGui.QStandardItemModel(self) + self.types = QtGui.QStandardItemModel(self) + + comboBoxLabel = QtWidgets.QLabel('&Subject', self, objectName='subject_combobox_label') self.addWidget(comboBoxLabel) combobox = ComboBox(self, objectName='subject_switch') - combobox.setEditable(False) - combobox.setFocusPolicy(QtCore.Qt.StrongFocus) - combobox.setScrollEnabled(True) + comboBoxLabel.setBuddy(combobox) + combobox.setFocusPolicy(QtCore.Qt.FocusPolicy.StrongFocus) + combobox.setModel(self.subjects) + combobox.addItem('') if not self.iri: - combobox.addItem('') - classes = self.project.itemIRIs(Item.ConceptNode) - objProperties = self.project.itemIRIs(Item.RoleNode) - dataProperties = self.project.itemIRIs(Item.AttributeNode) - indiv = self.project.itemIRIs(Item.IndividualNode) - datatypes = self.project.itemIRIs(Item.ValueDomainNode) - items = list( - set(classes) - | set(indiv) - | set(objProperties) - | set(dataProperties) - | set(datatypes) - ) - sortedItems = sorted(items, key=str) - combobox.addItems([str(x) for x in sortedItems]) + for e in self.classes: + self.subjects.appendRow(QtGui.QStandardItem(self.iconConcept, str(e))) + for e in self.individuals: + self.subjects.appendRow(QtGui.QStandardItem(self.iconInstance, str(e))) + for e in self.objectProperties: + self.subjects.appendRow(QtGui.QStandardItem(self.iconRole, str(e))) + for e in self.dataProperties: + self.subjects.appendRow(QtGui.QStandardItem(self.iconAttribute, str(e))) + for e in self.datatypes: + self.subjects.appendRow(QtGui.QStandardItem(self.iconValue, str(e))) combobox.setCurrentText('') else: - items = [self.iri] - sortedItems = sorted(items, key=str) - combobox.addItems([str(x) for x in sortedItems]) + combobox.addItem(str(self.iri)) combobox.setCurrentText(str(self.iri)) + combobox.setEnabled(False) self.addWidget(combobox) connect(combobox.currentIndexChanged, self.onSubjectSwitched) - comboBoxLabel = QtWidgets.QLabel(self, objectName='property_combobox_label') - comboBoxLabel.setText('Property') + comboBoxLabel = QtWidgets.QLabel('&Property', self, objectName='property_combobox_label') self.addWidget(comboBoxLabel) combobox = ComboBox(self, objectName='property_switch') - combobox.setEditable(False) - combobox.setFocusPolicy(QtCore.Qt.StrongFocus) - combobox.setScrollEnabled(True) + comboBoxLabel.setBuddy(combobox) + combobox.setModel(self.predicates) + combobox.setFocusPolicy(QtCore.Qt.FocusPolicy.StrongFocus) combobox.addItem('') - sortedItems = sorted(self.project.getAnnotationPropertyIRIs(), key=str) - combobox.addItems([str(x) for x in sortedItems]) + for p in self.annotations: + self.predicates.appendRow(QtGui.QStandardItem(str(p))) if not self.assertion: combobox.setCurrentText('') + elif self.assertion.assertionProperty not in self.annotations: + combobox.addItem(str(self.assertion.assertionProperty)) + combobox.setCurrentText(str(self.assertion.assertionProperty)) + combobox.setEnabled(False) else: combobox.setCurrentText(str(self.assertion.assertionProperty)) self.addWidget(combobox) connect(combobox.currentIndexChanged, self.onPropertySwitched) - valueLabel = QtWidgets.QLabel(self, objectName='value_label') - valueLabel.setText('Value') + valueLabel = QtWidgets.QLabel('Value', self, objectName='value_label') self.addWidget(valueLabel) ############################################# @@ -160,17 +176,21 @@ def __init__( textArea.setText(str(self.assertion.value)) self.addWidget(textArea) - comboBoxLabel = QtWidgets.QLabel(self, objectName='type_combobox_label') - comboBoxLabel.setText('Type') + comboBoxLabel = QtWidgets.QLabel('&Type', self, objectName='type_combobox_label') self.addWidget(comboBoxLabel) combobox = ComboBox(self, objectName='type_switch') + comboBoxLabel.setBuddy(combobox) combobox.setEditable(False) - combobox.setFocusPolicy(QtCore.Qt.StrongFocus) - combobox.setScrollEnabled(True) + combobox.setModel(self.types) + combobox.setFocusPolicy(QtCore.Qt.FocusPolicy.StrongFocus) combobox.addItem('') - - sortedItems = sorted(self.project.getDatatypeIRIs(), key=str) - combobox.addItems([str(x) for x in sortedItems]) + # Declared or used first + for d in self.datatypes: + self.types.appendRow(QtGui.QStandardItem(self.iconValue, str(d))) + # Remaining not used + for d in OWL2Datatype: + if d.value not in self.datatypes: + self.types.appendRow(QtGui.QStandardItem(self.iconValue, str(d.value))) if not self.assertion: combobox.setCurrentText('') else: @@ -179,15 +199,14 @@ def __init__( else: combobox.setCurrentText('') self.addWidget(combobox) - connect(combobox.currentIndexChanged,self.onTypeSwitched) + connect(combobox.currentIndexChanged, self.onTypeSwitched) - comboBoxLabel = QtWidgets.QLabel(self, objectName='lang_combobox_label') - comboBoxLabel.setText('Lang') + comboBoxLabel = QtWidgets.QLabel('&Lang', self, objectName='lang_combobox_label') self.addWidget(comboBoxLabel) combobox = ComboBox(self, objectName='lang_switch') + comboBoxLabel.setBuddy(combobox) combobox.setEditable(True) - combobox.setFocusPolicy(QtCore.Qt.StrongFocus) - combobox.setScrollEnabled(True) + combobox.setFocusPolicy(QtCore.Qt.FocusPolicy.StrongFocus) combobox.addItem('') combobox.addItems([x for x in self.project.getLanguages()]) if not self.assertion: @@ -198,10 +217,9 @@ def __init__( else: combobox.setCurrentText('') self.addWidget(combobox) + connect(combobox.editTextChanged, self.onLangChanged) formlayout = QtWidgets.QFormLayout(self) - #formlayout.addRow(self.widget('subject_combobox_label'), self.widget('subject_switch')) - #formlayout.addRow(self.widget('property_combobox_label'), self.widget('property_switch')) formlayout.addRow(self.widget('value_textedit')) formlayout.addRow(self.widget('type_combobox_label'), self.widget('type_switch')) formlayout.addRow(self.widget('lang_combobox_label'), self.widget('lang_switch')) @@ -224,8 +242,8 @@ def __init__( ontPrefix = self.project.ontologyPrefix if ontPrefix is not None: combobox.setCurrentText( - ontPrefix + ':' + ' <' + self.project.getNamespace(ontPrefix) + '>' - ) + ontPrefix + ':' + ' <' + self.project.getNamespace(ontPrefix) + '>' + ) else: combobox.setCurrentText('') self.addWidget(combobox) @@ -294,6 +312,14 @@ def __init__( layout.addWidget(self.widget('confirmation_widget'), 0, QtCore.Qt.AlignRight) self.setLayout(layout) + typeCombo = self.widget('type_switch') + langCombo = self.widget('lang_switch') + if langCombo.currentText(): + typeCombo.setStyleSheet("background: #808080") + typeCombo.setEnabled(False) + if typeCombo.currentText(): + langCombo.setStyleSheet("background: #808080") + langCombo.setEnabled(False) self.setMinimumSize(740, 380) self.setWindowTitle('Annotation assertion builder <{}>'.format(str(iri))) self.redraw() @@ -397,13 +423,26 @@ def onPropertySwitched(self, index): @QtCore.pyqtSlot(int) def onTypeSwitched(self, index): - typeIRI = self.widget('type_switch').itemText(index) - if not self.project.canAddLanguageTag(typeIRI): - self.widget('lang_switch').setStyleSheet("background:#808080") - self.widget('lang_switch').setEnabled(False) + typeCombo: QtWidgets.QComboBox = self.widget('type_switch') + langCombo: QtWidgets.QComboBox = self.widget('lang_switch') + langCombo.setCurrentText('') + if typeCombo.itemText(index): + langCombo.setStyleSheet("background: #808080") + langCombo.setEnabled(False) else: - self.widget('lang_switch').setStyleSheet("background:#FFFFFF") - self.widget('lang_switch').setEnabled(True) + langCombo.setStyleSheet("background: #FFFFFF") + langCombo.setEnabled(True) + + @QtCore.pyqtSlot(str) + def onLangChanged(self, text): + typeCombo: QtWidgets.QComboBox = self.widget('type_switch') + typeCombo.setCurrentText('') + if text: + typeCombo.setStyleSheet("background: #808080") + typeCombo.setEnabled(False) + else: + typeCombo.setStyleSheet("background: #FFFFFF") + typeCombo.setEnabled(True) @QtCore.pyqtSlot(int) def onPrefixChanged(self, _): @@ -425,9 +464,7 @@ def accept(self): propertyIRI = self.project.getIRI(propertyStr) activeTab = self.widget('main_widget').currentWidget() if activeTab is self.widget('literal_widget'): - value = self.widget('value_textedit').toPlainText() - if not value: - value = ' ' + value = self.widget('value_textedit').toPlainText().strip() typeStr = self.widget('type_switch').currentText().strip() typeIRI = self.project.getIRI(typeStr) if typeStr else None if self.widget('lang_switch').isEnabled(): @@ -435,6 +472,8 @@ def accept(self): language = langStr if langStr else None if language and language not in self.project.getLanguages(): self.project.addLanguageTag(language) + else: + language = None else: value = self.widget('full_iri_field').value() try: @@ -452,7 +491,7 @@ def accept(self): return if not self.assertion: - annAss = AnnotationAssertion(subjectIRI,propertyIRI,value,typeIRI,language) + annAss = AnnotationAssertion(subjectIRI, propertyIRI, value, typeIRI, language) command = CommandIRIAddAnnotationAssertion(self.project, subjectIRI, annAss) self.session.undostack.push(command) self.sgnAnnotationAssertionAccepted.emit(annAss) From a43154148f2a4b6df666382bceb78b4588a13aed Mon Sep 17 00:00:00 2001 From: Manuel Namici Date: Mon, 18 Nov 2024 19:45:43 +0100 Subject: [PATCH 4/8] ui: annotation: drop the redraw slot We already set the UI properly in the constructor, so there is no need for such slot. --- eddy/ui/annotation.py | 74 ------------------------------------------- 1 file changed, 74 deletions(-) diff --git a/eddy/ui/annotation.py b/eddy/ui/annotation.py index d0554048..1350e873 100644 --- a/eddy/ui/annotation.py +++ b/eddy/ui/annotation.py @@ -322,85 +322,11 @@ def __init__( langCombo.setEnabled(False) self.setMinimumSize(740, 380) self.setWindowTitle('Annotation assertion builder <{}>'.format(str(iri))) - self.redraw() ############################################# # SLOTS ################################# - @QtCore.pyqtSlot() - def redraw(self): - combobox = self.widget('property_switch') - combobox.clear() - combobox.addItem('') - sortedItems = sorted(self.project.getAnnotationPropertyIRIs(), key=str) - combobox.addItems([str(x) for x in sortedItems]) - if not self.assertion: - combobox.setCurrentText('') - else: - combobox.setCurrentText(str(self.assertion.assertionProperty)) - - textArea = self.widget('value_textedit') - if self.assertion and not self.assertion.isIRIValued(): - textArea.setText(str(self.assertion.value)) - else: - textArea.setText('') - - combobox = self.widget('type_switch') - combobox.clear() - combobox.addItem('') - sortedItems = sorted(self.project.getDatatypeIRIs(), key=str) - combobox.addItems([str(x) for x in sortedItems]) - if not self.assertion or self.assertion.isIRIValued(): - combobox.setCurrentText('') - else: - if self.assertion.datatype: - combobox.setCurrentText(str(self.assertion.datatype)) - else: - combobox.setCurrentText('') - - combobox = self.widget('lang_switch') - combobox.clear() - combobox.addItem('') - combobox.addItems([x for x in self.project.getLanguages()]) - if not self.assertion or self.assertion.isIRIValued(): - combobox.setCurrentText('') - else: - if self.assertion.language: - combobox.setCurrentText(str(self.assertion.language)) - else: - combobox.setCurrentText('') - - combobox = self.widget('iri_prefix_switch') - combobox.clear() - combobox.addItem('') - combobox.addItems( - [x + ':' + ' <' + y + '>' for x, y in self.project.prefixDictItems()]) - - shortest = None - if self.assertion and self.assertion.isIRIValued(): - shortest = self.project.getShortestPrefixedForm(self.assertion.value) - - if shortest: - combobox.setCurrentText( - shortest.prefix + ':' + ' <' + self.project.getNamespace(shortest.prefix) + '>') - else: - combobox.setCurrentText('') - - inputField = self.widget('iri_input_field') - if shortest: - inputField.setText(shortest.suffix) - elif self.assertion and self.assertion.isIRIValued(): - inputField.setText(str(self.assertion.value)) - else: - inputField.setText('') - - fullIriField = self.widget('full_iri_field') - if self.assertion and self.assertion.isIRIValued(): - fullIriField.setText(str(self.assertion.value)) - else: - fullIriField.setText('') - @QtCore.pyqtSlot(int) def onSubjectSwitched(self, index): subIRI = self.widget('subject_switch').itemText(index) From 0ddd3e5658cd60110e66f49f12cce0e1c9b32084 Mon Sep 17 00:00:00 2001 From: Manuel Namici Date: Mon, 18 Nov 2024 21:54:25 +0100 Subject: [PATCH 5/8] ui: annotation: align annotation builder with assertion builder --- eddy/ui/annotation.py | 272 +++++++++++++++++++++++++++++------------- 1 file changed, 189 insertions(+), 83 deletions(-) diff --git a/eddy/ui/annotation.py b/eddy/ui/annotation.py index 1350e873..1e49ee11 100644 --- a/eddy/ui/annotation.py +++ b/eddy/ui/annotation.py @@ -463,40 +463,68 @@ def __init__( self.edge = edge self.annotation = annotation - comboBoxLabel = QtWidgets.QLabel(self, objectName='property_combobox_label') - comboBoxLabel.setText('Property') + 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') + + # Occurrences in diagrams + self.individuals = sorted(self.project.itemIRIs(Item.IndividualNode), key=str) + self.datatypes = sorted(self.project.itemIRIs(Item.ValueDomainNode), key=str) + self.annotations = sorted(self.project.getAnnotationPropertyIRIs(), key=str) + + self.predicates = QtGui.QStandardItemModel(self) + self.types = QtGui.QStandardItemModel(self) + + comboBoxLabel = QtWidgets.QLabel('&Property', self, objectName='property_combobox_label') self.addWidget(comboBoxLabel) combobox = ComboBox(self, objectName='property_switch') - combobox.setEditable(False) - combobox.setFocusPolicy(QtCore.Qt.StrongFocus) - combobox.setScrollEnabled(True) + comboBoxLabel.setBuddy(combobox) + combobox.setModel(self.predicates) + combobox.setFocusPolicy(QtCore.Qt.FocusPolicy.StrongFocus) combobox.addItem('') - sortedItems = sorted(self.project.getAnnotationPropertyIRIs(), key=str) - combobox.addItems([str(x) for x in sortedItems]) + for p in self.annotations: + self.predicates.appendRow(QtGui.QStandardItem(str(p))) if not self.annotation: combobox.setCurrentText('') + elif self.annotation.assertionProperty not in self.annotations: + combobox.addItem(str(self.annotation.assertionProperty)) + combobox.setCurrentText(str(self.annotation.assertionProperty)) + combobox.setEnabled(False) else: combobox.setCurrentText(str(self.annotation.assertionProperty)) self.addWidget(combobox) connect(combobox.currentIndexChanged, self.onPropertySwitched) + valueLabel = QtWidgets.QLabel('Value', self, objectName='value_label') + self.addWidget(valueLabel) + + ############################################# + # LITERAL TAB + ################################# + textArea = QtWidgets.QTextEdit(self, objectName='value_textedit') if self.annotation: if self.annotation.value: textArea.setText(str(self.annotation.value)) self.addWidget(textArea) - comboBoxLabel = QtWidgets.QLabel(self, objectName='type_combobox_label') - comboBoxLabel.setText('Type') + comboBoxLabel = QtWidgets.QLabel('&Type', self, objectName='type_combobox_label') self.addWidget(comboBoxLabel) combobox = ComboBox(self, objectName='type_switch') + comboBoxLabel.setBuddy(combobox) combobox.setEditable(False) - combobox.setFocusPolicy(QtCore.Qt.StrongFocus) - combobox.setScrollEnabled(True) + combobox.setModel(self.types) + combobox.setFocusPolicy(QtCore.Qt.FocusPolicy.StrongFocus) combobox.addItem('') - - sortedItems = sorted(self.project.getDatatypeIRIs(), key=str) - combobox.addItems([str(x) for x in sortedItems]) + # Declared or used first + for d in self.datatypes: + self.types.appendRow(QtGui.QStandardItem(self.iconValue, str(d))) + # Remaining not used + for d in OWL2Datatype: + if d.value not in self.datatypes: + self.types.appendRow(QtGui.QStandardItem(self.iconValue, str(d.value))) if not self.annotation: combobox.setCurrentText('') else: @@ -507,13 +535,12 @@ def __init__( self.addWidget(combobox) connect(combobox.currentIndexChanged, self.onTypeSwitched) - comboBoxLabel = QtWidgets.QLabel(self, objectName='lang_combobox_label') - comboBoxLabel.setText('Lang') + comboBoxLabel = QtWidgets.QLabel('&Lang', self, objectName='lang_combobox_label') self.addWidget(comboBoxLabel) combobox = ComboBox(self, objectName='lang_switch') + comboBoxLabel.setBuddy(combobox) combobox.setEditable(True) - combobox.setFocusPolicy(QtCore.Qt.StrongFocus) - combobox.setScrollEnabled(True) + combobox.setFocusPolicy(QtCore.Qt.FocusPolicy.StrongFocus) combobox.addItem('') combobox.addItems([x for x in self.project.getLanguages()]) if not self.annotation: @@ -524,6 +551,63 @@ def __init__( else: combobox.setCurrentText('') self.addWidget(combobox) + connect(combobox.editTextChanged, self.onLangChanged) + + formlayout = QtWidgets.QFormLayout(self) + formlayout.addRow(self.widget('value_textedit')) + formlayout.addRow(self.widget('type_combobox_label'), self.widget('type_switch')) + formlayout.addRow(self.widget('lang_combobox_label'), self.widget('lang_switch')) + widget = QtWidgets.QWidget() + widget.setLayout(formlayout) + widget.setObjectName('literal_widget') + self.addWidget(widget) + + ############################################# + # IRI TAB + ################################# + + comboBoxLabel = getIRIPrefixComboBoxLabel(self) + self.addWidget(comboBoxLabel) + + combobox = getIRIPrefixComboBox(self) + combobox.clear() + combobox.addItem('') + combobox.addItems([x + ':' + ' <' + y + '>' for x, y in self.project.prefixDictItems()]) + ontPrefix = self.project.ontologyPrefix + if ontPrefix is not None: + combobox.setCurrentText( + ontPrefix + ':' + ' <' + self.project.getNamespace(ontPrefix) + '>' + ) + else: + combobox.setCurrentText('') + self.addWidget(combobox) + + inputLabel = getInputLabel(self) + self.addWidget(inputLabel) + + inputField = getInputField(self) + inputField.setText('') + self.addWidget(inputField) + + fullIriLabel = getFullIRILabel(self) + self.addWidget(fullIriLabel) + + fullIriField = getFullIRIField(self) + fullIriField.setText('') + self.addWidget(fullIriField) + + formlayout2 = QtWidgets.QFormLayout() + formlayout2.addRow(self.widget('iri_prefix_combobox_label'), + self.widget('iri_prefix_switch')) + formlayout2.addRow(self.widget('input_field_label'), self.widget('iri_input_field')) + formlayout2.addRow(self.widget('full_iri_label'), self.widget('full_iri_field')) + widget2 = QtWidgets.QWidget() + widget2.setLayout(formlayout2) + widget2.setObjectName('iri_widget') + self.addWidget(widget2) + + connect(self.widget('iri_prefix_switch').currentIndexChanged, self.onPrefixChanged) + connect(self.widget('iri_input_field').textChanged, self.onInputChanged) ############################################# # CONFIRMATION BOX @@ -540,63 +624,43 @@ def __init__( connect(confirmation.accepted, self.accept) connect(confirmation.rejected, self.reject) - formlayout = QtWidgets.QFormLayout(self) - formlayout.addRow(self.widget('property_combobox_label'), self.widget('property_switch')) - formlayout.addRow(self.widget('value_textedit')) - formlayout.addRow(self.widget('type_combobox_label'), self.widget('type_switch')) - formlayout.addRow(self.widget('lang_combobox_label'), self.widget('lang_switch')) - formlayout.addRow(self.widget('confirmation_widget')) + ############################################# + # MAIN WIDGET + ################################# + + main_widget = QtWidgets.QTabWidget(self, objectName='main_widget') + main_widget.addTab(self.widget('literal_widget'), 'Literal') + main_widget.addTab(self.widget('iri_widget'), 'IRI') + if self.annotation and self.annotation.isIRIValued(): + main_widget.setCurrentWidget(self.widget('iri_widget')) + self.addWidget(main_widget) + + layout = QtWidgets.QVBoxLayout() + layout.setContentsMargins(10, 10, 10, 10) + layout.addWidget(self.widget('subject_combobox_label')) + layout.addWidget(self.widget('subject_switch')) + layout.addWidget(self.widget('property_combobox_label')) + layout.addWidget(self.widget('property_switch')) + layout.addWidget(self.widget('value_label')) + layout.addWidget(self.widget('main_widget')) + layout.addWidget(self.widget('confirmation_widget'), 0, QtCore.Qt.AlignRight) + self.setLayout(layout) + typeCombo = self.widget('type_switch') + langCombo = self.widget('lang_switch') + if langCombo.currentText(): + typeCombo.setStyleSheet("background: #808080") + typeCombo.setEnabled(False) + if typeCombo.currentText(): + langCombo.setStyleSheet("background: #808080") + langCombo.setEnabled(False) self.setMinimumSize(740, 380) self.setWindowTitle('Annotation builder <{}>'.format(str(edge))) - self.redraw() ############################################# # SLOTS ################################# - @QtCore.pyqtSlot() - def redraw(self): - combobox = self.widget('property_switch') - combobox.clear() - combobox.addItem('') - sortedItems = sorted(self.project.getAnnotationPropertyIRIs(), key=str) - combobox.addItems([str(x) for x in sortedItems]) - if not self.annotation: - combobox.setCurrentText('') - else: - combobox.setCurrentText(str(self.annotation.assertionProperty)) - - textArea = self.widget('value_textedit') - if self.annotation: - if self.annotation.value: - textArea.setText(str(self.annotation.value)) - - combobox = self.widget('type_switch') - combobox.clear() - combobox.addItem('') - sortedItems = sorted(self.project.getDatatypeIRIs(), key=str) - combobox.addItems([str(x) for x in sortedItems]) - if not self.annotation: - combobox.setCurrentText('') - else: - if self.annotation.datatype: - combobox.setCurrentText(str(self.annotation.datatype)) - else: - combobox.setCurrentText('') - - combobox = self.widget('lang_switch') - combobox.clear() - combobox.addItem('') - combobox.addItems([x for x in self.project.getLanguages()]) - if not self.annotation: - combobox.setCurrentText('') - else: - if self.annotation.language: - combobox.setCurrentText(str(self.annotation.language)) - else: - combobox.setCurrentText('') - @QtCore.pyqtSlot(int) def onPropertySwitched(self, index): propIRI = self.widget('property_switch').itemText(index) @@ -605,28 +669,70 @@ def onPropertySwitched(self, index): @QtCore.pyqtSlot(int) def onTypeSwitched(self, index): - typeIRI = self.widget('type_switch').itemText(index) - if not self.project.canAddLanguageTag(typeIRI): - self.widget('lang_switch').setStyleSheet("background:#808080") - self.widget('lang_switch').setEnabled(False) + typeCombo: QtWidgets.QComboBox = self.widget('type_switch') + langCombo: QtWidgets.QComboBox = self.widget('lang_switch') + langCombo.setCurrentText('') + if typeCombo.itemText(index): + langCombo.setStyleSheet("background: #808080") + langCombo.setEnabled(False) + else: + langCombo.setStyleSheet("background: #FFFFFF") + langCombo.setEnabled(True) + + @QtCore.pyqtSlot(str) + def onLangChanged(self, text): + typeCombo: QtWidgets.QComboBox = self.widget('type_switch') + typeCombo.setCurrentText('') + if text: + typeCombo.setStyleSheet("background: #808080") + typeCombo.setEnabled(False) else: - self.widget('lang_switch').setStyleSheet("background:#FFFFFF") - self.widget('lang_switch').setEnabled(True) + typeCombo.setStyleSheet("background: #FFFFFF") + typeCombo.setEnabled(True) + + @QtCore.pyqtSlot(int) + def onPrefixChanged(self, _): + self.onInputChanged('') + + @QtCore.pyqtSlot(str) + def onInputChanged(self, _): + prefix = self.widget('iri_prefix_switch').currentText() + input = self.widget('iri_input_field').value() + resolvedPrefix = resolvePrefix(self.project, prefix) + fullIri = '{}{}'.format(resolvedPrefix, input) + self.widget('full_iri_field').setValue(fullIri) @QtCore.pyqtSlot() def accept(self): propertyStr = self.widget('property_switch').currentText().strip() propertyIRI = self.project.getIRI(propertyStr) - value = self.widget('value_textedit').toPlainText() - if not value: - value = ' ' - typeStr = self.widget('type_switch').currentText().strip() - typeIRI = self.project.getIRI(typeStr) if typeStr else None - if self.widget('lang_switch').isEnabled(): - langStr = self.widget('lang_switch').currentText().strip() - language = langStr if langStr else None - if language and language not in self.project.getLanguages(): - self.project.addLanguageTag(language) + activeTab = self.widget('main_widget').currentWidget() + if activeTab is self.widget('literal_widget'): + value = self.widget('value_textedit').toPlainText().strip() + typeStr = self.widget('type_switch').currentText().strip() + typeIRI = self.project.getIRI(typeStr) if typeStr else None + if self.widget('lang_switch').isEnabled(): + langStr = self.widget('lang_switch').currentText().strip() + language = langStr if langStr else None + if language and language not in self.project.getLanguages(): + self.project.addLanguageTag(language) + else: + language = None + else: + value = self.widget('full_iri_field').value() + try: + parse(value, rule='IRI') + value = self.project.getIRI(value) + typeIRI = self.project.getIRI('http://www.w3.org/2001/XMLSchema#anyURI') + language = None + except ValueError: + dialog = QtWidgets.QMessageBox( + QtWidgets.QMessageBox.Warning, + 'IRI Definition Error', + 'The input string is not a valid IRI', + parent=self) + dialog.open() + return if not self.annotation: annotation = Annotation(propertyIRI, value, typeIRI, language) command = CommandEdgeAddAnnotation(self.project, self.edge, annotation) From 20e9b366891ce775a52c27eaa0e9f4944bb9e339 Mon Sep 17 00:00:00 2001 From: Manuel Namici Date: Mon, 18 Nov 2024 22:48:55 +0100 Subject: [PATCH 6/8] core: exporters: graphol_iri: export all IRIs known to the project This includes datatypes, facets, and top/bottom IRIs since we want to enable support for managing non-graphical IRI in the project. Note that due to this, when selecting a subset of the diagrams you stll get the IRIs of those, as there is no way to distinguish between those coming for external sources and those from excluded diagrams. --- eddy/core/exporters/graphol_iri.py | 58 ++++++++++++++++++++---------- 1 file changed, 39 insertions(+), 19 deletions(-) diff --git a/eddy/core/exporters/graphol_iri.py b/eddy/core/exporters/graphol_iri.py index d1794df2..428d50fe 100644 --- a/eddy/core/exporters/graphol_iri.py +++ b/eddy/core/exporters/graphol_iri.py @@ -1,3 +1,37 @@ +# -*- coding: utf-8 -*- + +########################################################################## +# # +# Eddy: a graphical editor for the specification of Graphol ontologies # +# Copyright (C) 2015 Daniele Pantaleone # +# # +# This program is free software: you can redistribute it and/or modify # +# it under the terms of the GNU General Public License as published by # +# the Free Software Foundation, either version 3 of the License, or # +# (at your option) any later version. # +# # +# This program is distributed in the hope that it will be useful, # +# but WITHOUT ANY WARRANTY; without even the implied warranty of # +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # +# GNU General Public License for more details. # +# # +# You should have received a copy of the GNU General Public License # +# along with this program. If not, see . # +# # +# ##################### ##################### # +# # +# Graphol is developed by members of the DASI-lab group of the # +# Dipartimento di Ingegneria Informatica, Automatica e Gestionale # +# A.Ruberti at Sapienza University of Rome: http://www.dis.uniroma1.it # +# # +# - Domenico Lembo # +# - Valerio Santarelli # +# - Domenico Fabio Savo # +# - Daniele Pantaleone # +# - Marco Console # +# # +########################################################################## + import os from PyQt5 import QtXml @@ -13,6 +47,7 @@ LOGGER = getLogger() + class GrapholIRIProjectExporter(AbstractProjectExporter): """ Extends AbstractProjectExporter with facilities to export the structure of a Graphol project. @@ -187,26 +222,11 @@ def getOntologyDomElement(self): irisEl = self.getDomElement('iris') ontologyEl.appendChild(irisEl) - if not self.selectedDiagrams: - for iri in sorted(self.project.iris,key=str): - if (self.project.existIriOccurrence(iri) or iri==self.project.ontologyIRI) and not (iri.isTopBottomEntity() or iri in self.project.getDatatypeIRIs() or iri in self.project.constrainingFacets or iri in self.project.getAnnotationPropertyIRIs()): - iriEl = self.getIriDomElement(iri) - irisEl.appendChild(iriEl) - else: - for iri in sorted(self.project.iris,key=str): - if (self.project.existIriOccurrence(iri) or iri == self.project.ontologyIRI) and not ( - iri.isTopBottomEntity() or iri in self.project.getDatatypeIRIs() or iri in self.project.constrainingFacets or iri in self.project.getAnnotationPropertyIRIs()): - if self.occursInAtLeastOneSelectedDiagrams(iri): - iriEl = self.getIriDomElement(iri) - irisEl.appendChild(iriEl) + for iri in sorted(self.project.iris, key=str): + iriEl = self.getIriDomElement(iri) + irisEl.appendChild(iriEl) return ontologyEl - def occursInAtLeastOneSelectedDiagrams(self,iri): - for diagram in self.selectedDiagrams: - if self.project.iriOccurrences(iri=iri,diagram=diagram): - return True - return False - def getOntologyImportDomElement(self, impOnt): impEl = self.getDomElement('import') impEl.setAttribute('iri', impOnt.ontologyIRI) @@ -742,10 +762,10 @@ def getNodeDomElement(self, node): element.appendChild(geometry) return element - ############################################# # INTERFACE ################################# + def createProjectFile(self): """ Serialize a previously created QDomDocument to disk. From be1c88625779e8d2cd190a4054969b93ebab8311 Mon Sep 17 00:00:00 2001 From: Manuel Namici Date: Tue, 19 Nov 2024 18:07:51 +0100 Subject: [PATCH 7/8] ui: annotation: do not turn iri-valued into literals with anyURI type An IRI value is really an IRI and not a literal with xsd:anyURI type. --- eddy/ui/annotation.py | 93 ++++++++++++++++++++++++------------------- 1 file changed, 52 insertions(+), 41 deletions(-) diff --git a/eddy/ui/annotation.py b/eddy/ui/annotation.py index 1e49ee11..ac742540 100644 --- a/eddy/ui/annotation.py +++ b/eddy/ui/annotation.py @@ -59,16 +59,11 @@ IRI, OWL2Datatype, ) -from eddy.ui.fields import ComboBox -from eddy.ui.iri import ( - getFullIRIField, - getFullIRILabel, - getIRIPrefixComboBox, - getIRIPrefixComboBoxLabel, - getInputField, - getInputLabel, - resolvePrefix, +from eddy.ui.fields import ( + ComboBox, + StringField, ) +from eddy.ui.iri import resolvePrefix if TYPE_CHECKING: from eddy.ui.session import Session @@ -171,9 +166,8 @@ def __init__( ################################# textArea = QtWidgets.QTextEdit(self, objectName='value_textedit') - if self.assertion: - if self.assertion.value: - textArea.setText(str(self.assertion.value)) + if self.assertion and not self.assertion.isIRIValued(): + textArea.setText(str(self.assertion.value)) self.addWidget(textArea) comboBoxLabel = QtWidgets.QLabel('&Type', self, objectName='type_combobox_label') @@ -232,11 +226,12 @@ def __init__( # IRI TAB ################################# - comboBoxLabel = getIRIPrefixComboBoxLabel(self) + comboBoxLabel = QtWidgets.QLabel('Pre&fix', self, objectName='iri_prefix_combobox_label') self.addWidget(comboBoxLabel) - - combobox = getIRIPrefixComboBox(self) - combobox.clear() + combobox = ComboBox(self, objectName='iri_prefix_switch') + comboBoxLabel.setBuddy(combobox) + combobox.setFocusPolicy(QtCore.Qt.StrongFocus) + combobox.setEditable(False) combobox.addItem('') combobox.addItems([x + ':' + ' <' + y + '>' for x, y in self.project.prefixDictItems()]) ontPrefix = self.project.ontologyPrefix @@ -248,18 +243,16 @@ def __init__( combobox.setCurrentText('') self.addWidget(combobox) - inputLabel = getInputLabel(self) + inputLabel = QtWidgets.QLabel('&Input', self, objectName='input_field_label') self.addWidget(inputLabel) - - inputField = getInputField(self) - inputField.setText('') + inputField = StringField('', self, objectName='iri_input_field') + inputLabel.setBuddy(inputField) self.addWidget(inputField) - fullIriLabel = getFullIRILabel(self) + fullIriLabel = QtWidgets.QLabel('Full IRI', self, objectName='full_iri_label') self.addWidget(fullIriLabel) - - fullIriField = getFullIRIField(self) - fullIriField.setText('') + fullIriField = StringField('', self, objectName='full_iri_field') + fullIriField.setReadOnly(True) self.addWidget(fullIriField) formlayout2 = QtWidgets.QFormLayout() @@ -275,6 +268,16 @@ def __init__( connect(self.widget('iri_prefix_switch').currentIndexChanged, self.onPrefixChanged) connect(self.widget('iri_input_field').textChanged, self.onInputChanged) + if self.assertion and self.assertion.isIRIValued(): + prefixed = self.project.getLongestSuffixPrefixedForm(self.assertion.value) + if prefixed: + self.widget('iri_prefix_switch').setCurrentText( + f'{prefixed.prefix}: <{str(self.project.getNamespace(prefixed.prefix))}>' + ) + self.widget('iri_input_field').setText(prefixed.suffix) + else: + self.widget('iri_input_field').setText(str(self.assertion.value)) + ############################################# # CONFIRMATION BOX ################################# @@ -405,7 +408,7 @@ def accept(self): try: parse(value, rule='IRI') value = self.project.getIRI(value) - typeIRI = self.project.getIRI('http://www.w3.org/2001/XMLSchema#anyURI') + typeIRI = None language = None except ValueError: dialog = QtWidgets.QMessageBox( @@ -505,9 +508,8 @@ def __init__( ################################# textArea = QtWidgets.QTextEdit(self, objectName='value_textedit') - if self.annotation: - if self.annotation.value: - textArea.setText(str(self.annotation.value)) + if self.annotation and not self.annotation.isIRIValued(): + textArea.setText(str(self.annotation.value)) self.addWidget(textArea) comboBoxLabel = QtWidgets.QLabel('&Type', self, objectName='type_combobox_label') @@ -566,11 +568,12 @@ def __init__( # IRI TAB ################################# - comboBoxLabel = getIRIPrefixComboBoxLabel(self) + comboBoxLabel = QtWidgets.QLabel('Pre&fix', self, objectName='iri_prefix_combobox_label') self.addWidget(comboBoxLabel) - - combobox = getIRIPrefixComboBox(self) - combobox.clear() + combobox = ComboBox(self, objectName='iri_prefix_switch') + comboBoxLabel.setBuddy(combobox) + combobox.setFocusPolicy(QtCore.Qt.StrongFocus) + combobox.setEditable(False) combobox.addItem('') combobox.addItems([x + ':' + ' <' + y + '>' for x, y in self.project.prefixDictItems()]) ontPrefix = self.project.ontologyPrefix @@ -582,18 +585,16 @@ def __init__( combobox.setCurrentText('') self.addWidget(combobox) - inputLabel = getInputLabel(self) + inputLabel = QtWidgets.QLabel('&Input', self, objectName='input_field_label') self.addWidget(inputLabel) - - inputField = getInputField(self) - inputField.setText('') + inputField = StringField('', self, objectName='iri_input_field') + inputLabel.setBuddy(inputField) self.addWidget(inputField) - fullIriLabel = getFullIRILabel(self) + fullIriLabel = QtWidgets.QLabel('Full IRI', self, objectName='full_iri_label') self.addWidget(fullIriLabel) - - fullIriField = getFullIRIField(self) - fullIriField.setText('') + fullIriField = StringField('', self, objectName='full_iri_field') + fullIriField.setReadOnly(True) self.addWidget(fullIriField) formlayout2 = QtWidgets.QFormLayout() @@ -609,6 +610,16 @@ def __init__( connect(self.widget('iri_prefix_switch').currentIndexChanged, self.onPrefixChanged) connect(self.widget('iri_input_field').textChanged, self.onInputChanged) + if self.annotation and self.annotation.isIRIValued(): + prefixed = self.project.getLongestSuffixPrefixedForm(self.annotation.value) + if prefixed: + self.widget('iri_prefix_switch').setCurrentText( + f'{prefixed.prefix}: <{str(self.project.getNamespace(prefixed.prefix))}>' + ) + self.widget('iri_input_field').setText(prefixed.suffix) + else: + self.widget('iri_input_field').setText(str(self.annotation.value)) + ############################################# # CONFIRMATION BOX ################################# @@ -723,7 +734,7 @@ def accept(self): try: parse(value, rule='IRI') value = self.project.getIRI(value) - typeIRI = self.project.getIRI('http://www.w3.org/2001/XMLSchema#anyURI') + typeIRI = None language = None except ValueError: dialog = QtWidgets.QMessageBox( From 9f28c84016954eb68ef508a6acf8d03513b98dec Mon Sep 17 00:00:00 2001 From: Manuel Namici Date: Tue, 19 Nov 2024 18:41:12 +0100 Subject: [PATCH 8/8] ui: ontology: allow double click to edit an assertion from the table --- eddy/ui/ontology.py | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/eddy/ui/ontology.py b/eddy/ui/ontology.py index ec1fe2b7..99afdade 100644 --- a/eddy/ui/ontology.py +++ b/eddy/ui/ontology.py @@ -464,6 +464,7 @@ def __init__(self, session): table.verticalHeader().setSectionsClickable(False) table.setSelectionBehavior(QtWidgets.QAbstractItemView.SelectRows) #table.setSelectionMode(QAbstractItemView.MultiSelection) + connect(table.cellDoubleClicked, self.onAssertionCellDoubleClicked) self.addWidget(table) selectBtn = QtWidgets.QPushButton('Select All', objectName = 'annotation_assertions_selectall_button') @@ -1045,6 +1046,18 @@ def onAnnotationCellClicked(self,row,column): self.widget('ontology_annotations_delete_button').setEnabled(True) self.widget('ontology_annotations_edit_button').setEnabled(True) + @QtCore.pyqtSlot(int, int) + def onAssertionCellDoubleClicked(self, row: int, _col: int) -> None: + table: QtWidgets.QTableWidget = self.widget('annotation_assertions_table_widget') + assertion = table.item(row, 2).data(QtCore.Qt.ItemDataRole.UserRole) + assertionBuilder = AnnotationAssertionBuilderDialog( + self.session, + self.project.ontologyIRI, + assertion, + ) + connect(assertionBuilder.sgnAnnotationAssertionCorrectlyModified, self.redraw) + assertionBuilder.open() + @QtCore.pyqtSlot(bool) def editOntologyAnnotation(self, _): self.widget('ontology_annotations_edit_button').setEnabled(False)