class EditableNodeProperty(PredicateNodeProperty): """ This class implements the property dialog for label editable predicate nodes. """ def __init__(self, scene, node, parent=None): """ Initialize the editable node properties dialog. :type scene: DiagramScene :type node: AbstractNode :type parent: QWidget """ super().__init__(scene, node, parent) ################################################################################################################ # # # LABEL TAB # # # ################################################################################################################ self.labelWidget = QWidget() self.labelLayout = QFormLayout(self.labelWidget) self.textField = StringField(self.labelWidget) self.textField.setFixedWidth(300) self.textField.setValue(self.node.text()) self.textField.setEnabled(self.node.label.editable) self.labelLayout.addRow('Text', self.textField) self.mainWidget.addTab(self.labelWidget, 'Label') #################################################################################################################### # # # SLOTS # # # #################################################################################################################### def completed(self, code): """ Executed when the dialog is terminated. :type code: int """ if code == QDialog.Accepted: super().completed(code) self.labelEdited() def labelEdited(self): """ Change the label of the node. """ data = self.textField.value().strip() data = data if not isEmpty(data) else self.node.label.template if self.node.text() != data: command = CommandNodeLabelChange(self.scene, self.node, self.node.text(), data) self.scene.undostack.push(command)
class PredicateNodeProperty(NodeProperty): """ This class implements the property dialog for predicate nodes. """ def __init__(self, scene, node, parent=None): """ Initialize the predicate node properties dialog. :type scene: DiagramScene :type node: AbstractNode :type parent: QWidget """ super().__init__(scene, node, parent) meta = scene.meta.metaFor(node.item, node.text()) self.urlField = StringField(self.generalWidget) self.urlField.setFixedWidth(300) self.urlField.setValue(meta.url) self.descriptionField = TextField(self.generalWidget) self.descriptionField.setFixedSize(300, 160) self.descriptionField.setValue(meta.description) self.generalLayout.addRow('URL', self.urlField) self.generalLayout.addRow('Description', self.descriptionField) #################################################################################################################### # # # SLOTS # # # #################################################################################################################### @pyqtSlot(int) def completed(self, code): """ Executed when the dialog is terminated. :type code: int """ if code == QDialog.Accepted: super().completed(code) self.metaDataChanged() def metaDataChanged(self): """ Change the url and description of the node. """ meta = self.scene.meta.metaFor(self.node.item, self.node.text()) copy = meta.copy() copy.description = self.descriptionField.value() copy.url = self.urlField.value() if copy != meta: command = CommandNodeChangeMeta(self.scene, self.node, meta, copy) self.scene.undostack.push(command)
class NewProjectDialog(QtWidgets.QDialog): """ This class is used to display a modal window to enter new project specific data. """ def __init__(self, parent=None): """ Initialize the project dialog. :type parent: QWidget """ super().__init__(parent) ############################################# # FORM AREA ################################# settings = QtCore.QSettings(ORGANIZATION, APPNAME) self.workspace = expandPath( settings.value('workspace/home', WORKSPACE, str)) self.workspace = '{0}{1}'.format(rstrip(self.workspace, os.path.sep), os.path.sep) self.nameLabel = QtWidgets.QLabel(self) self.nameLabel.setFont(Font('Roboto', 12)) self.nameLabel.setText('Name') self.nameField = StringField(self) self.nameField.setFont(Font('Roboto', 12)) self.nameField.setMinimumWidth(400) self.nameField.setMaxLength(64) self.prefixLabel = QtWidgets.QLabel(self) self.prefixLabel.setFont(Font('Roboto', 12)) self.prefixLabel.setText('Prefix') self.prefixField = StringField(self) self.prefixField.setFont(Font('Roboto', 12)) self.prefixField.setMinimumWidth(400) self.iriLabel = QtWidgets.QLabel(self) self.iriLabel.setFont(Font('Roboto', 12)) self.iriLabel.setText('IRI') self.iriField = StringField(self) self.iriField.setFont(Font('Roboto', 12)) self.iriField.setMinimumWidth(400) connect(self.prefixField.textChanged, self.doAcceptForm) connect(self.iriField.textChanged, self.doAcceptForm) connect(self.nameField.textChanged, self.doAcceptForm) connect(self.nameField.textChanged, self.onNameFieldChanged) self.pathLabel = QtWidgets.QLabel(self) self.pathLabel.setFont(Font('Roboto', 12)) self.pathLabel.setText('Location') self.pathField = StringField(self) self.pathField.setFont(Font('Roboto', 12)) self.pathField.setMinimumWidth(400) self.pathField.setReadOnly(True) self.pathField.setFocusPolicy(QtCore.Qt.NoFocus) self.pathField.setValue(self.workspace) spacer = QtWidgets.QFrame() spacer.setFrameShape(QtWidgets.QFrame.HLine) spacer.setFrameShadow(QtWidgets.QFrame.Sunken) self.formWidget = QtWidgets.QWidget(self) self.formLayout = QtWidgets.QFormLayout(self.formWidget) self.formLayout.addRow(self.nameLabel, self.nameField) self.formLayout.addRow(self.prefixLabel, self.prefixField) self.formLayout.addRow(self.iriLabel, self.iriField) self.formLayout.addWidget(spacer) self.formLayout.addRow(self.pathLabel, self.pathField) ############################################# # CONFIRMATION AREA ################################# self.confirmationBox = QtWidgets.QDialogButtonBox( QtCore.Qt.Horizontal, self) self.confirmationBox.addButton(QtWidgets.QDialogButtonBox.Ok) self.confirmationBox.addButton(QtWidgets.QDialogButtonBox.Cancel) self.confirmationBox.setContentsMargins(10, 0, 10, 10) self.confirmationBox.setFont(Font('Roboto', 12)) self.confirmationBox.button( QtWidgets.QDialogButtonBox.Ok).setEnabled(False) ############################################# # SETUP DIALOG LAYOUT ################################# self.caption = QtWidgets.QLabel(self) self.caption.setFont(Font('Roboto', 12)) self.caption.setContentsMargins(8, 0, 8, 0) self.caption.setProperty('class', 'invalid') self.caption.setVisible(False) self.gridLayout = QtWidgets.QVBoxLayout(self) self.gridLayout.setContentsMargins(0, 0, 0, 0) self.gridLayout.addWidget(self.formWidget) self.gridLayout.addWidget(self.caption) self.gridLayout.addWidget(self.confirmationBox, 0, QtCore.Qt.AlignRight) self.setFixedSize(self.sizeHint()) self.setWindowIcon(QtGui.QIcon(':/icons/128/ic_eddy')) self.setWindowTitle('New project') connect(self.confirmationBox.accepted, self.accept) connect(self.confirmationBox.rejected, self.reject) ############################################# # INTERFACE ################################# def iri(self): """ Returns the value of the iri field (trimmed). :rtype: str """ return self.iriField.value() def name(self): """ Returns the value of the name field (trimmed). :rtype: str """ return self.nameField.value() def path(self): """ Returns the value of the path field (expanded). :rtype: str """ return expandPath(self.pathField.value()) def prefix(self): """ Returns the value of the prefix field (trimmed). :rtype: str """ return self.prefixField.value() ############################################# # SLOTS ################################# @QtCore.pyqtSlot() def accept(self): """ Accept the project form and creates a new empty project. """ project = Project(name=self.name(), path=self.path(), prefix=self.prefix(), iri=self.iri(), profile=OWL2Profile()) worker = GrapholProjectExporter(project) worker.run() super().accept() @QtCore.pyqtSlot() def doAcceptForm(self): """ Validate project settings. """ caption = '' enabled = True ############################################# # CHECK NAME ################################# if not self.name(): caption = '' enabled = False else: if isdir(self.path()): caption = "Project '{0}' already exists!".format(self.name()) enabled = False elif not isPathValid(self.path()): caption = "'{0}' is not a valid project name!".format( self.name()) enabled = False ############################################# # CHECK PREFIX ################################# if enabled: if not self.prefix(): caption = '' enabled = False ############################################# # CHECK IRI ################################# if enabled: if not self.iri(): caption = '' enabled = False self.caption.setText(caption) self.caption.setVisible(not isEmpty(caption)) self.confirmationBox.button( QtWidgets.QDialogButtonBox.Ok).setEnabled(enabled) self.setFixedSize(self.sizeHint()) @QtCore.pyqtSlot(str) def onNameFieldChanged(self, name): """ Update the project location field to reflect the new project name. :type name: str """ self.pathField.setValue('{0}{1}'.format(self.workspace, name.strip()))
class ValueNodeProperty(NodeProperty): """ This class implements the property dialog for value nodes. """ def __init__(self, diagram, node, session): """ Initialize the node properties dialog. :type diagram: Diagram :type node: AbstractNode :type session: Session """ super().__init__(diagram, node, session) ############################################# # VALUE TAB ################################# self.datatypeLabel = QtWidgets.QLabel(self) self.datatypeLabel.setFont(Font('Roboto', 12)) self.datatypeLabel.setText('Datatype') self.datatypeField = ComboBox(self) self.datatypeField.setFixedWidth(200) self.datatypeField.setFocusPolicy(QtCore.Qt.StrongFocus) self.datatypeField.setFont(Font('Roboto', 12)) for datatype in Datatype: self.datatypeField.addItem(datatype.value, datatype) datatype = self.node.datatype for i in range(self.datatypeField.count()): if self.datatypeField.itemData(i) is datatype: self.datatypeField.setCurrentIndex(i) break else: self.datatypeField.setCurrentIndex(0) self.valueLabel = QtWidgets.QLabel(self) self.valueLabel.setFont(Font('Roboto', 12)) self.valueLabel.setText('Value') self.valueField = StringField(self) self.valueField.setFixedWidth(200) self.valueField.setFont(Font('Roboto', 12)) self.valueField.setValue(self.node.value) self.valueWidget = QtWidgets.QWidget() self.valueLayout = QtWidgets.QFormLayout(self.valueWidget) self.valueLayout.addRow(self.datatypeLabel, self.datatypeField) self.valueLayout.addRow(self.valueLabel, self.valueField) self.mainWidget.addTab(self.valueWidget, 'Datatype') ############################################# # SLOTS ################################# @QtCore.pyqtSlot() def complete(self): """ Executed when the dialog is accepted. """ commands = [self.positionChanged(), self.valueChanged()] if any(commands): self.session.undostack.beginMacro('edit {0} properties'.format( self.node.name)) for command in commands: if command: self.session.undostack.push(command) self.session.undostack.endMacro() super().accept() ############################################# # AUXILIARY METHODS ################################# def valueChanged(self): """ Change the value of the node. :rtype: QUndoCommand """ datatype = self.datatypeField.currentData() value = self.valueField.value() data = self.node.compose(value, datatype) if self.node.text() != data: return CommandLabelChange(self.diagram, self.node, self.node.text(), data) return None
class PredicateNodeProperty(NodeProperty): """ This class implements the property dialog for predicate nodes. Note that this dialog window is not used for value-domain nodes even though they are predicate nodes. """ def __init__(self, diagram, node, session): """ Initialize the node properties dialog. :type diagram: Diagram :type node: AbstractNode :type session: Session """ super().__init__(diagram, node, session) meta = diagram.project.meta(node.type(), node.text()) self.urlLabel = QtWidgets.QLabel(self) self.urlLabel.setFont(Font('Roboto', 12)) self.urlLabel.setText('URL') self.urlField = StringField(self) self.urlField.setFixedWidth(300) self.urlField.setFont(Font('Roboto', 12)) self.urlField.setValue(meta.get(K_URL, '')) self.descriptionLabel = QtWidgets.QLabel(self) self.descriptionLabel.setFont(Font('Roboto', 12)) self.descriptionLabel.setText('Description') self.descriptionField = TextField(self) self.descriptionField.setFixedSize(300, 160) self.descriptionField.setFont(Font('Roboto', 12)) self.descriptionField.setValue(meta.get(K_DESCRIPTION, '')) self.generalLayout.addRow(self.urlLabel, self.urlField) self.generalLayout.addRow(self.descriptionLabel, self.descriptionField) ############################################# # LABEL TAB ################################# self.textLabel = QtWidgets.QLabel(self) self.textLabel.setFont(Font('Roboto', 12)) self.textLabel.setText('Text') self.textField = StringField(self) self.textField.setFixedWidth(300) self.textField.setFont(Font('Roboto', 12)) self.textField.setValue(self.node.text()) self.refactorLabel = QtWidgets.QLabel(self) self.refactorLabel.setFont(Font('Roboto', 12)) self.refactorLabel.setText('Refactor') self.refactorField = CheckBox(self) self.refactorField.setFont(Font('Roboto', 12)) self.refactorField.setChecked(False) if node.type() in { Item.AttributeNode, Item.ConceptNode, Item.RoleNode }: if node.special() is not None: self.refactorField.setEnabled(False) self.labelWidget = QtWidgets.QWidget() self.labelLayout = QtWidgets.QFormLayout(self.labelWidget) self.labelLayout.addRow(self.textLabel, self.textField) self.labelLayout.addRow(self.refactorLabel, self.refactorField) self.mainWidget.addTab(self.labelWidget, 'Label') ############################################# # SLOTS ################################# @QtCore.pyqtSlot() def complete(self): """ Executed when the dialog is accepted. """ commands = [self.positionChanged(), self.metaDataChanged()] commands.extend(self.textChanged()) if any(commands): self.session.undostack.beginMacro('edit {0} properties'.format( self.node.name)) for command in commands: if command: self.session.undostack.push(command) self.session.undostack.endMacro() super().accept() ############################################# # AUXILIARY METHODS ################################# def metaDataChanged(self): """ Change the url and description of the node. :rtype: QUndoCommand """ undo = self.diagram.project.meta(self.node.type(), self.node.text()) redo = undo.copy() redo[K_DESCRIPTION] = self.descriptionField.value() redo[K_URL] = self.urlField.value() if redo != undo: return CommandNodeSetMeta(self.diagram.project, self.node.type(), self.node.text(), undo, redo) return None def textChanged(self): """ Change the label of the node. :rtype: list """ data = self.textField.value().strip() data = data if not isEmpty(data) else self.node.label.template if self.node.text() != data: if self.refactorField.isChecked(): item = self.node.type() name = self.node.text() project = self.diagram.project return [ CommandLabelChange(n.diagram, n, n.text(), data) for n in project.predicates(item, name) ] return [ CommandLabelChange(self.diagram, self.node, self.node.text(), data) ] return [None]
class ValueForm(QtWidgets.QDialog): """ This class implements the form used to select the Value of an Individual node. """ def __init__(self, node, session): """ Initialize the form dialog. :type node: IndividualNode :type session: Session """ super().__init__(session) self.node = node ############################################# # FORM AREA ################################# self.datatypeLabel = QtWidgets.QLabel(self) self.datatypeLabel.setText('Datatype') self.datatypeField = ComboBox(self) self.datatypeField.setFixedWidth(300) for datatype in sorted(Datatype.forProfile( self.project.profile.type()), key=attrgetter('value')): self.datatypeField.addItem(datatype.value, datatype) self.valueLabel = QtWidgets.QLabel(self) self.valueLabel.setText('Value') self.valueField = StringField(self) self.valueField.setFixedWidth(300) if node.identity() is Identity.Value: self.valueField.setValue(node.value) datatype = node.datatype for i in range(self.datatypeField.count()): if self.datatypeField.itemData(i) is datatype: self.datatypeField.setCurrentIndex(i) break else: self.valueField.setValue('') self.datatypeField.setCurrentIndex(0) self.formWidget = QtWidgets.QWidget(self) self.formLayout = QtWidgets.QFormLayout(self.formWidget) self.formLayout.addRow(self.datatypeLabel, self.datatypeField) self.formLayout.addRow(self.valueLabel, self.valueField) ############################################# # CONFIRMATION AREA ################################# self.confirmationBox = QtWidgets.QDialogButtonBox( QtCore.Qt.Horizontal, self) self.confirmationBox.addButton(QtWidgets.QDialogButtonBox.Ok) self.confirmationBox.addButton(QtWidgets.QDialogButtonBox.Cancel) self.confirmationBox.setContentsMargins(10, 0, 10, 10) ############################################# # SETUP DIALOG LAYOUT ################################# self.mainLayout = QtWidgets.QVBoxLayout(self) self.mainLayout.setContentsMargins(0, 0, 0, 0) self.mainLayout.addWidget(self.formWidget) self.mainLayout.addWidget(self.confirmationBox, 0, QtCore.Qt.AlignRight) self.setFixedSize(self.sizeHint()) self.setWindowIcon(QtGui.QIcon(':/icons/128/ic_eddy')) self.setWindowTitle('Compose value') connect(self.confirmationBox.accepted, self.accept) connect(self.confirmationBox.rejected, self.reject) ############################################# # PROPERTIES ################################# @property def project(self): """ Returns the reference to the active project. :rtype: Project """ return self.session.project @property def session(self): """ Returns the reference to the active session (alias for RefactorNameForm.parent()). :rtype: Session """ return self.parent() ############################################# # SLOTS ################################# @QtCore.pyqtSlot() def accept(self): """ Accepts the form and set the new value. """ # print('>>> ValueForm (accept)') node = self.node diagram = node.diagram datatype = self.datatypeField.currentData() value = self.valueField.value() data = node.compose(value, datatype) if node.text() != data: name = 'change {0} to {1}'.format(node.text(), data) new_prefix = datatype.value[0:datatype.value.index(':')] new_remaining_characters = datatype.value[datatype.value.index(':' ) + 1:len(datatype.value)] new_iri = None for namespace in Namespace: if namespace.name.lower() == new_prefix: new_iri = namespace.value if new_iri is None: LOGGER.error( '***************** failed to assign iri to node *******************' ) return Duplicate_dict_1 = self.project.copy_IRI_prefixes_nodes_dictionaries( self.project.IRI_prefixes_nodes_dict, dict()) Duplicate_dict_2 = self.project.copy_IRI_prefixes_nodes_dictionaries( self.project.IRI_prefixes_nodes_dict, dict()) old_iri = self.project.get_iri_of_node(node) Duplicate_dict_1[old_iri][1].remove(node) Duplicate_dict_1[new_iri][1].add(node) commands = [] commands.append( CommandProjectDisconnectSpecificSignals(self.project)) commands.append( CommandLabelChange(diagram, self.node, self.node.text(), data)) commands.append( CommandNodeSetRemainingCharacters(node.remaining_characters, new_remaining_characters, node, self.project)) commands.append( CommandLabelChange(diagram, self.node, self.node.text(), data)) commands.append(CommandProjectConnectSpecificSignals(self.project)) if any(commands): self.session.undostack.beginMacro( 'edit Forms >> accept() {0}'.format(node)) for command in commands: if command: self.session.undostack.push(command) self.session.undostack.endMacro() super().accept()
class FacetNodeProperty(NodeProperty): """ This class implements the property dialog for facet nodes. """ def __init__(self, diagram, node, session): """ Initialize the node properties dialog. :type diagram: Diagram :type node: AbstractNode :type session: Session """ super().__init__(diagram, node, session) ############################################# # FACET TAB ################################# f1 = lambda x: x.type() is Item.InputEdge f2 = lambda x: x.type() is Item.DatatypeRestrictionNode f3 = lambda x: x.type() is Item.ValueDomainNode admissible = [x for x in Facet] restriction = first( self.node.outgoingNodes(filter_on_edges=f1, filter_on_nodes=f2)) if restriction: valuedomain = first( restriction.incomingNodes(filter_on_edges=f1, filter_on_nodes=f3)) if valuedomain: admissible = Facet.forDatatype(valuedomain.datatype) self.facetLabel = QtWidgets.QLabel(self) self.facetLabel.setText('Facet') self.facetField = ComboBox(self) self.facetField.setFixedWidth(200) self.facetField.setFocusPolicy(QtCore.Qt.StrongFocus) for facet in admissible: self.facetField.addItem(facet.value, facet) facet = self.node.facet for i in range(self.facetField.count()): if self.facetField.itemData(i) is facet: self.facetField.setCurrentIndex(i) break else: self.facetField.setCurrentIndex(0) self.valueLabel = QtWidgets.QLabel(self) self.valueLabel.setText('Value') self.valueField = StringField(self) self.valueField.setFixedWidth(200) self.valueField.setValue(self.node.value) self.facetWidget = QtWidgets.QWidget() self.facetLayout = QtWidgets.QFormLayout(self.facetWidget) self.facetLayout.addRow(self.facetLabel, self.facetField) self.facetLayout.addRow(self.valueLabel, self.valueField) self.mainWidget.addTab(self.facetWidget, 'Facet') ############################################# # SLOTS ################################# @QtCore.pyqtSlot() def complete(self): """ Executed when the dialog is accepted. """ commands = [self.positionChanged(), self.facetChanged()] if any(commands): self.session.undostack.beginMacro('edit {0} properties'.format( self.node.name)) for command in commands: if command: self.session.undostack.push(command) self.session.undostack.endMacro() super().accept() ############################################# # AUXILIARY METHODS ################################# def facetChanged(self): """ Change the facet value of the node of the node. :rtype: QUndoCommand """ data = self.node.compose(self.facetField.currentData(), self.valueField.value()) if self.node.text() != data: return CommandLabelChange(self.diagram, self.node, self.node.text(), data) return None
class ValueNodeProperty(NodeProperty): """ This class implements the property dialog for value nodes. """ def __init__(self, diagram, node, session): """ Initialize the node properties dialog. :type diagram: Diagram :type node: AbstractNode :type session: Session """ super().__init__(diagram, node, session) self.node = node ############################################# # VALUE TAB ################################# self.datatypeLabel = QtWidgets.QLabel(self) self.datatypeLabel.setText('Datatype') self.datatypeField = ComboBox(self) self.datatypeField.setFixedWidth(200) self.datatypeField.setFocusPolicy(QtCore.Qt.StrongFocus) for datatype in Datatype: self.datatypeField.addItem(datatype.value, datatype) datatype = self.node.datatype for i in range(self.datatypeField.count()): if self.datatypeField.itemData(i) is datatype: self.datatypeField.setCurrentIndex(i) break else: self.datatypeField.setCurrentIndex(0) self.valueLabel = QtWidgets.QLabel(self) self.valueLabel.setText('Value') self.valueField = StringField(self) self.valueField.setFixedWidth(200) self.valueField.setValue(self.node.value) self.valueWidget = QtWidgets.QWidget() self.valueLayout = QtWidgets.QFormLayout(self.valueWidget) self.valueLayout.addRow(self.datatypeLabel, self.datatypeField) self.valueLayout.addRow(self.valueLabel, self.valueField) self.mainWidget.addTab(self.valueWidget, 'Datatype') ############################################# # SLOTS ################################# @QtCore.pyqtSlot() def complete(self): """ Executed when the dialog is accepted. """ commands = [self.positionChanged()] commands_value_changed = self.valueChanged() if commands_value_changed is not None: commands.extend(commands_value_changed) if any(commands): self.session.undostack.beginMacro('edit {0} properties'.format( self.node.name)) for command in commands: if command: self.session.undostack.push(command) self.session.undostack.endMacro() super().accept() ############################################# # AUXILIARY METHODS ################################# def valueChanged(self): """ Change the value of the node. :rtype: QUndoCommand """ datatype = self.datatypeField.currentData() value = self.valueField.value() data = self.node.compose(value, datatype) if self.node.text() != data: new_prefix = datatype.value[0:datatype.value.index(':')] new_remaining_characters = datatype.value[datatype.value.index(':' ) + 1:len(datatype.value)] new_iri = None for namespace in Namespace: if namespace.name.lower() == new_prefix: new_iri = namespace.value Duplicate_dict_1 = self.project.copy_IRI_prefixes_nodes_dictionaries( self.project.IRI_prefixes_nodes_dict, dict()) Duplicate_dict_2 = self.project.copy_IRI_prefixes_nodes_dictionaries( self.project.IRI_prefixes_nodes_dict, dict()) old_iri = self.project.get_iri_of_node(self.node) Duplicate_dict_1[old_iri][1].remove(self.node) Duplicate_dict_1[new_iri][1].add(self.node) commands = [ CommandLabelChange(self.diagram, self.node, self.node.text(), data), CommandNodeSetRemainingCharacters( self.node.remaining_characters, new_remaining_characters, self.node, self.project), CommandLabelChange(self.diagram, self.node, self.node.text(), data) ] return commands return None
class ValueNodeProperty(NodeProperty): """ This class implements the property dialog for value nodes. """ def __init__(self, diagram, node, session): """ Initialize the node properties dialog. :type diagram: Diagram :type node: AbstractNode :type session: Session """ super().__init__(diagram, node, session) ############################################# # VALUE TAB ################################# self.datatypeLabel = QtWidgets.QLabel(self) self.datatypeLabel.setFont(Font('Roboto', 12)) self.datatypeLabel.setText('Datatype') self.datatypeField = ComboBox(self) self.datatypeField.setFixedWidth(200) self.datatypeField.setFocusPolicy(QtCore.Qt.StrongFocus) self.datatypeField.setFont(Font('Roboto', 12)) for datatype in Datatype: self.datatypeField.addItem(datatype.value, datatype) datatype = self.node.datatype for i in range(self.datatypeField.count()): if self.datatypeField.itemData(i) is datatype: self.datatypeField.setCurrentIndex(i) break else: self.datatypeField.setCurrentIndex(0) self.valueLabel = QtWidgets.QLabel(self) self.valueLabel.setFont(Font('Roboto', 12)) self.valueLabel.setText('Value') self.valueField = StringField(self) self.valueField.setFixedWidth(200) self.valueField.setFont(Font('Roboto', 12)) self.valueField.setValue(self.node.value) self.valueWidget = QtWidgets.QWidget() self.valueLayout = QtWidgets.QFormLayout(self.valueWidget) self.valueLayout.addRow(self.datatypeLabel, self.datatypeField) self.valueLayout.addRow(self.valueLabel, self.valueField) self.mainWidget.addTab(self.valueWidget, 'Datatype') ############################################# # SLOTS ################################# @QtCore.pyqtSlot() def complete(self): """ Executed when the dialog is accepted. """ commands = [self.positionChanged(), self.valueChanged()] if any(commands): self.session.undostack.beginMacro('edit {0} properties'.format(self.node.name)) for command in commands: if command: self.session.undostack.push(command) self.session.undostack.endMacro() super().accept() ############################################# # AUXILIARY METHODS ################################# def valueChanged(self): """ Change the value of the node. :rtype: QUndoCommand """ datatype = self.datatypeField.currentData() value = self.valueField.value() data = self.node.compose(value, datatype) if self.node.text() != data: return CommandLabelChange(self.diagram, self.node, self.node.text(), data) return None
class FacetNodeProperty(NodeProperty): """ This class implements the property dialog for facet nodes. """ def __init__(self, diagram, node, session): """ Initialize the node properties dialog. :type diagram: Diagram :type node: AbstractNode :type session: Session """ super().__init__(diagram, node, session) ############################################# # FACET TAB ################################# f1 = lambda x: x.type() is Item.InputEdge f2 = lambda x: x.type() is Item.DatatypeRestrictionNode f3 = lambda x: x.type() is Item.ValueDomainNode admissible = [x for x in Facet] restriction = first(self.node.outgoingNodes(filter_on_edges=f1, filter_on_nodes=f2)) if restriction: valuedomain = first(restriction.incomingNodes(filter_on_edges=f1, filter_on_nodes=f3)) if valuedomain: admissible = Facet.forDatatype(valuedomain.datatype) self.facetLabel = QtWidgets.QLabel(self) self.facetLabel.setFont(Font('Roboto', 12)) self.facetLabel.setText('Facet') self.facetField = ComboBox(self) self.facetField.setFixedWidth(200) self.facetField.setFocusPolicy(QtCore.Qt.StrongFocus) self.facetField.setFont(Font('Roboto', 12)) for facet in admissible: self.facetField.addItem(facet.value, facet) facet = self.node.facet for i in range(self.facetField.count()): if self.facetField.itemData(i) is facet: self.facetField.setCurrentIndex(i) break else: self.facetField.setCurrentIndex(0) self.valueLabel = QtWidgets.QLabel(self) self.valueLabel.setFont(Font('Roboto', 12)) self.valueLabel.setText('Value') self.valueField = StringField(self) self.valueField.setFixedWidth(200) self.valueField.setFont(Font('Roboto', 12)) self.valueField.setValue(self.node.value) self.facetWidget = QtWidgets.QWidget() self.facetLayout = QtWidgets.QFormLayout(self.facetWidget) self.facetLayout.addRow(self.facetLabel, self.facetField) self.facetLayout.addRow(self.valueLabel, self.valueField) self.mainWidget.addTab(self.facetWidget, 'Facet') ############################################# # SLOTS ################################# @QtCore.pyqtSlot() def complete(self): """ Executed when the dialog is accepted. """ commands = [self.positionChanged(), self.facetChanged()] if any(commands): self.session.undostack.beginMacro('edit {0} properties'.format(self.node.name)) for command in commands: if command: self.session.undostack.push(command) self.session.undostack.endMacro() super().accept() ############################################# # AUXILIARY METHODS ################################# def facetChanged(self): """ Change the facet value of the node of the node. :rtype: QUndoCommand """ data = self.node.compose(self.facetField.currentData(), self.valueField.value()) if self.node.text() != data: return CommandLabelChange(self.diagram, self.node, self.node.text(), data) return None
class PredicateNodeProperty(NodeProperty): """ This class implements the property dialog for predicate nodes. Note that this dialog window is not used for value-domain nodes even though they are predicate nodes. """ def __init__(self, diagram, node, session): """ Initialize the node properties dialog. :type diagram: Diagram :type node: AbstractNode :type session: Session """ super().__init__(diagram, node, session) meta = diagram.project.meta(node.type(), node.text()) self.urlLabel = QtWidgets.QLabel(self) self.urlLabel.setFont(Font('Roboto', 12)) self.urlLabel.setText('URL') self.urlField = StringField(self) self.urlField.setFixedWidth(300) self.urlField.setFont(Font('Roboto', 12)) self.urlField.setValue(meta.get('url', '')) self.descriptionLabel = QtWidgets.QLabel(self) self.descriptionLabel.setFont(Font('Roboto', 12)) self.descriptionLabel.setText('Description') self.descriptionField = TextField(self) self.descriptionField.setFixedSize(300, 160) self.descriptionField.setFont(Font('Roboto', 12)) self.descriptionField.setValue(meta.get('description', '')) self.generalLayout.addRow(self.urlLabel, self.urlField) self.generalLayout.addRow(self.descriptionLabel, self.descriptionField) ############################################# # LABEL TAB ################################# self.textLabel = QtWidgets.QLabel(self) self.textLabel.setFont(Font('Roboto', 12)) self.textLabel.setText('Text') self.textField = StringField(self) self.textField.setFixedWidth(300) self.textField.setFont(Font('Roboto', 12)) self.textField.setValue(self.node.text()) self.refactorLabel = QtWidgets.QLabel(self) self.refactorLabel.setFont(Font('Roboto', 12)) self.refactorLabel.setText('Refactor') self.refactorField = CheckBox(self) self.refactorField.setFont(Font('Roboto', 12)) self.refactorField.setChecked(False) if node.type() in {Item.AttributeNode, Item.ConceptNode, Item.RoleNode}: if node.special() is not None: self.refactorField.setEnabled(False) self.labelWidget = QtWidgets.QWidget() self.labelLayout = QtWidgets.QFormLayout(self.labelWidget) self.labelLayout.addRow(self.textLabel, self.textField) self.labelLayout.addRow(self.refactorLabel, self.refactorField) self.mainWidget.addTab(self.labelWidget, 'Label') ############################################# # SLOTS ################################# @QtCore.pyqtSlot() def complete(self): """ Executed when the dialog is accepted. """ commands = [self.positionChanged(), self.metaDataChanged()] commands.extend(self.textChanged()) if any(commands): self.session.undostack.beginMacro('edit {0} properties'.format(self.node.name)) for command in commands: if command: self.session.undostack.push(command) self.session.undostack.endMacro() super().accept() ############################################# # AUXILIARY METHODS ################################# def metaDataChanged(self): """ Change the url and description of the node. :rtype: QUndoCommand """ meta = self.diagram.project.meta(self.node.type(), self.node.text()) copy = meta.copy() copy['description'] = self.descriptionField.value() copy['url'] = self.urlField.value() if copy != meta: return CommandNodeChangeMeta(self.diagram, self.node, meta, copy) return None def textChanged(self): """ Change the label of the node. :rtype: list """ data = self.textField.value().strip() data = data if not isEmpty(data) else self.node.label.template if self.node.text() != data: if self.refactorField.isChecked(): item = self.node.type() name = self.node.text() project = self.diagram.project return [CommandLabelChange(n.diagram, n, n.text(), data) for n in project.predicates(item, name)] return [CommandLabelChange(self.diagram, self.node, self.node.text(), data)] return [None]
class ValueForm(QtWidgets.QDialog): """ This class implements the form used to select the Value of an Individual node. """ def __init__(self, node, session): """ Initialize the form dialog. :type node: IndividualNode :type session: Session """ super().__init__(session) self.node = node ############################################# # FORM AREA ################################# self.datatypeLabel = QtWidgets.QLabel(self) self.datatypeLabel.setFont(Font('Roboto', 12)) self.datatypeLabel.setText('Datatype') self.datatypeField = ComboBox(self) self.datatypeField.setFont(Font('Roboto', 12)) self.datatypeField.setFixedWidth(300) for datatype in sorted(Datatype.forProfile( self.project.profile.type()), key=attrgetter('value')): self.datatypeField.addItem(datatype.value, datatype) self.valueLabel = QtWidgets.QLabel(self) self.valueLabel.setFont(Font('Roboto', 12)) self.valueLabel.setText('Value') self.valueField = StringField(self) self.valueField.setFixedWidth(300) if node.identity() is Identity.Value: self.valueField.setValue(node.value) datatype = node.datatype for i in range(self.datatypeField.count()): if self.datatypeField.itemData(i) is datatype: self.datatypeField.setCurrentIndex(i) break else: self.valueField.setValue('') self.datatypeField.setCurrentIndex(0) self.formWidget = QtWidgets.QWidget(self) self.formLayout = QtWidgets.QFormLayout(self.formWidget) self.formLayout.addRow(self.datatypeLabel, self.datatypeField) self.formLayout.addRow(self.valueLabel, self.valueField) ############################################# # CONFIRMATION AREA ################################# self.confirmationBox = QtWidgets.QDialogButtonBox( QtCore.Qt.Horizontal, self) self.confirmationBox.addButton(QtWidgets.QDialogButtonBox.Ok) self.confirmationBox.addButton(QtWidgets.QDialogButtonBox.Cancel) self.confirmationBox.setContentsMargins(10, 0, 10, 10) self.confirmationBox.setFont(Font('Roboto', 12)) ############################################# # SETUP DIALOG LAYOUT ################################# self.mainLayout = QtWidgets.QVBoxLayout(self) self.mainLayout.setContentsMargins(0, 0, 0, 0) self.mainLayout.addWidget(self.formWidget) self.mainLayout.addWidget(self.confirmationBox, 0, QtCore.Qt.AlignRight) self.setFixedSize(self.sizeHint()) self.setWindowIcon(QtGui.QIcon(':/icons/128/ic_eddy')) self.setWindowTitle('Compose value') connect(self.confirmationBox.accepted, self.accept) connect(self.confirmationBox.rejected, self.reject) ############################################# # PROPERTIES ################################# @property def project(self): """ Returns the reference to the active project. :rtype: Project """ return self.session.project @property def session(self): """ Returns the reference to the active session (alias for RefactorNameForm.parent()). :rtype: Session """ return self.parent() ############################################# # SLOTS ################################# @QtCore.pyqtSlot() def accept(self): """ Accepts the form and set the new value. """ node = self.node diagram = node.diagram datatype = self.datatypeField.currentData() value = self.valueField.value() data = node.compose(value, datatype) if node.text() != data: name = 'change {0} to {1}'.format(node.text(), data) self.session.undostack.push( CommandLabelChange(diagram, node, node.text(), data, name=name)) super().accept()
class RefactorNameForm(QtWidgets.QDialog): """ This class implements the form used to rename nodes during refactor operations. """ def __init__(self, node, session): """ Initialize the form dialog. :type node: AbstractNode :type session: Session """ super().__init__(session) self.node = node ############################################# # FORM AREA ################################# self.renameLabel = QtWidgets.QLabel(self) self.renameLabel.setFont(Font('Roboto', 12)) self.renameLabel.setText('Name') self.renameField = StringField(self) self.renameField.setFixedWidth(200) self.renameField.setFont(Font('Roboto', 12)) self.renameField.setValue(self.node.text()) connect(self.renameField.textChanged, self.nameChanged) self.formWidget = QtWidgets.QWidget(self) self.formLayout = QtWidgets.QFormLayout(self.formWidget) self.formLayout.addRow(self.renameLabel, self.renameField) ############################################# # CONFIRMATION AREA ################################# self.confirmationBox = QtWidgets.QDialogButtonBox( QtCore.Qt.Horizontal, self) self.confirmationBox.addButton(QtWidgets.QDialogButtonBox.Ok) self.confirmationBox.addButton(QtWidgets.QDialogButtonBox.Cancel) self.confirmationBox.setContentsMargins(10, 0, 10, 10) self.confirmationBox.setFont(Font('Roboto', 12)) ############################################# # SETUP DIALOG LAYOUT ################################# self.caption = QtWidgets.QLabel(self) self.caption.setFont(Font('Roboto', 12)) self.caption.setContentsMargins(8, 0, 8, 0) self.caption.setProperty('class', 'invalid') self.caption.setVisible(False) self.mainLayout = QtWidgets.QVBoxLayout(self) self.mainLayout.setContentsMargins(0, 0, 0, 0) self.mainLayout.addWidget(self.formWidget) self.mainLayout.addWidget(self.caption) self.mainLayout.addWidget(self.confirmationBox, 0, QtCore.Qt.AlignRight) self.setFixedSize(self.sizeHint()) self.setWindowIcon(QtGui.QIcon(':/icons/128/ic_eddy')) self.setWindowTitle('Rename') connect(self.confirmationBox.accepted, self.accept) connect(self.confirmationBox.rejected, self.reject) ############################################# # PROPERTIES ################################# @property def project(self): """ Returns the reference to the active project. :rtype: Project """ return self.session.project @property def session(self): """ Returns the reference to the active session (alias for RefactorNameForm.parent()). :rtype: Session """ return self.parent() ############################################# # SLOTS ################################# @QtCore.pyqtSlot() def accept(self): """ Accepts the rename form and perform refactoring. """ name = self.renameField.value() self.session.undostack.beginMacro( 'change predicate "{0}" to "{1}"'.format(self.node.text(), name)) for node in self.project.predicates(self.node.type(), self.node.text()): command = CommandLabelChange(node.diagram, node, node.text(), name, refactor=True) self.session.undostack.push(command) self.session.undostack.endMacro() super().accept() @QtCore.pyqtSlot() def nameChanged(self): """ Executed whenever the text in the rename field changes. """ caption = '' enabled = True if isEmpty(self.renameField.value()): caption = "\'{0}\' is not a valid predicate name".format( self.renameField.value()) enabled = False self.caption.setText(caption) self.caption.setVisible(not isEmpty(caption)) self.confirmationBox.button( QtWidgets.QDialogButtonBox.Ok).setEnabled(enabled) self.setFixedSize(self.sizeHint())
class PluginInstallDialog(QtWidgets.QDialog): """ Extends QtWidgets.QDialog providing an interface to install plugins. """ def __init__(self, session): """ Initialize the plugin install dialog. :type session: Session """ super().__init__(session) ############################################# # HEAD AREA ################################# self.headTitle = QtWidgets.QLabel('Install a plugin', self) self.headTitle.setFont(Font('Roboto', 12, bold=True)) self.headDescription = QtWidgets.QLabel(dedent(""" Plugins are software components that add specific features to {0}.<br/> Please select the plugin you wish to install.""".format(APPNAME)), self) self.headDescription.setFont(Font('Roboto', 12)) self.headPix = QtWidgets.QLabel(self) self.headPix.setPixmap(QtGui.QIcon(':/icons/48/ic_extension_black').pixmap(48)) self.headPix.setContentsMargins(0, 0, 0, 0) self.headWidget = QtWidgets.QWidget(self) self.headWidget.setProperty('class', 'head') self.headWidget.setContentsMargins(10, 10, 10, 10) self.headLayoutL = QtWidgets.QVBoxLayout() self.headLayoutL.addWidget(self.headTitle) self.headLayoutL.addWidget(self.headDescription) self.headLayoutL.setContentsMargins(0, 0, 0, 0) self.headLayoutR = QtWidgets.QVBoxLayout() self.headLayoutR.addWidget(self.headPix, 0, QtCore.Qt.AlignRight) self.headLayoutR.setContentsMargins(0, 0, 0, 0) self.headLayoutM = QtWidgets.QHBoxLayout(self.headWidget) self.headLayoutM.addLayout(self.headLayoutL) self.headLayoutM.addLayout(self.headLayoutR) self.headLayoutM.setContentsMargins(0, 0, 0, 0) ############################################# # SELECTION AREA ################################# self.pluginField = StringField(self) self.pluginField.setFont(Font('Roboto', 12)) self.pluginField.setFixedWidth(400) self.pluginField.setReadOnly(True) self.btnBrowse = QtWidgets.QPushButton(self) self.btnBrowse.setFont(Font('Roboto', 12)) self.btnBrowse.setFixedWidth(30) self.btnBrowse.setText('...') self.editLayout = QtWidgets.QHBoxLayout() self.editLayout.setContentsMargins(10, 10, 10, 10) self.editLayout.addWidget(self.pluginField) self.editLayout.addWidget(self.btnBrowse) ############################################# # CONFIRMATION AREA ################################# self.confirmationBox = QtWidgets.QDialogButtonBox(QtWidgets.QDialogButtonBox.Ok, self) self.confirmationBox.setContentsMargins(10, 0, 10, 10) self.confirmationBox.setEnabled(False) self.confirmationBox.setFont(Font('Roboto', 12)) ############################################# # SETUP DIALOG LAYOUT ################################# self.mainLayout = QtWidgets.QVBoxLayout(self) self.mainLayout.setContentsMargins(0, 0, 0, 0) self.mainLayout.addWidget(self.headWidget) self.mainLayout.addLayout(self.editLayout) self.mainLayout.addWidget(self.confirmationBox, 0, QtCore.Qt.AlignRight) self.setFixedSize(self.sizeHint()) self.setWindowIcon(QtGui.QIcon(':/icons/128/ic_eddy')) self.setWindowTitle('Install a plugin') connect(self.btnBrowse.clicked, self.selectPlugin) connect(self.confirmationBox.accepted, self.accept) ############################################# # PROPERTIES ################################# @property def session(self): """ Returns the reference to the main session (alias for PluginInstallDialog.parent()). :rtype: Session """ return self.parent() ############################################# # SLOTS ################################# @QtCore.pyqtSlot() def accept(self): """ Trigger the install of the selected plugin. """ try: spec = self.session.pmanager.install(self.pluginField.value()) except Exception as e: msgbox = QtWidgets.QMessageBox(self) msgbox.setIconPixmap(QtGui.QIcon(':/icons/48/ic_error_outline_black').pixmap(48)) msgbox.setStandardButtons(QtWidgets.QMessageBox.Close) msgbox.setText('{0} could not install plugin archive <b>{1}</b>: {2}'.format(APPNAME, self.pluginField.value(), e)) msgbox.setDetailedText(format_exception(e)) msgbox.setWindowIcon(QtGui.QIcon(':/icons/128/ic_eddy')) msgbox.setWindowTitle('Plugin install failed!') msgbox.exec_() else: plugin_name = spec.get('plugin', 'name') plugin_version = spec.get('plugin', 'version') plugin_author = spec.get('plugin', 'author', fallback='<unknown>') message = dedent("""Successfully installed plugin <b>{0} v{1}</b> by <b>{2}</b>. Please reboot {3} for the plugin to work.""".format(plugin_name, plugin_version, plugin_author, APPNAME)) msgbox = QtWidgets.QMessageBox(self) msgbox.setIconPixmap(QtGui.QIcon(':/icons/48/ic_done_black').pixmap(48)) msgbox.setStandardButtons(QtWidgets.QMessageBox.Close) msgbox.setText(message) msgbox.setTextFormat(QtCore.Qt.RichText) msgbox.setWindowIcon(QtGui.QIcon(':/icons/128/ic_eddy')) msgbox.setWindowTitle('Plugin installed!') msgbox.exec_() super().accept() @QtCore.pyqtSlot() def selectPlugin(self): """ Bring up a modal window that allows the user to choose a valid plugin archive. """ path = os.path.dirname(self.pluginField.value()) if not isPathValid(path): path = expandPath('~') dialog = QtWidgets.QFileDialog(self) dialog.setAcceptMode(QtWidgets.QFileDialog.AcceptOpen) dialog.setDirectory(path) dialog.setFileMode(QtWidgets.QFileDialog.ExistingFile) dialog.setViewMode(QtWidgets.QFileDialog.Detail) dialog.setNameFilters([File.Zip.value]) if dialog.exec_() == QtWidgets.QFileDialog.Accepted: self.pluginField.setValue(first(dialog.selectedFiles())) self.confirmationBox.setEnabled(not isEmpty(self.pluginField.value()))
class RefactorNameForm(QtWidgets.QDialog): """ This class implements the form used to rename nodes during refactor operations. """ def __init__(self, node, session): """ Initialize the form dialog. :type node: AbstractNode :type session: Session """ super().__init__(session) self.node = node ############################################# # FORM AREA ################################# self.renameLabel = QtWidgets.QLabel(self) self.renameLabel.setFont(Font('Roboto', 12)) self.renameLabel.setText('Name') self.renameField = StringField(self) self.renameField.setFixedWidth(200) self.renameField.setFont(Font('Roboto', 12)) self.renameField.setValue(self.node.text()) connect(self.renameField.textChanged, self.nameChanged) self.formWidget = QtWidgets.QWidget(self) self.formLayout = QtWidgets.QFormLayout(self.formWidget) self.formLayout.addRow(self.renameLabel, self.renameField) ############################################# # CONFIRMATION AREA ################################# self.confirmationBox = QtWidgets.QDialogButtonBox(QtCore.Qt.Horizontal, self) self.confirmationBox.addButton(QtWidgets.QDialogButtonBox.Ok) self.confirmationBox.addButton(QtWidgets.QDialogButtonBox.Cancel) self.confirmationBox.setContentsMargins(10, 0, 10, 10) self.confirmationBox.setFont(Font('Roboto', 12)) ############################################# # SETUP DIALOG LAYOUT ################################# self.caption = QtWidgets.QLabel(self) self.caption.setFont(Font('Roboto', 12)) self.caption.setContentsMargins(8, 0, 8, 0) self.caption.setProperty('class', 'invalid') self.caption.setVisible(False) self.mainLayout = QtWidgets.QVBoxLayout(self) self.mainLayout.setContentsMargins(0, 0, 0, 0) self.mainLayout.addWidget(self.formWidget) self.mainLayout.addWidget(self.caption) self.mainLayout.addWidget(self.confirmationBox, 0, QtCore.Qt.AlignRight) self.setFixedSize(self.sizeHint()) self.setWindowIcon(QtGui.QIcon(':/icons/128/ic_eddy')) self.setWindowTitle('Rename') connect(self.confirmationBox.accepted, self.accept) connect(self.confirmationBox.rejected, self.reject) ############################################# # PROPERTIES ################################# @property def project(self): """ Returns the reference to the active project. :rtype: Project """ return self.session.project @property def session(self): """ Returns the reference to the active session (alias for RefactorNameForm.parent()). :rtype: Session """ return self.parent() ############################################# # SLOTS ################################# @QtCore.pyqtSlot() def accept(self): """ Accepts the rename form and perform refactoring. """ name = self.renameField.value() self.session.undostack.beginMacro('change predicate "{0}" to "{1}"'.format(self.node.text(), name)) for node in self.project.predicates(self.node.type(), self.node.text()): command = CommandLabelChange(node.diagram, node, node.text(), name, refactor=True) self.session.undostack.push(command) self.session.undostack.endMacro() super().accept() @QtCore.pyqtSlot() def nameChanged(self): """ Executed whenever the text in the rename field changes. """ caption = '' enabled = True if isEmpty(self.renameField.value()): caption = "\'{0}\' is not a valid predicate name".format(self.renameField.value()) enabled = False self.caption.setText(caption) self.caption.setVisible(not isEmpty(caption)) self.confirmationBox.button(QtWidgets.QDialogButtonBox.Ok).setEnabled(enabled) self.setFixedSize(self.sizeHint())
class ValueForm(QtWidgets.QDialog): """ This class implements the form used to select the Value of an Individual node. """ def __init__(self, node, session): """ Initialize the form dialog. :type node: IndividualNode :type session: Session """ super().__init__(session) self.node = node ############################################# # FORM AREA ################################# self.datatypeLabel = QtWidgets.QLabel(self) self.datatypeLabel.setFont(Font('Roboto', 12)) self.datatypeLabel.setText('Datatype') self.datatypeField = ComboBox(self) self.datatypeField.setFont(Font('Roboto', 12)) self.datatypeField.setFixedWidth(300) for datatype in sorted(Datatype.forProfile(self.project.profile.type()), key=attrgetter('value')): self.datatypeField.addItem(datatype.value, datatype) self.valueLabel = QtWidgets.QLabel(self) self.valueLabel.setFont(Font('Roboto', 12)) self.valueLabel.setText('Value') self.valueField = StringField(self) self.valueField.setFixedWidth(300) if node.identity() is Identity.Value: self.valueField.setValue(node.value) datatype = node.datatype for i in range(self.datatypeField.count()): if self.datatypeField.itemData(i) is datatype: self.datatypeField.setCurrentIndex(i) break else: self.valueField.setValue('') self.datatypeField.setCurrentIndex(0) self.formWidget = QtWidgets.QWidget(self) self.formLayout = QtWidgets.QFormLayout(self.formWidget) self.formLayout.addRow(self.datatypeLabel, self.datatypeField) self.formLayout.addRow(self.valueLabel, self.valueField) ############################################# # CONFIRMATION AREA ################################# self.confirmationBox = QtWidgets.QDialogButtonBox(QtCore.Qt.Horizontal, self) self.confirmationBox.addButton(QtWidgets.QDialogButtonBox.Ok) self.confirmationBox.addButton(QtWidgets.QDialogButtonBox.Cancel) self.confirmationBox.setContentsMargins(10, 0, 10, 10) self.confirmationBox.setFont(Font('Roboto', 12)) ############################################# # SETUP DIALOG LAYOUT ################################# self.mainLayout = QtWidgets.QVBoxLayout(self) self.mainLayout.setContentsMargins(0, 0, 0, 0) self.mainLayout.addWidget(self.formWidget) self.mainLayout.addWidget(self.confirmationBox, 0, QtCore.Qt.AlignRight) self.setFixedSize(self.sizeHint()) self.setWindowIcon(QtGui.QIcon(':/icons/128/ic_eddy')) self.setWindowTitle('Compose value') connect(self.confirmationBox.accepted, self.accept) connect(self.confirmationBox.rejected, self.reject) ############################################# # PROPERTIES ################################# @property def project(self): """ Returns the reference to the active project. :rtype: Project """ return self.session.project @property def session(self): """ Returns the reference to the active session (alias for RefactorNameForm.parent()). :rtype: Session """ return self.parent() ############################################# # SLOTS ################################# @QtCore.pyqtSlot() def accept(self): """ Accepts the form and set the new value. """ node = self.node diagram = node.diagram datatype = self.datatypeField.currentData() value = self.valueField.value() data = node.compose(value, datatype) if node.text() != data: name = 'change {0} to {1}'.format(node.text(), data) self.session.undostack.push(CommandLabelChange(diagram, node, node.text(), data, name=name)) super().accept()
class ProjectDialog(QtWidgets.QDialog): """ This class is used to display a modal window to enter project specific data. """ def __init__(self, parent=None): """ Initialize the project dialog. :type parent: QtWidgets.QWidget """ super().__init__(parent) ############################################# # FORM AREA ################################# settings = QtCore.QSettings(ORGANIZATION, APPNAME) self.workspace = expandPath(settings.value('workspace/home', WORKSPACE, str)) self.workspace = '{0}{1}'.format(rstrip(self.workspace, os.path.sep), os.path.sep) self.nameLabel = QtWidgets.QLabel(self) self.nameLabel.setFont(Font('Roboto', 12)) self.nameLabel.setText('Name') self.nameField = StringField(self) self.nameField.setFont(Font('Roboto', 12)) self.nameField.setMinimumWidth(400) self.nameField.setMaxLength(64) connect(self.nameField.textChanged, self.onNameFieldChanged) self.prefixLabel = QtWidgets.QLabel(self) self.prefixLabel.setFont(Font('Roboto', 12)) self.prefixLabel.setText('Prefix') self.prefixField = StringField(self) self.prefixField.setFont(Font('Roboto', 12)) self.prefixField.setMinimumWidth(400) self.iriLabel = QtWidgets.QLabel(self) self.iriLabel.setFont(Font('Roboto', 12)) self.iriLabel.setText('IRI') self.iriField = StringField(self) self.iriField.setFont(Font('Roboto', 12)) self.iriField.setMinimumWidth(400) connect(self.iriField.textChanged, self.doProjectPathValidate) connect(self.nameField.textChanged, self.doProjectPathValidate) connect(self.prefixField.textChanged, self.doProjectPathValidate) self.pathLabel = QtWidgets.QLabel(self) self.pathLabel.setFont(Font('Roboto', 12)) self.pathLabel.setText('Location') self.pathField = StringField(self) self.pathField.setFont(Font('Roboto', 12)) self.pathField.setMinimumWidth(400) self.pathField.setReadOnly(True) self.pathField.setFocusPolicy(QtCore.Qt.NoFocus) self.pathField.setValue(self.workspace) spacer = QtWidgets.QFrame() spacer.setFrameShape(QtWidgets.QFrame.HLine) spacer.setFrameShadow(QtWidgets.QFrame.Sunken) self.formWidget = QtWidgets.QWidget(self) self.formLayout = QtWidgets.QFormLayout(self.formWidget) self.formLayout.addRow(self.nameLabel, self.nameField) self.formLayout.addRow(self.prefixLabel, self.prefixField) self.formLayout.addRow(self.iriLabel, self.iriField) self.formLayout.addWidget(spacer) self.formLayout.addRow(self.pathLabel, self.pathField) ############################################# # CONFIRMATION AREA ################################# self.confirmationBox = QtWidgets.QDialogButtonBox(QtCore.Qt.Horizontal, self) self.confirmationBox.addButton(QtWidgets.QDialogButtonBox.Ok) self.confirmationBox.addButton(QtWidgets.QDialogButtonBox.Cancel) self.confirmationBox.setContentsMargins(10, 0, 10, 10) self.confirmationBox.setFont(Font('Roboto', 12)) self.confirmationBox.button(QtWidgets.QDialogButtonBox.Ok).setEnabled(False) ############################################# # SETUP DIALOG LAYOUT ################################# self.caption = QtWidgets.QLabel(self) self.caption.setFont(Font('Roboto', 12)) self.caption.setContentsMargins(8, 0, 8, 0) self.caption.setProperty('class', 'invalid') self.caption.setVisible(False) self.mainLayout = QtWidgets.QVBoxLayout(self) self.mainLayout.setContentsMargins(0, 0, 0, 0) self.mainLayout.addWidget(self.formWidget) self.mainLayout.addWidget(self.caption) self.mainLayout.addWidget(self.confirmationBox, 0, QtCore.Qt.AlignRight) self.setFixedSize(self.sizeHint()) self.setWindowIcon(QtGui.QIcon(':/icons/128/ic_eddy')) self.setWindowTitle('New project') connect(self.confirmationBox.accepted, self.accept) connect(self.confirmationBox.rejected, self.reject) ############################################# # INTERFACE ################################# def iri(self): """ Returns the value of the iri field (trimmed). :rtype: str """ return self.iriField.value() def path(self): """ Returns the value of the path field (expanded). :rtype: str """ return expandPath(self.pathField.value()) def prefix(self): """ Returns the value of the prefix field (trimmed). :rtype: str """ return self.prefixField.value() ############################################# # SLOTS ################################# @QtCore.pyqtSlot() def accept(self): """ Accept the project form and creates a new empty project. """ project = Project(self.path(), self.prefix(), self.iri(), OWL2Profile()) worker = GrapholProjectExporter(project) worker.run() super().accept() @QtCore.pyqtSlot() def doProjectPathValidate(self): """ Validate project settings. """ caption = '' enabled = True ############################################# # CHECK NAME ################################# name = self.nameField.value() path = self.pathField.value() if not name: caption = '' enabled = False else: if isdir(path): caption = "Project '{0}' already exists!".format(name) enabled = False elif not isPathValid(path): caption = "'{0}' is not a valid project name!".format(name) enabled = False ############################################# # CHECK PREFIX ################################# if enabled: if not self.prefixField.value(): caption = '' enabled = False ############################################# # CHECK IRI ################################# if enabled: if not self.iriField.value(): caption = '' enabled = False self.caption.setText(caption) self.caption.setVisible(not isEmpty(caption)) self.confirmationBox.button(QtWidgets.QDialogButtonBox.Ok).setEnabled(enabled) self.setFixedSize(self.sizeHint()) @QtCore.pyqtSlot(str) def onNameFieldChanged(self, name): """ Update the project location field to reflect the new project name. :type name: str """ self.pathField.setValue('{0}{1}'.format(self.workspace, name.strip()))
class PredicateNodeProperty(NodeProperty): """ This class implements the property dialog for predicate nodes. Note that this dialog window is not used for value-domain nodes even though they are predicate nodes. """ def __init__(self, diagram, node, session): """ Initialize the node properties dialog. :type diagram: Diagram :type node: AbstractNode :type session: Session """ super().__init__(diagram, node, session) meta = diagram.project.meta(node.type(), node.text()) self.iriLabel = QtWidgets.QLabel(self) self.iriLabel.setText('IRI') self.iriField = StringField(self) self.iriField.setFixedWidth(300) self.iriField.setValue(self.diagram.project.get_iri_of_node(node)) """ self.iriversionLabel = QtWidgets.QLabel(self) self.iriversionLabel.setText('IRI version') self.iriversionField = StringField(self) self.iriversionField.setFixedWidth(300) self.iriversionField.setValue(self.node.IRI_version(diagram.project)) """ ############################################# # LABEL TAB ################################# self.textLabel = QtWidgets.QLabel(self) self.textLabel.setText('IRI Label') self.textField = StringField(self) self.textField.setFixedWidth(300) # if node.type() in {Item.AttributeNode, Item.ConceptNode, Item.RoleNode, 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)))): self.textField.setValue(self.node.remaining_characters) else: self.textField.setValue(self.node.text().replace('\n', '')) # if ((node.type() is Item.IndividualNode) and (node.identity() is Identity.Value)) or \ if (('IndividualNode' in str(type(node))) and (node.identity() is Identity.Value)) or \ (('IndividualNode' not in str(type(node))) and (node.special() is not None)): self.textField.setReadOnly(True) self.iriField.setReadOnly(True) self.refactorLabel = QtWidgets.QLabel(self) self.refactorLabel.setText('Refactor') self.refactorField = CheckBox(self) self.refactorField.setChecked(False) # if node.type() in {Item.AttributeNode, Item.ConceptNode, Item.RoleNode}: if (('AttributeNode' in str(type(node))) or ('ConceptNode' in str(type(node))) or ('RoleNode' in str(type(node)))): if node.special() is not None: self.refactorField.setEnabled(False) self.FulliriLabel = QtWidgets.QLabel(self) self.FulliriLabel.setText('Full IRI') self.FulliriField = StringField(self) self.FulliriField.setFixedWidth(300) full_iri = self.project.get_full_IRI(self.iriField.value(), None, self.textField.value().strip()) self.FulliriField.setValue(full_iri) # self.FulliriField.setValue(self.iriField.value()+'#'+self.textField.value().strip()) self.FulliriField.setReadOnly(True) self.labelWidget = QtWidgets.QWidget() self.labelLayout = QtWidgets.QFormLayout(self.labelWidget) self.labelLayout.addRow(self.iriLabel, self.iriField) self.labelLayout.addRow(self.textLabel, self.textField) self.labelLayout.addRow(self.FulliriLabel, self.FulliriField) self.labelLayout.addRow(self.refactorLabel, self.refactorField) self.mainWidget.addTab(self.labelWidget, 'IRI') self.metaDataChanged_ADD_OK_var = None self.metaDataChanged_REMOVE_OK_var = None self.metaDataChanged_IGNORE_var = None ############################################# # SLOTS ################################# @QtCore.pyqtSlot() def complete(self): """ Executed when the dialog is accepted. """ commands = [self.positionChanged()] iri_changed_result = self.IRIChanged() if iri_changed_result is not None: if (str(type(iri_changed_result)) is '<class \'str\'>') and ('Error in' in iri_changed_result): super().reject() return else: commands.extend(iri_changed_result) text_changed_result = self.textChanged() if text_changed_result is not None: commands.extend(text_changed_result) if any(commands): self.session.undostack.beginMacro('edit {0} properties'.format( self.node.name)) for command in commands: if command: self.session.undostack.push(command) self.session.undostack.endMacro() super().accept() ############################################# # AUXILIARY METHODS ################################# def textChanged(self): unprocessed_new_text = self.textField.value().strip() unprocessed_new_text = unprocessed_new_text if not isEmpty( unprocessed_new_text) else self.node.label.template exception_list = ['-', '_', '.', '~', '\n'] new_rc = '' flag = False for i, c in enumerate(unprocessed_new_text): if c == '': pass elif i < (len(unprocessed_new_text) - 1) and ( c == '\\' and unprocessed_new_text[i + 1] == 'n'): new_rc = new_rc + '\n' elif i > 0 and (c == 'n' and unprocessed_new_text[i - 1] == '\\'): pass elif (not c.isalnum()) and (c not in exception_list): new_rc = new_rc + '_' flag = True else: new_rc = new_rc + c # new_rc = new_rc.replace('\n','') if flag is True: self.session.statusBar().showMessage( 'Spaces in between alphanumeric characters and special characters were replaced by an underscore character.', 15000) return_list = [] if (unprocessed_new_text != self.node.remaining_characters): # print('unprocessed_new_text',unprocessed_new_text) # print('self.node.remaining_characters',self.node.remaining_characters) # print(NewlineFeedInsensitive(new_rc, self.node.remaining_characters).result()) return_list.append( CommandProjectDisconnectSpecificSignals(self.project)) if self.refactorField.isChecked(): for n in self.project.nodes(): if n.text() == self.node.text(): return_list.append( CommandNodeSetRemainingCharacters( n.remaining_characters, new_rc, n, self.project, refactor=True)) else: # refactor_var = NewlineFeedInsensitive(new_rc, self.node.remaining_characters).result() # return_list.append( # CommandNodeSetRemainingCharacters(self.node.remaining_characters, new_rc, self.node, self.project, refactor=refactor_var)) return_list.append( CommandNodeSetRemainingCharacters( self.node.remaining_characters, new_rc, self.node, self.project)) return_list.append( CommandProjectConnectSpecificSignals(self.project)) return return_list return None def IRIChanged(self): # Change the iri of the node. #:rtype: Command IRI_valid = self.project.check_validity_of_IRI(self.iriField.value()) if IRI_valid is False: self.session.statusBar().showMessage('Invalid IRI.', 15000) return None else: old_iri = self.project.get_iri_of_node(self.node) new_iri = self.iriField.value() # if (self.iriField.value() != self.project.get_iri_of_node(node)) or (self.iriversionField.value() != self.node.IRI_version(self.project)): if new_iri != old_iri: connect(self.project.sgnIRINodeEntryAdded, self.metaDataChanged_ADD_OK) connect(self.project.sgnIRINodeEntryRemoved, self.metaDataChanged_REMOVE_OK) connect(self.project.sgnIRINodeEntryIgnored, self.metaDataChanged_IGNORE) # check for conflict in prefixes # transaction = remove(old) + add(new) # perform transaction on duplicate dict. # if successful, original_dict = duplicate_dict # else duplicate_dict = original_dict Duplicate_dict_1 = self.project.copy_IRI_prefixes_nodes_dictionaries( self.project.IRI_prefixes_nodes_dict, dict()) Duplicate_dict_2 = self.project.copy_IRI_prefixes_nodes_dictionaries( self.project.IRI_prefixes_nodes_dict, dict()) list_of_nodes_to_process = [] if self.refactorField.isChecked(): for n in self.project.nodes(): if (('AttributeNode' in str(type(n))) or ('ConceptNode' in str(type(n))) or ('IndividualNode' in str(type(n))) or ('RoleNode' in str(type(n)))): if (self.project.get_iri_of_node(n) == old_iri ) and (n.remaining_characters == self.node.remaining_characters): list_of_nodes_to_process.append(n) else: list_of_nodes_to_process.append(self.node) commands = [] for nd in list_of_nodes_to_process: self.project.removeIRINodeEntry(Duplicate_dict_1, old_iri, nd) self.project.addIRINodeEntry(Duplicate_dict_1, new_iri, nd) if (self.metaDataChanged_REMOVE_OK_var is True) and ( self.metaDataChanged_ADD_OK_var is True): self.metaDataChanged_REMOVE_OK_var = False self.metaDataChanged_ADD_OK_var = False self.metaDataChanged_IGNORE_var = False else: LOGGER.warning( 'redo != undo but transaction was not executed correctly' ) self.metaDataChanged_REMOVE_OK_var = False self.metaDataChanged_ADD_OK_var = False self.metaDataChanged_IGNORE_var = False return str('Error in ' + str(nd)) if len(Duplicate_dict_1[new_iri][0]) == 0: ### if 'display_in_widget' in Duplicate_dict_1[new_iri][2]: new_label = ':' + self.node.remaining_characters else: new_label = self.project.get_full_IRI( new_iri, None, self.node.remaining_characters) else: new_label = str(Duplicate_dict_1[new_iri][0][ len(Duplicate_dict_1[new_iri][0]) - 1] + ':' + self.node.remaining_characters) commands.append( CommandProjectDisconnectSpecificSignals(self.project)) for nd in list_of_nodes_to_process: commands.append( CommandLabelChange(nd.diagram, nd, nd.text(), new_label)) for nd in list_of_nodes_to_process: commands.append( CommandLabelChange(nd.diagram, nd, nd.text(), new_label)) commands.append( CommandProjectConnectSpecificSignals(self.project)) return commands self.metaDataChanged_REMOVE_OK_var = False self.metaDataChanged_ADD_OK_var = False self.metaDataChanged_IGNORE_var = False return None @QtCore.pyqtSlot(str, str, str) def metaDataChanged_REMOVE_OK(self, iri, node, message): # print('metaDataChanged_REMOVE_OK -', iri, ',', node, ',', message) self.metaDataChanged_REMOVE_OK_var = True @QtCore.pyqtSlot(str, str, str) def metaDataChanged_ADD_OK(self, iri, node, message): # print('metaDataChanged_ADD_OK -', iri, ',', node, ',', message) self.metaDataChanged_ADD_OK_var = True @QtCore.pyqtSlot(str, str, str) def metaDataChanged_IGNORE(self, iri, node, message): # if node.id is None: # print('metaDataChanged_IGNORE >', iri, '-', 'None', '-', message) # else: # print('metaDataChanged_IGNORE >', iri, '-', node, '-', message) self.metaDataChanged_IGNORE_var = True
class RenameForm(QDialog): """ This class implements the form used to rename nodes during refactor operations. """ def __init__(self, node, parent=None): """ Initialize the form dialog. :type node: AbstractNode :type parent: QWidget """ super().__init__(parent) self.node = node self.renameField = StringField(self) self.renameField.setFixedWidth(200) self.renameField.setValue(self.node.text()) self.invalidName = QLabel('\'\' is not a valid predicate name', self) self.invalidName.setProperty('class', 'invalid') self.invalidName.setVisible(False) self.buttonBox = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel, Qt.Horizontal, self) self.mainLayout = QFormLayout(self) self.mainLayout.addRow('Name', self.renameField) self.mainLayout.addRow(self.invalidName) self.mainLayout.addRow(self.buttonBox) self.setWindowTitle('Rename') self.setWindowIcon(QIcon(':/images/eddy')) self.setFixedSize(self.sizeHint()) connect(self.buttonBox.accepted, self.validate) connect(self.buttonBox.rejected, self.reject) connect(self.renameField.textChanged, self.nameChanged) #################################################################################################################### # # # SLOTS # # # #################################################################################################################### @pyqtSlot() def nameChanged(self): """ Executed whenever the text in the rename field changes. """ button = self.buttonBox.button(QDialogButtonBox.Ok) empty = isEmpty(self.renameField.value()) button.setDisabled(empty) self.invalidName.setVisible(empty) self.setFixedSize(self.sizeHint()) @pyqtSlot() def validate(self): """ Validate the form and trigger accept() if the form is valid. """ if isEmpty(self.renameField.value()): msgbox = QMessageBox(self) msgbox.setIconPixmap(QPixmap(':/icons/warning')) msgbox.setWindowIcon(QIcon(':/images/eddy')) msgbox.setWindowTitle('Invalid predicate') msgbox.setText('You specified an invalid predicate name!') msgbox.setStandardButtons(QMessageBox.Ok) msgbox.exec_() return # This will strip out leading/trailing whitespaces. self.renameField.setValue(self.renameField.value()) self.accept()
class RefactorNameForm(QtWidgets.QDialog): """ This class implements the form used to rename nodes during refactor operations. """ def __init__(self, node, session): """ Initialize the form dialog. :type node: AbstractNode :type session: Session """ super().__init__(session) self.node = node ############################################# # FORM AREA ################################# self.renameLabel = QtWidgets.QLabel(self) self.renameLabel.setText('IRI label') self.renameField = StringField(self) self.renameField.setFixedWidth(200) self.renameLabel.setWordWrap(True) match = RE_VALUE.match(self.node.text()) if match: self.renameField.setValue(self.node.text()) else: self.renameField.setValue(self.node.remaining_characters) self.old_text = self.node.text() connect(self.renameField.textChanged, self.nameChanged) self.formWidget = QtWidgets.QWidget(self) self.formLayout = QtWidgets.QFormLayout(self.formWidget) self.formLayout.addRow(self.renameLabel, self.renameField) ############################################# # CONFIRMATION AREA ################################# self.confirmationBox = QtWidgets.QDialogButtonBox( QtCore.Qt.Horizontal, self) self.confirmationBox.addButton(QtWidgets.QDialogButtonBox.Ok) self.confirmationBox.addButton(QtWidgets.QDialogButtonBox.Cancel) self.confirmationBox.setContentsMargins(10, 0, 10, 10) ############################################# # SETUP DIALOG LAYOUT ################################# self.caption = QtWidgets.QLabel(self) self.caption.setContentsMargins(8, 0, 8, 0) self.caption.setProperty('class', 'invalid') self.caption.setVisible(False) self.mainLayout = QtWidgets.QVBoxLayout(self) self.mainLayout.setContentsMargins(0, 0, 0, 0) self.mainLayout.addWidget(self.formWidget) self.mainLayout.addWidget(self.caption) self.mainLayout.addWidget(self.confirmationBox, 0, QtCore.Qt.AlignRight) self.setFixedSize(self.sizeHint()) self.setWindowIcon(QtGui.QIcon(':/icons/128/ic_eddy')) self.setWindowTitle('Rename') connect(self.confirmationBox.accepted, self.accept) connect(self.confirmationBox.rejected, self.reject) ############################################# # PROPERTIES ################################# @property def project(self): """ Returns the reference to the active project. :rtype: Project """ return self.session.project @property def session(self): """ Returns the reference to the active session (alias for RefactorNameForm.parent()). :rtype: Session """ return self.parent() ############################################# # SLOTS ################################# @QtCore.pyqtSlot() def accept(self): """ Accepts the rename form and perform refactoring. """ currentData = self.renameField.value() if currentData and currentData != self.old_text: match = RE_VALUE.match(currentData) match_old = RE_VALUE.match(self.old_text) commands = [] if match: new_prefix = match.group( 'datatype')[0:match.group('datatype').index(':')] new_remaining_characters = match.group( 'datatype')[match.group('datatype').index(':') + 1:len(match.group('datatype'))] new_iri = None for namespace in Namespace: if namespace.name.lower() == new_prefix: new_iri = namespace.value Duplicate_dict_1 = self.project.copy_IRI_prefixes_nodes_dictionaries( self.project.IRI_prefixes_nodes_dict, dict()) Duplicate_dict_2 = self.project.copy_IRI_prefixes_nodes_dictionaries( self.project.IRI_prefixes_nodes_dict, dict()) old_iri = self.project.get_iri_of_node(self.node) list_of_nodes_to_process = [] commands_label_change_list_1 = [] commands_label_change_list_2 = [] commands_rc_change = [] for node in self.project.predicates(self.node.type(), self.node.text()): list_of_nodes_to_process.append(node) Duplicate_dict_1[old_iri][1].remove(node) Duplicate_dict_1[new_iri][1].add(node) commands_label_change_list_1.append( CommandLabelChange(node.diagram, node, self.old_text, currentData, refactor=True)) commands_rc_change.append( CommandNodeSetRemainingCharacters( node.remaining_characters, new_remaining_characters, node, self.project, refactor=True)) commands_label_change_list_2.append( CommandLabelChange(node.diagram, node, self.old_text, currentData, refactor=True)) commands.append( CommandProjectDisconnectSpecificSignals(self.project)) commands.extend(commands_label_change_list_1) commands.extend(commands_rc_change) commands.extend(commands_label_change_list_2) commands.append( CommandProjectConnectSpecificSignals(self.project)) else: exception_list = ['-', '_', '.', '~', '\n'] currentData_processed = '' flag = False for i, c in enumerate(currentData): if c == '': pass elif i < (len(currentData) - 1) and ( c == '\\' and currentData[i + 1] == 'n'): currentData_processed = currentData_processed + '\n' elif i > 0 and (c == 'n' and currentData[i - 1] == '\\'): pass elif (not c.isalnum()) and (c not in exception_list): currentData_processed = currentData_processed + '_' flag = True else: currentData_processed = currentData_processed + c if flag is True: self.session.statusBar().showMessage( 'Spaces in between alphanumeric characters and special characters were replaced by an ' 'underscore character.', 15000) if match_old: new_remaining_characters = currentData_processed new_iri = self.project.ontologyIRIString Duplicate_dict_1 = self.project.copy_IRI_prefixes_nodes_dictionaries( self.project.IRI_prefixes_nodes_dict, dict()) Duplicate_dict_2 = self.project.copy_IRI_prefixes_nodes_dictionaries( self.project.IRI_prefixes_nodes_dict, dict()) old_iri = self.project.get_iri_of_node(self.node) list_of_nodes_to_process = [] commands_label_change_list_1 = [] commands_label_change_list_2 = [] commands_rc_change = [] for node in self.project.predicates( self.node.type(), self.node.text()): list_of_nodes_to_process.append(node) Duplicate_dict_1[old_iri][1].remove(node) Duplicate_dict_1[new_iri][1].add(node) if len(Duplicate_dict_1[new_iri][0]) == 0: new_label = self.project.get_full_IRI( new_iri, None, new_remaining_characters) else: new_label = str(Duplicate_dict_1[new_iri][0][ len(Duplicate_dict_1[new_iri][0]) - 1] + ':' + new_remaining_characters) commands_label_change_list_1.append( CommandLabelChange(node.diagram, node, self.old_text, new_label, refactor=True)) commands_rc_change.append( CommandNodeSetRemainingCharacters( node.remaining_characters, new_remaining_characters, node, self.project, refactor=True)) commands_label_change_list_2.append( CommandLabelChange(node.diagram, node, self.old_text, new_label, refactor=True)) command_dict_change = CommandProjetSetIRIPrefixesNodesDict( self.project, Duplicate_dict_2, Duplicate_dict_1, [old_iri, new_iri], list_of_nodes_to_process) commands.append( CommandProjectDisconnectSpecificSignals(self.project)) commands.extend(commands_label_change_list_1) commands.append(command_dict_change) commands.extend(commands_rc_change) commands.extend(commands_label_change_list_2) commands.append( CommandProjectConnectSpecificSignals(self.project)) else: commands.append( CommandProjectDisconnectSpecificSignals(self.project)) for node in self.project.predicates( self.node.type(), self.node.text()): commands.append( CommandNodeSetRemainingCharacters( node.remaining_characters, currentData_processed, node, self.project, refactor=True)) commands.append( CommandProjectConnectSpecificSignals(self.project)) if any(commands): self.session.undostack.beginMacro( 'change predicate "{0}" to "{1}"'.format( self.node.text(), currentData)) for command in commands: if command: self.session.undostack.push(command) self.session.undostack.endMacro() else: pass super().accept() # not used @QtCore.pyqtSlot() def accept_2(self): """ Accepts the rename form and perform refactoring. """ name = self.renameField.value() self.session.undostack.beginMacro( 'change predicate "{0}" to "{1}"'.format(self.node.text(), name)) for node in self.project.predicates(self.node.type(), self.node.text()): command = CommandLabelChange(node.diagram, node, node.text(), name, refactor=True) self.session.undostack.push(command) self.session.undostack.endMacro() super().accept() @QtCore.pyqtSlot() def nameChanged(self): """ Executed whenever the text in the rename field changes. """ caption = '' enabled = True if isEmpty(self.renameField.value()): caption = "\'{0}\' is not a valid predicate name".format( self.renameField.value()) enabled = False self.caption.setText(caption) self.caption.setVisible(not isEmpty(caption)) self.confirmationBox.button( QtWidgets.QDialogButtonBox.Ok).setEnabled(enabled) self.setFixedSize(self.sizeHint())
class WorkspaceDialog(QtWidgets.QDialog): """ This class can be used to setup the workspace path. """ def __init__(self, parent=None): """ Initialize the workspace dialog. :type parent: QtWidgets.QWidget """ super().__init__(parent) ############################################# # HEAD AREA ################################# self.headTitle = QtWidgets.QLabel('Select a workspace', self) self.headTitle.setFont(Font('Roboto', 12, bold=True)) self.headDescription = QtWidgets.QLabel(dedent(""" {0} stores your projects in a directory called workspace.<br/> Please choose a workspace directory to use.""".format(APPNAME)), self) self.headDescription.setFont(Font('Roboto', 12)) self.headPix = QtWidgets.QLabel(self) self.headPix.setPixmap(QtGui.QIcon(':/icons/128/ic_eddy').pixmap(48)) self.headPix.setContentsMargins(0, 0, 0, 0) self.headWidget = QtWidgets.QWidget(self) self.headWidget.setProperty('class', 'head') self.headWidget.setContentsMargins(10, 10, 10, 10) self.headLayoutL = QtWidgets.QVBoxLayout() self.headLayoutL.addWidget(self.headTitle) self.headLayoutL.addWidget(self.headDescription) self.headLayoutL.setContentsMargins(0, 0, 0, 0) self.headLayoutR = QtWidgets.QVBoxLayout() self.headLayoutR.addWidget(self.headPix, 0, QtCore.Qt.AlignRight) self.headLayoutR.setContentsMargins(0, 0, 0, 0) self.headLayoutM = QtWidgets.QHBoxLayout(self.headWidget) self.headLayoutM.addLayout(self.headLayoutL) self.headLayoutM.addLayout(self.headLayoutR) self.headLayoutM.setContentsMargins(0, 0, 0, 0) ############################################# # EDIT AREA ################################# self.workspaceField = StringField(self) self.workspaceField.setFont(Font('Roboto', 12)) self.workspaceField.setFixedWidth(400) self.workspaceField.setReadOnly(True) self.workspaceField.setText(expandPath(WORKSPACE)) self.btnBrowse = QtWidgets.QPushButton(self) self.btnBrowse.setFont(Font('Roboto', 12)) self.btnBrowse.setFixedWidth(30) self.btnBrowse.setText('...') self.editLayout = QtWidgets.QHBoxLayout() self.editLayout.setContentsMargins(10, 10, 10, 10) self.editLayout.addWidget(self.workspaceField) self.editLayout.addWidget(self.btnBrowse) ############################################# # CONFIRMATION AREA ################################# self.confirmationBox = QtWidgets.QDialogButtonBox(QtWidgets.QDialogButtonBox.Ok, self) self.confirmationBox.setContentsMargins(10, 0, 10, 10) self.confirmationBox.setFont(Font('Roboto', 12)) ############################################# # SETUP DIALOG LAYOUT ################################# self.mainLayout = QtWidgets.QVBoxLayout(self) self.mainLayout.setContentsMargins(0, 0, 0, 0) self.mainLayout.addWidget(self.headWidget) self.mainLayout.addLayout(self.editLayout) self.mainLayout.addWidget(self.confirmationBox, 0, QtCore.Qt.AlignRight) self.setFixedSize(self.sizeHint()) self.setWindowIcon(QtGui.QIcon(':/icons/128/ic_eddy')) self.setWindowTitle('Configure workspace') connect(self.btnBrowse.clicked, self.choosePath) connect(self.confirmationBox.accepted, self.accept) ############################################# # SLOTS ################################# @QtCore.pyqtSlot() def accept(self): """ Create Eddy workspace (if necessary). """ path = self.workspaceField.value() try: mkdir(path) except Exception as e: msgbox = QtWidgets.QMessageBox(self) msgbox.setDetailedText(format_exception(e)) msgbox.setIconPixmap(QtGui.QIcon(':/icons/48/ic_error_outline_black').pixmap(48)) msgbox.setStandardButtons(QtWidgets.QMessageBox.Close) msgbox.setText('{0} could not create the specified workspace: {1}!'.format(APPNAME, path)) msgbox.setWindowIcon(QtGui.QIcon(':/icons/128/ic_eddy')) msgbox.setWindowTitle('Workspace setup failed!') msgbox.exec_() super().reject() else: settings = QtCore.QSettings(ORGANIZATION, APPNAME) settings.setValue('workspace/home', path) settings.sync() super().accept() @QtCore.pyqtSlot() def choosePath(self): """ Bring up a modal window that allows the user to choose a valid workspace path. """ path = self.workspaceField.value() if not isPathValid(path): path = expandPath('~') dialog = QtWidgets.QFileDialog(self) dialog.setAcceptMode(QtWidgets.QFileDialog.AcceptOpen) dialog.setDirectory(path) dialog.setFileMode(QtWidgets.QFileDialog.Directory) dialog.setOption(QtWidgets.QFileDialog.ShowDirsOnly, True) dialog.setViewMode(QtWidgets.QFileDialog.Detail) if dialog.exec_() == QtWidgets.QFileDialog.Accepted: self.workspaceField.setValue(first(dialog.selectedFiles()))
class PluginInstallDialog(QtWidgets.QDialog): """ Extends QtWidgets.QDialog providing an interface to install plugins. """ def __init__(self, session): """ Initialize the plugin install dialog. :type session: Session """ super().__init__(session) ############################################# # HEAD AREA ################################# self.headTitle = QtWidgets.QLabel('Install a plugin', self) self.headTitle.setFont(Font('Roboto', 12, bold=True)) self.headDescription = QtWidgets.QLabel( dedent(""" Plugins are software components that add specific features to {0}.<br/> Please select the plugin you wish to install.""".format(APPNAME)), self) self.headDescription.setFont(Font('Roboto', 12)) self.headPix = QtWidgets.QLabel(self) self.headPix.setPixmap( QtGui.QIcon(':/icons/48/ic_extension_black').pixmap(48)) self.headPix.setContentsMargins(0, 0, 0, 0) self.headWidget = QtWidgets.QWidget(self) self.headWidget.setProperty('class', 'head') self.headWidget.setContentsMargins(10, 10, 10, 10) self.headLayoutL = QtWidgets.QVBoxLayout() self.headLayoutL.addWidget(self.headTitle) self.headLayoutL.addWidget(self.headDescription) self.headLayoutL.setContentsMargins(0, 0, 0, 0) self.headLayoutR = QtWidgets.QVBoxLayout() self.headLayoutR.addWidget(self.headPix, 0, QtCore.Qt.AlignRight) self.headLayoutR.setContentsMargins(0, 0, 0, 0) self.headLayoutM = QtWidgets.QHBoxLayout(self.headWidget) self.headLayoutM.addLayout(self.headLayoutL) self.headLayoutM.addLayout(self.headLayoutR) self.headLayoutM.setContentsMargins(0, 0, 0, 0) ############################################# # SELECTION AREA ################################# self.pluginField = StringField(self) self.pluginField.setFont(Font('Roboto', 12)) self.pluginField.setFixedWidth(400) self.pluginField.setReadOnly(True) self.btnBrowse = QtWidgets.QPushButton(self) self.btnBrowse.setFont(Font('Roboto', 12)) self.btnBrowse.setFixedWidth(30) self.btnBrowse.setText('...') self.editLayout = QtWidgets.QHBoxLayout() self.editLayout.setContentsMargins(10, 10, 10, 10) self.editLayout.addWidget(self.pluginField) self.editLayout.addWidget(self.btnBrowse) ############################################# # CONFIRMATION AREA ################################# self.confirmationBox = QtWidgets.QDialogButtonBox( QtWidgets.QDialogButtonBox.Ok, self) self.confirmationBox.setContentsMargins(10, 0, 10, 10) self.confirmationBox.setEnabled(False) self.confirmationBox.setFont(Font('Roboto', 12)) ############################################# # SETUP DIALOG LAYOUT ################################# self.mainLayout = QtWidgets.QVBoxLayout(self) self.mainLayout.setContentsMargins(0, 0, 0, 0) self.mainLayout.addWidget(self.headWidget) self.mainLayout.addLayout(self.editLayout) self.mainLayout.addWidget(self.confirmationBox, 0, QtCore.Qt.AlignRight) self.setFixedSize(self.sizeHint()) self.setWindowIcon(QtGui.QIcon(':/icons/128/ic_eddy')) self.setWindowTitle('Install a plugin') connect(self.btnBrowse.clicked, self.selectPlugin) connect(self.confirmationBox.accepted, self.accept) ############################################# # PROPERTIES ################################# @property def session(self): """ Returns the reference to the main session (alias for PluginInstallDialog.parent()). :rtype: Session """ return self.parent() ############################################# # SLOTS ################################# @QtCore.pyqtSlot() def accept(self): """ Trigger the install of the selected plugin. """ try: spec = self.session.pmanager.install(self.pluginField.value()) except Exception as e: msgbox = QtWidgets.QMessageBox(self) msgbox.setIconPixmap( QtGui.QIcon(':/icons/48/ic_error_outline_black').pixmap(48)) msgbox.setStandardButtons(QtWidgets.QMessageBox.Close) msgbox.setText( '{0} could not install plugin archive <b>{1}</b>: {2}'.format( APPNAME, self.pluginField.value(), e)) msgbox.setDetailedText(format_exception(e)) msgbox.setWindowIcon(QtGui.QIcon(':/icons/128/ic_eddy')) msgbox.setWindowTitle('Plugin install failed!') msgbox.exec_() else: plugin_name = spec.get('plugin', 'name') plugin_version = spec.get('plugin', 'version') plugin_author = spec.get('plugin', 'author', fallback='<unknown>') message = dedent( """Successfully installed plugin <b>{0} v{1}</b> by <b>{2}</b>. Please reboot {3} for the plugin to work.""".format( plugin_name, plugin_version, plugin_author, APPNAME)) msgbox = QtWidgets.QMessageBox(self) msgbox.setIconPixmap( QtGui.QIcon(':/icons/48/ic_done_black').pixmap(48)) msgbox.setStandardButtons(QtWidgets.QMessageBox.Close) msgbox.setText(message) msgbox.setTextFormat(QtCore.Qt.RichText) msgbox.setWindowIcon(QtGui.QIcon(':/icons/128/ic_eddy')) msgbox.setWindowTitle('Plugin installed!') msgbox.exec_() super().accept() @QtCore.pyqtSlot() def selectPlugin(self): """ Bring up a modal window that allows the user to choose a valid plugin archive. """ path = os.path.dirname(self.pluginField.value()) if not isPathValid(path): path = expandPath('~') dialog = QtWidgets.QFileDialog(self) dialog.setAcceptMode(QtWidgets.QFileDialog.AcceptOpen) dialog.setDirectory(path) dialog.setFileMode(QtWidgets.QFileDialog.ExistingFile) dialog.setViewMode(QtWidgets.QFileDialog.Detail) dialog.setNameFilters([File.Zip.value]) if dialog.exec_() == QtWidgets.QFileDialog.Accepted: self.pluginField.setValue(first(dialog.selectedFiles())) self.confirmationBox.setEnabled( not isEmpty(self.pluginField.value()))
class OWLTranslationForm(QDialog): """ This class implements the form used to perform Graphol -> OWL ontology translation. """ def __init__(self, scene, filepath, parent=None): """ Initialize the form dialog. :type scene: DiagramScene :type filepath: str :type parent: QWidget """ super().__init__(parent) self.scene = scene self.filepath = filepath self.worker = None self.workerThread = None self.iriField = StringField(self) self.iriField.setFixedWidth(300) self.iriField.setValidator(QRegExpValidator(QRegExp('[\w:\/\[\]=?%#~\.\-\+]*'), self)) self.prefixField = StringField(self) self.prefixField.setFixedWidth(300) self.prefixField.setValidator(QRegExpValidator(QRegExp('[\w]*'), self)) self.syntaxField = ComboBox(self) for syntax in OWLSyntax: self.syntaxField.addItem(syntax.value, syntax) self.syntaxField.setCurrentIndex(0) self.progressBar = QProgressBar(self) self.progressBar.setAlignment(Qt.AlignHCenter) self.progressBar.setRange(0, 100) self.progressBar.setValue(0) self.buttonBox = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel, Qt.Horizontal, self) self.buttonBox.button(QDialogButtonBox.Ok).setDisabled(True) self.mainLayout = QFormLayout(self) self.mainLayout.addRow('IRI', self.iriField) self.mainLayout.addRow('Prefix', self.prefixField) self.mainLayout.addRow('Syntax', self.syntaxField) self.mainLayout.addRow(self.progressBar) self.mainLayout.addRow(self.buttonBox) self.setWindowTitle('OWL Translation') self.setWindowIcon(QIcon(':/images/eddy')) self.setFixedSize(self.sizeHint()) connect(self.buttonBox.accepted, self.run) connect(self.buttonBox.rejected, self.reject) connect(self.iriField.textChanged, self.iriChanged) #################################################################################################################### # # # SLOTS # # # #################################################################################################################### @pyqtSlot(Exception) def errored(self, exception): """ Executed whenever the translation errors. :type exception: Exception """ if isinstance(exception, MalformedDiagramError): msgbox = QMessageBox(self) msgbox.setIconPixmap(QPixmap(':/icons/warning')) msgbox.setWindowIcon(QIcon(':/images/eddy')) msgbox.setWindowTitle('Malformed Diagram') msgbox.setText('Malformed expression detected on {}: {}'.format(exception.item, exception)) msgbox.setInformativeText('Do you want to see the error in the diagram?') msgbox.setStandardButtons(QMessageBox.Yes|QMessageBox.No) S = QSpacerItem(400, 0, QSizePolicy.Minimum, QSizePolicy.Expanding) L = msgbox.layout() L.addItem(S, L.rowCount(), 0, 1, L.columnCount()) msgbox.exec_() if msgbox.result() == QMessageBox.Yes: for view in self.scene.views(): if isinstance(view, MainView): view.centerOn(exception.item) else: msgbox = QMessageBox(self) msgbox.setIconPixmap(QPixmap(':/icons/error')) msgbox.setWindowIcon(QIcon(':/images/eddy')) msgbox.setWindowTitle('Unhandled exception!') msgbox.setStandardButtons(QMessageBox.Close) msgbox.setText('Diagram translation could not be completed!') msgbox.setInformativeText('Please <a href="{}">submit a bug report</a> with detailed information.'.format(BUG_TRACKER)) msgbox.setDetailedText(''.join(traceback.format_exception(type(exception), exception, exception.__traceback__))) S = QSpacerItem(400, 0, QSizePolicy.Minimum, QSizePolicy.Expanding) L = msgbox.layout() L.addItem(S, L.rowCount(), 0, 1, L.columnCount()) msgbox.exec_() self.workerThread.quit() self.reject() @pyqtSlot() def completed(self): """ Executed whenever the translation completes. """ self.workerThread.quit() file = File(path=self.filepath) file.write(string=self.worker.export(syntax=self.syntaxField.currentData())) msgbox = QMessageBox(self) msgbox.setIconPixmap(QPixmap(':/icons/info')) msgbox.setWindowIcon(QIcon(':/images/eddy')) msgbox.setText('Translation completed!') msgbox.setInformativeText('Do you want to open the OWL ontology?') msgbox.setStandardButtons(QMessageBox.Yes|QMessageBox.No) S = QSpacerItem(400, 0, QSizePolicy.Minimum, QSizePolicy.Expanding) L = msgbox.layout() L.addItem(S, L.rowCount(), 0, 1, L.columnCount()) msgbox.exec_() if msgbox.result() == QMessageBox.Yes: openPath(self.filepath) self.accept() @pyqtSlot(int, int) def progress(self, current, total): """ Update the progress bar showing the translation advancement. :type current: int :type total: int """ self.progressBar.setRange(0, total) self.progressBar.setValue(current) @pyqtSlot() def iriChanged(self): """ Executed whenever the value of the prefix field changes. """ button = self.buttonBox.button(QDialogButtonBox.Ok) button.setEnabled(not isEmpty(self.iriField.value())) @pyqtSlot() def run(self): """ Perform the Graphol -> OWL translation in a separate thread. """ ontoIRI = self.iriField.value() ontoPrefix = self.prefixField.value() self.buttonBox.setEnabled(False) self.syntaxField.setEnabled(False) if not ontoIRI.endswith('#'): ontoIRI = '{0}#'.format(ontoIRI) self.workerThread = QThread() self.worker = OWLExporter(scene=self.scene, ontoIRI=ontoIRI, ontoPrefix=ontoPrefix) self.worker.moveToThread(self.workerThread) connect(self.worker.completed, self.completed) connect(self.worker.errored, self.errored) connect(self.worker.progress, self.progress) connect(self.workerThread.started, self.worker.work) self.workerThread.start()