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 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 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 NodeProperty(PropertyDialog): """ This class implements the 'Node property' dialog. """ def __init__(self, diagram, node, session): """ Initialize the node properties dialog. :type diagram: Diagram :type node: AbstractNode :type session: Session """ super().__init__(session) self.diagram = diagram self.node = node ############################################# # GENERAL TAB ################################# self.idLabel = QtWidgets.QLabel(self) self.idLabel.setFont(Font('Roboto', 12)) self.idLabel.setText('ID') self.idField = StringField(self) self.idField.setFont(Font('Roboto', 12)) self.idField.setFixedWidth(300) self.idField.setFocusPolicy(QtCore.Qt.NoFocus) self.idField.setReadOnly(True) self.idField.setValue(self.node.id) self.typeLabel = QtWidgets.QLabel(self) self.typeLabel.setFont(Font('Roboto', 12)) self.typeLabel.setText('Type') self.typeField = StringField(self) self.typeField.setFont(Font('Roboto', 12)) self.typeField.setFocusPolicy(QtCore.Qt.NoFocus) self.typeField.setFixedWidth(300) self.typeField.setReadOnly(True) self.typeField.setValue(node.shortName.capitalize()) self.identityLabel = QtWidgets.QLabel(self) self.identityLabel.setFont(Font('Roboto', 12)) self.identityLabel.setText('Identity') self.identityField = StringField(self) self.identityField.setFont(Font('Roboto', 12)) self.identityField.setFocusPolicy(QtCore.Qt.NoFocus) self.identityField.setFixedWidth(300) self.identityField.setReadOnly(True) self.identityField.setValue(self.node.identityName) self.neighboursLabel = QtWidgets.QLabel(self) self.neighboursLabel.setFont(Font('Roboto', 12)) self.neighboursLabel.setText('Neighbours') self.neighboursField = IntegerField(self) self.neighboursField.setFont(Font('Roboto', 12)) self.neighboursField.setFocusPolicy(QtCore.Qt.NoFocus) self.neighboursField.setFixedWidth(300) self.neighboursField.setReadOnly(True) self.neighboursField.setValue(len(self.node.adjacentNodes())) self.generalWidget = QtWidgets.QWidget() self.generalLayout = QtWidgets.QFormLayout(self.generalWidget) self.generalLayout.addRow(self.idLabel, self.idField) self.generalLayout.addRow(self.typeLabel, self.typeField) self.generalLayout.addRow(self.identityLabel, self.identityField) self.generalLayout.addRow(self.neighboursLabel, self.neighboursField) ############################################# # GEOMETRY TAB ################################# nodePos = self.node.pos() sceneRect = self.diagram.sceneRect() self.xLabel = QtWidgets.QLabel(self) self.xLabel.setFont(Font('Roboto', 12)) self.xLabel.setText('X') self.xField = SpinBox(self) self.xField.setFixedWidth(60) self.xField.setFont(Font('Roboto', 12)) self.xField.setRange(sceneRect.left(), sceneRect.right()) self.xField.setValue(int(nodePos.x())) self.yLabel = QtWidgets.QLabel(self) self.yLabel.setFont(Font('Roboto', 12)) self.yLabel.setText('Y') self.yField = SpinBox(self) self.yField.setFixedWidth(60) self.yField.setFont(Font('Roboto', 12)) self.yField.setRange(sceneRect.top(), sceneRect.bottom()) self.yField.setValue(int(nodePos.y())) self.widthLabel = QtWidgets.QLabel(self) self.widthLabel.setFont(Font('Roboto', 12)) self.widthLabel.setText('Width') self.widthField = SpinBox(self) self.widthField.setFixedWidth(60) self.widthField.setFont(Font('Roboto', 12)) self.widthField.setRange(20, sceneRect.width()) self.widthField.setReadOnly(True) self.widthField.setValue(int(self.node.width())) self.heightLabel = QtWidgets.QLabel(self) self.heightLabel.setFont(Font('Roboto', 12)) self.heightLabel.setText('Height') self.heightField = SpinBox(self) self.heightField.setFixedWidth(60) self.heightField.setFont(Font('Roboto', 12)) self.heightField.setRange(20, sceneRect.height()) self.heightField.setReadOnly(True) self.heightField.setValue(int(self.node.height())) self.geometryWidget = QtWidgets.QWidget() self.geometryLayout = QtWidgets.QFormLayout(self.geometryWidget) self.geometryLayout.addRow(self.xLabel, self.xField) self.geometryLayout.addRow(self.yLabel, self.yField) self.geometryLayout.addRow(self.widthLabel, self.widthField) self.geometryLayout.addRow(self.heightLabel, self.heightField) ############################################# # CONFIRMATION BOX ################################# 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)) ############################################# # MAIN WIDGET ################################# self.mainWidget = QtWidgets.QTabWidget(self) self.mainWidget.addTab(self.generalWidget, 'General') self.mainWidget.addTab(self.geometryWidget, 'Geometry') self.mainLayout = QtWidgets.QVBoxLayout(self) self.mainLayout.setContentsMargins(0, 0, 0, 0) self.mainLayout.addWidget(self.mainWidget) self.mainLayout.addWidget(self.confirmationBox, 0, QtCore.Qt.AlignRight) self.setWindowTitle('Properties: {0}'.format(self.node)) self.setWindowIcon(QtGui.QIcon(':/icons/128/ic_eddy')) connect(self.confirmationBox.accepted, self.complete) connect(self.confirmationBox.rejected, self.reject) ############################################# # SLOTS ################################# @QtCore.pyqtSlot() def complete(self): """ Executed when the dialog is accepted. """ commands = [self.positionChanged()] 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 positionChanged(self): """ Move the node properly if the position has been changed. :rtype: QUndoCommand """ rect = self.diagram.sceneRect() xPos = clamp(self.xField.value(), rect.left(), rect.right()) yPos = clamp(self.yField.value(), rect.top(), rect.bottom()) pos1 = self.node.pos() pos2 = QtCore.QPointF(xPos, yPos) if pos1 != pos2: initData = self.diagram.setupMove([self.node]) moveData = self.diagram.completeMove(initData, pos2 - pos1) return CommandNodeMove(self.diagram, initData, moveData) return None
class AbstractDiagramForm(QtWidgets.QDialog): """ Base class for diagram dialogs. """ __metaclass__ = ABCMeta def __init__(self, project, parent=None): """ Initialize the dialog. :type project: Project :type parent: QtWidgets.QWidget """ super().__init__(parent) self.project = project ############################################# # FORM AREA ################################# self.nameField = StringField(self) self.nameField.setFont(Font('Roboto', 12)) self.nameField.setMinimumWidth(400) self.nameField.setMaxLength(64) self.nameField.setPlaceholderText('Name...') connect(self.nameField.textChanged, self.onNameFieldChanged) self.warnLabel = QtWidgets.QLabel(self) self.warnLabel.setContentsMargins(0, 0, 0, 0) self.warnLabel.setProperty('class', 'invalid') self.warnLabel.setVisible(False) ############################################# # CONFIRMATION AREA ################################# self.confirmationBox = QtWidgets.QDialogButtonBox(QtCore.Qt.Horizontal, self) self.confirmationBox.addButton(QtWidgets.QDialogButtonBox.Ok) self.confirmationBox.addButton(QtWidgets.QDialogButtonBox.Cancel) self.confirmationBox.setFont(Font('Roboto', 12)) self.confirmationBox.button(QtWidgets.QDialogButtonBox.Ok).setEnabled(False) ############################################# # SETUP DIALOG LAYOUT ################################# self.mainLayout = QtWidgets.QVBoxLayout(self) self.mainLayout.setContentsMargins(10, 10, 10, 10) self.mainLayout.addWidget(self.nameField) self.mainLayout.addWidget(self.warnLabel) self.mainLayout.addWidget(self.confirmationBox, 0, QtCore.Qt.AlignRight) self.setFixedSize(self.sizeHint()) self.setWindowIcon(QtGui.QIcon(':/icons/128/ic_eddy')) connect(self.confirmationBox.accepted, self.accept) connect(self.confirmationBox.rejected, self.reject) ############################################# # SLOTS ################################# @QtCore.pyqtSlot(str) def onNameFieldChanged(self, name): """ Executed when the content of the input field changes. :type name: str """ name = name.strip() if not name: caption = '' enabled = False else: for diagram in self.project.diagrams(): if diagram.name.upper() == name.upper(): caption = "Diagram '{0}' already exists!".format(name) enabled = False break else: caption = '' enabled = True self.warnLabel.setText(caption) self.warnLabel.setVisible(not isEmpty(caption)) self.confirmationBox.button(QtWidgets.QDialogButtonBox.Ok).setEnabled(enabled) self.setFixedSize(self.sizeHint())
class 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('IRI label') self.renameField = StringField(self) self.renameField.setFixedWidth(200) self.renameField.setFont(Font('Roboto', 12)) 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.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) 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. """ 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 std_iri in OWLStandardIRIPrefixPairsDict.std_IRI_prefix_dict.keys( ): std_prefix = OWLStandardIRIPrefixPairsDict.std_IRI_prefix_dict[ std_iri] if std_prefix == new_prefix: new_iri = std_iri 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)) 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: #self.setText(self.old_text) exception_list = ['-', '_', '.', '~', '\n'] currentData_processed = '' flag = False for i, c in enumerate(currentData): # i ranges from 0->len(currentDate)-1 inc. 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.iri 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 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 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.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 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 NodeProperty(PropertyDialog): """ This class implements the 'Node property' dialog. """ def __init__(self, diagram, node, session): """ Initialize the node properties dialog. :type diagram: Diagram :type node: AbstractNode :type session: Session """ super().__init__(session) self.diagram = diagram self.node = node ############################################# # GENERAL TAB ################################# self.idLabel = QtWidgets.QLabel(self) self.idLabel.setFont(Font('Roboto', 12)) self.idLabel.setText('ID') self.idField = StringField(self) self.idField.setFont(Font('Roboto', 12)) self.idField.setFixedWidth(300) self.idField.setFocusPolicy(QtCore.Qt.NoFocus) self.idField.setReadOnly(True) self.idField.setValue(self.node.id) self.typeLabel = QtWidgets.QLabel(self) self.typeLabel.setFont(Font('Roboto', 12)) self.typeLabel.setText('Type') self.typeField = StringField(self) self.typeField.setFont(Font('Roboto', 12)) self.typeField.setFocusPolicy(QtCore.Qt.NoFocus) self.typeField.setFixedWidth(300) self.typeField.setReadOnly(True) self.typeField.setValue(node.shortName.capitalize()) self.identityLabel = QtWidgets.QLabel(self) self.identityLabel.setFont(Font('Roboto', 12)) self.identityLabel.setText('Identity') self.identityField = StringField(self) self.identityField.setFont(Font('Roboto', 12)) self.identityField.setFocusPolicy(QtCore.Qt.NoFocus) self.identityField.setFixedWidth(300) self.identityField.setReadOnly(True) self.identityField.setValue(self.node.identityName) self.neighboursLabel = QtWidgets.QLabel(self) self.neighboursLabel.setFont(Font('Roboto', 12)) self.neighboursLabel.setText('Neighbours') self.neighboursField = IntegerField(self) self.neighboursField.setFont(Font('Roboto', 12)) self.neighboursField.setFocusPolicy(QtCore.Qt.NoFocus) self.neighboursField.setFixedWidth(300) self.neighboursField.setReadOnly(True) self.neighboursField.setValue(len(self.node.adjacentNodes())) self.generalWidget = QtWidgets.QWidget() self.generalLayout = QtWidgets.QFormLayout(self.generalWidget) self.generalLayout.addRow(self.idLabel, self.idField) self.generalLayout.addRow(self.typeLabel, self.typeField) self.generalLayout.addRow(self.identityLabel, self.identityField) self.generalLayout.addRow(self.neighboursLabel, self.neighboursField) ############################################# # GEOMETRY TAB ################################# nodePos = self.node.pos() sceneRect = self.diagram.sceneRect() self.xLabel = QtWidgets.QLabel(self) self.xLabel.setFont(Font('Roboto', 12)) self.xLabel.setText('X') self.xField = SpinBox(self) self.xField.setFixedWidth(60) self.xField.setFont(Font('Roboto', 12)) self.xField.setRange(sceneRect.left(), sceneRect.right()) self.xField.setValue(int(nodePos.x())) self.yLabel = QtWidgets.QLabel(self) self.yLabel.setFont(Font('Roboto', 12)) self.yLabel.setText('Y') self.yField = SpinBox(self) self.yField.setFixedWidth(60) self.yField.setFont(Font('Roboto', 12)) self.yField.setRange(sceneRect.top(), sceneRect.bottom()) self.yField.setValue(int(nodePos.y())) self.widthLabel = QtWidgets.QLabel(self) self.widthLabel.setFont(Font('Roboto', 12)) self.widthLabel.setText('Width') self.widthField = SpinBox(self) self.widthField.setFixedWidth(60) self.widthField.setFont(Font('Roboto', 12)) self.widthField.setRange(20, sceneRect.width()) self.widthField.setReadOnly(True) self.widthField.setValue(int(self.node.width())) self.heightLabel = QtWidgets.QLabel(self) self.heightLabel.setFont(Font('Roboto', 12)) self.heightLabel.setText('Height') self.heightField = SpinBox(self) self.heightField.setFixedWidth(60) self.heightField.setFont(Font('Roboto', 12)) self.heightField.setRange(20, sceneRect.height()) self.heightField.setReadOnly(True) self.heightField.setValue(int(self.node.height())) self.geometryWidget = QtWidgets.QWidget() self.geometryLayout = QtWidgets.QFormLayout(self.geometryWidget) self.geometryLayout.addRow(self.xLabel, self.xField) self.geometryLayout.addRow(self.yLabel, self.yField) self.geometryLayout.addRow(self.widthLabel, self.widthField) self.geometryLayout.addRow(self.heightLabel, self.heightField) ############################################# # CONFIRMATION BOX ################################# 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)) ############################################# # MAIN WIDGET ################################# self.mainWidget = QtWidgets.QTabWidget(self) self.mainWidget.addTab(self.generalWidget, 'General') self.mainWidget.addTab(self.geometryWidget, 'Geometry') self.mainLayout = QtWidgets.QVBoxLayout(self) self.mainLayout.setContentsMargins(0, 0, 0, 0) self.mainLayout.addWidget(self.mainWidget) self.mainLayout.addWidget(self.confirmationBox, 0, QtCore.Qt.AlignRight) self.setWindowTitle('Properties: {0}'.format(self.node)) self.setWindowIcon(QtGui.QIcon(':/icons/128/ic_eddy')) connect(self.confirmationBox.accepted, self.complete) connect(self.confirmationBox.rejected, self.reject) ############################################# # SLOTS ################################# @QtCore.pyqtSlot() def complete(self): """ Executed when the dialog is accepted. """ commands = [self.positionChanged()] 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 positionChanged(self): """ Move the node properly if the position has been changed. :rtype: QUndoCommand """ rect = self.diagram.sceneRect() xPos = clamp(self.xField.value(), rect.left(), rect.right()) yPos = clamp(self.yField.value(), rect.top(), rect.bottom()) pos1 = self.node.pos() pos2 = QtCore.QPointF(xPos, yPos) if pos1 != pos2: node = self.node data = { 'redo': { 'nodes': {node: {'anchors': {k: v + pos2 - pos1 for k, v in node.anchors.items()}, 'pos': pos2}}, 'edges': {}, }, 'undo': { 'nodes': {node: {'anchors': {k: v for k, v in node.anchors.items()}, 'pos': pos1}}, 'edges': {} } } return CommandNodeMove(self.diagram, data) return None
class AbstractDiagramForm(QtWidgets.QDialog): """ Base class for diagram dialogs. """ __metaclass__ = ABCMeta def __init__(self, project, parent=None): """ Initialize the dialog. :type project: Project :type parent: QtWidgets.QWidget """ super().__init__(parent) self.project = project ############################################# # FORM AREA ################################# self.nameField = StringField(self) self.nameField.setFont(Font('Roboto', 12)) self.nameField.setMinimumWidth(400) self.nameField.setMaxLength(64) self.nameField.setPlaceholderText('Name...') connect(self.nameField.textChanged, self.onNameFieldChanged) self.warnLabel = QtWidgets.QLabel(self) self.warnLabel.setContentsMargins(0, 0, 0, 0) self.warnLabel.setProperty('class', 'invalid') self.warnLabel.setVisible(False) ############################################# # CONFIRMATION AREA ################################# self.confirmationBox = QtWidgets.QDialogButtonBox( QtCore.Qt.Horizontal, self) self.confirmationBox.addButton(QtWidgets.QDialogButtonBox.Ok) self.confirmationBox.addButton(QtWidgets.QDialogButtonBox.Cancel) self.confirmationBox.setFont(Font('Roboto', 12)) self.confirmationBox.button( QtWidgets.QDialogButtonBox.Ok).setEnabled(False) ############################################# # SETUP DIALOG LAYOUT ################################# self.mainLayout = QtWidgets.QVBoxLayout(self) self.mainLayout.setContentsMargins(10, 10, 10, 10) self.mainLayout.addWidget(self.nameField) self.mainLayout.addWidget(self.warnLabel) self.mainLayout.addWidget(self.confirmationBox, 0, QtCore.Qt.AlignRight) self.setFixedSize(self.sizeHint()) self.setWindowIcon(QtGui.QIcon(':/icons/128/ic_eddy')) connect(self.confirmationBox.accepted, self.accept) connect(self.confirmationBox.rejected, self.reject) ############################################# # SLOTS ################################# @QtCore.pyqtSlot(str) def onNameFieldChanged(self, name): """ Executed when the content of the input field changes. :type name: str """ name = name.strip() if not name: caption = '' enabled = False else: for diagram in self.project.diagrams(): if diagram.name.upper() == name.upper(): caption = "Diagram '{0}' already exists!".format(name) enabled = False break else: caption = '' enabled = True self.warnLabel.setText(caption) self.warnLabel.setVisible(not isEmpty(caption)) self.confirmationBox.button( QtWidgets.QDialogButtonBox.Ok).setEnabled(enabled) self.setFixedSize(self.sizeHint())
class 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 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) self.node = node ############################################# # 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()] 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 std_iri in OWLStandardIRIPrefixPairsDict.std_IRI_prefix_dict.keys( ): std_prefix = OWLStandardIRIPrefixPairsDict.std_IRI_prefix_dict[ std_iri] if std_prefix == new_prefix: new_iri = std_iri 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 = [] commands.append( CommandLabelChange(self.diagram, self.node, self.node.text(), data)) commands.append( CommandProjetSetIRIPrefixesNodesDict(self.project, Duplicate_dict_2, Duplicate_dict_1, [old_iri, new_iri], [self.node])) commands.append(CommandNodeSetRemainingCharacters(self.node.remaining_characters,\ new_remaining_characters,self.node,self.project)) commands.append( CommandLabelChange(self.diagram, self.node, self.node.text(), data)) return commands return None
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 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.setFont(Font('Roboto', 12)) self.iriLabel.setText('IRI') self.iriField = StringField(self) self.iriField.setFixedWidth(300) self.iriField.setFont(Font('Roboto', 12)) self.iriField.setValue(self.diagram.project.get_iri_of_node(node)) """ self.iriversionLabel = QtWidgets.QLabel(self) self.iriversionLabel.setFont(Font('Roboto', 12)) self.iriversionLabel.setText('IRI version') self.iriversionField = StringField(self) self.iriversionField.setFixedWidth(300) self.iriversionField.setFont(Font('Roboto', 12)) self.iriversionField.setValue(self.node.IRI_version(diagram.project)) """ ############################################# # LABEL TAB ################################# self.textLabel = QtWidgets.QLabel(self) self.textLabel.setFont(Font('Roboto', 12)) self.textLabel.setText('IRI Label') self.textField = StringField(self) self.textField.setFixedWidth(300) self.textField.setFont(Font('Roboto', 12)) #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.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 (('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.setFont(Font('Roboto', 12)) self.FulliriLabel.setText('Full IRI') self.FulliriField = StringField(self) self.FulliriField.setFixedWidth(300) self.FulliriField.setFont(Font('Roboto', 12)) 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)) commands.append( CommandProjetSetIRIPrefixesNodesDict( self.project, Duplicate_dict_2, Duplicate_dict_1, [new_iri, old_iri], list_of_nodes_to_process)) 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 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 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()))