def action_new(self): """The new model menu action. This action will create a new UML model. This will trigger a FileManagerStateChange event.""" element_factory = self.element_factory main_window = self.main_window if element_factory.size(): dialog = QuestionDialog(_("Opening a new model will flush the"\ " currently loaded model.\nAny changes"\ " made will not be saved. Do you want to"\ " continue?"),\ parent=main_window.window) answer = dialog.answer dialog.destroy() if not answer: return element_factory.flush() model = element_factory.create(UML.Package) model.name = _('New model') diagram = element_factory.create(UML.Diagram) diagram.package = model diagram.name= _('main') self.filename = None element_factory.notify_model() #main_window.select_element(diagram) #main_window.show_diagram(diagram) self.component_registry.handle(FileManagerStateChanged(self))
def ask_to_close(self): """ Ask user to close window if the model has changed. The user is asked to either discard the changes, keep the application running or save the model and quit afterwards. """ if self.model_changed: dialog = gtk.MessageDialog(self.window, gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT, gtk.MESSAGE_WARNING, gtk.BUTTONS_NONE, _('Save changed to your model before closing?')) dialog.format_secondary_text( _('If you close without saving, your changes will be discarded.')) dialog.add_buttons('Close _without saving', gtk.RESPONSE_REJECT, gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL, gtk.STOCK_SAVE, gtk.RESPONSE_YES) dialog.set_default_response(gtk.RESPONSE_YES) response = dialog.run() dialog.destroy() if response == gtk.RESPONSE_YES: # On filedialog.cancel, the application should not close. return self.file_manager.action_save() return response == gtk.RESPONSE_REJECT return True
def construct(self): page = gtk.VBox() hbox = gtk.HBox() label = gtk.Label('') label.set_justify(gtk.JUSTIFY_LEFT) self.size_group.add_widget(label) hbox.pack_start(label, expand=False) button = gtk.CheckButton(_('Orthogonal')) button.set_active(self.item.orthogonal) button.connect('toggled', self._on_orthogonal_change) hbox.pack_start(button) page.pack_start(hbox, expand=False) if len(self.item.handles()) < 3: # Only one segment button.props.sensitive = False hbox = gtk.HBox() label = gtk.Label('') label.set_justify(gtk.JUSTIFY_LEFT) self.size_group.add_widget(label) hbox.pack_start(label, expand=False) button = gtk.CheckButton(_('Horizontal')) button.set_active(self.item.horizontal) button.connect('toggled', self._on_horizontal_change) hbox.pack_start(button) page.pack_start(hbox, expand=False) return page
def construct(self): page = super(StatePropertyPage, self).construct() subject = self.subject if not subject: return page hbox = create_hbox_label(self, page, _('Entry')) entry = gtk.Entry() if self.item._entry.subject: entry.set_text(self.item._entry.subject.name) entry.connect('changed', self._on_text_change, self.item.set_entry) hbox.pack_start(entry) hbox = create_hbox_label(self, page, _('Exit')) entry = gtk.Entry() if self.item._exit.subject: entry.set_text(self.item._exit.subject.name) entry.connect('changed', self._on_text_change, self.item.set_exit) hbox.pack_start(entry) hbox = create_hbox_label(self, page, _('Do Activity')) entry = gtk.Entry() if self.item._do_activity.subject: entry.set_text(self.item._do_activity.subject.name) entry.connect('changed', self._on_text_change, self.item.set_do_activity) hbox.pack_start(entry) page.show_all() return page
def construct(self): page = super(ObjectNodePropertyPage, self).construct() subject = self.subject if not subject: return page hbox = create_hbox_label(self, page, _('Upper bound')) entry = gtk.Entry() entry.set_text(subject.upperBound and subject.upperBound.value or '') entry.connect('changed', self._on_upper_bound_change) hbox.pack_start(entry) hbox = create_hbox_label(self, page, '') combo = gtk.combo_box_new_text() for v in self.ORDERING_VALUES: combo.append_text(v) combo.set_active(self.ORDERING_VALUES.index(subject.ordering)) combo.connect('changed', self._on_ordering_change) hbox.pack_start(combo, expand=False) hbox = create_hbox_label(self, page, '') button = gtk.CheckButton(_('Ordering')) button.set_active(self.item.show_ordering) button.connect('toggled', self._on_ordering_show_change) hbox.pack_start(button, expand=False) return page
def ask_to_close(self): """ Ask user to close window if the model has changed. The user is asked to either discard the changes, keep the application running or save the model and quit afterwards. """ if self.model_changed: dialog = Gtk.MessageDialog( self.window, Gtk.DialogFlags.MODAL | Gtk.DialogFlags.DESTROY_WITH_PARENT, Gtk.MessageType.WARNING, Gtk.ButtonsType.NONE, _("Save changed to your model before closing?"), ) dialog.format_secondary_text( _("If you close without saving, your changes will be discarded.") ) dialog.add_buttons( "Close _without saving", Gtk.ResponseType.REJECT, Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL, Gtk.STOCK_SAVE, Gtk.ResponseType.YES, ) dialog.set_default_response(Gtk.ResponseType.YES) response = dialog.run() dialog.destroy() if response == Gtk.ResponseType.YES: # On filedialog.cancel, the application should not close. return self.file_manager.action_save() return response == Gtk.ResponseType.REJECT return True
def construct(self): page = super(AssociationPropertyPage, self).construct() if not self.subject: return page hbox = gtk.HBox() label = gtk.Label('') label.set_justify(gtk.JUSTIFY_LEFT) self.size_group.add_widget(label) hbox.pack_start(label, expand=False) button = gtk.CheckButton(_('Show direction')) button.set_active(self.item.show_direction) button.connect('toggled', self._on_show_direction_change) hbox.pack_start(button) button = gtk.Button(_('Invert Direction')) button.connect('clicked', self._on_invert_direction_change) hbox.pack_start(button) page.pack_start(hbox, expand=False) box = self.construct_end(_('Head'), self.item.head_end) if box: page.pack_start(box, expand=False) box = self.construct_end(_('Tail'), self.item.tail_end) if box: page.pack_start(box, expand=False) self.update() return page
def load(self, filename): """Load the Gaphor model from the supplied file name. A status window displays the loading progress. The load generator updates the progress queue. The loader is passed to a GIdleThread which executes the load generator. If loading is successful, the filename is set.""" self.logger.info('Loading file') self.logger.debug('Path is %s' % filename) main_window = self.main_window queue = Queue() status_window = StatusWindow(_('Loading...'),\ _('Loading model from %s') % filename,\ parent=main_window.window,\ queue=queue) loader = storage.load_generator(filename, self.element_factory) worker = GIdleThread(loader, queue) worker.start() worker.wait() if worker.error: self.logger.error('Error loading file: ', exc_info=worker.exc_info) #self.logger.error(worker.error) self.filename = filename status_window.destroy()
def create_stereotype_tree_view(model, toggle_stereotype, set_slot_value): """ Create a tree view for an editable tree model. :Parameters: model Model, for which tree view is created. """ tree_view = Gtk.TreeView.new_with_model(model) # Stereotype/Attributes col = Gtk.TreeViewColumn.new() col.set_title("%s / %s" % (_("Stereotype"), _("Attribute"))) col.set_expand(True) renderer = Gtk.CellRendererToggle() renderer.set_property("active", True) renderer.set_property("activatable", True) renderer.connect("toggled", toggle_stereotype, model, 2) col.pack_start(renderer, False) col.add_attribute(renderer, "active", 2) def show_checkbox(column, cell, model, iter, data): # value = model.get_value(iter, 4) # cell.set_property('active', value is not None) value = model.get_value(iter, 3) cell.set_property("visible", isinstance(value, UML.Stereotype)) col.set_cell_data_func(renderer, show_checkbox) renderer = Gtk.CellRendererText.new() renderer.set_property("editable", False) renderer.set_property("is-expanded", True) col.pack_start(renderer, False) col.add_attribute(renderer, "text", 0) tree_view.append_column(col) # TODO: use col.set_cell_data_func(renderer, func, None) to toggle visibility # Value renderer = Gtk.CellRendererText() renderer.set_property("is-expanded", True) renderer.connect("edited", set_slot_value, model, 1) col = Gtk.TreeViewColumn(_("Value"), renderer, text=1) col.set_expand(True) def set_editable(column, cell, model, iter, data): value = model.get_value(iter, 4) cell.set_property("editable", bool(value)) col.set_cell_data_func(renderer, set_editable) tree_view.append_column(col) # tree_view.connect('key_press_event', remove_on_keypress) # tree_view.connect('key_press_event', swap_on_keypress) return tree_view
def dock_item_factory(parent, title, tooltip, icon_name=None, stock_id=None, pos=None, vispos=None, current=None, name=None): item = DockItem(_(title), _(tooltip), icon_name, stock_id) if name: item.set_name(name) if pos: pos = int(pos) if vispos: vispos = int(vispos) parent.insert_item(item, pos, vispos) item.show() return item
def create_stereotype_tree_view(model): """ Create a tree view for a editable tree model. :Parameters: model Model, for which tree view is created. """ tree_view = gtk.TreeView(model) tree_view.set_rules_hint(True) # Stereotype/Attributes col = gtk.TreeViewColumn('%s / %s' % (_('Stereotype'), _('Attribute'))) col.set_expand(True) renderer = gtk.CellRendererToggle() renderer.set_property('active', True) renderer.set_property('activatable', True) renderer.connect('toggled', on_bool_cell_edited, model, 2) col.pack_start(renderer, expand=False) col.add_attribute(renderer, 'active', 2) def show_checkbox(column, cell, model, iter): #value = model.get_value(iter, 4) #cell.set_property('active', value is not None) value = model.get_value(iter, 3) cell.set_property('visible', isinstance(value, UML.Stereotype)) col.set_cell_data_func(renderer, show_checkbox) renderer = gtk.CellRendererText() renderer.set_property('editable', False) renderer.set_property('is-expanded', True) col.pack_start(renderer, expand=False) col.add_attribute(renderer, 'text', 0) tree_view.append_column(col) # TODO: use col.set_cell_data_func(renderer, func, None) to toggle visibility # Value renderer = gtk.CellRendererText() renderer.set_property('is-expanded', True) renderer.connect('edited', on_text_cell_edited, model, 1) col = gtk.TreeViewColumn(_('Value'), renderer, text=1) col.set_expand(True) def set_editable(column, cell, model, iter): value = model.get_value(iter, 4) cell.set_property('editable', bool(value)) col.set_cell_data_func(renderer, set_editable) tree_view.append_column(col) #tree_view.connect('key_press_event', remove_on_keypress) #tree_view.connect('key_press_event', swap_on_keypress) return tree_view
def construct(self): page = gtk.VBox() if not self.item.subject: return page # Show operations toggle hbox = gtk.HBox() label = gtk.Label("") label.set_justify(gtk.JUSTIFY_LEFT) hbox.pack_start(label, expand=False) button = gtk.CheckButton(_("Show operations")) button.set_active(self.item.show_operations) button.connect('toggled', self._on_show_operations_change) hbox.pack_start(button) page.pack_start(hbox, expand=False) def create_model(): return ClassOperations(self.item, (str, bool, bool, object)) self.model = create_model() tip = """\ Add and edit class operations according to UML syntax. Operation syntax examples - call() - + call(a: int, b: str) - # call(a: int: b: str): bool """ tree_view = create_tree_view(self.model, (_('Operation'), _('A'), _('S')), tip) page.pack_start(tree_view) @async(single=True) def handler(event): if not tree_view.props.has_focus and self.item and self.item.subject: self.model = create_model() tree_view.set_model(self.model) self.watcher.watch('ownedOperation.name', handler) \ .watch('ownedOperation.isAbstract', handler) \ .watch('ownedOperation.visibility', handler) \ .watch('ownedOperation.returnResult.lowerValue<LiteralSpecification>.value', handler) \ .watch('ownedOperation.returnResult.upperValue<LiteralSpecification>.value', handler) \ .watch('ownedOperation.returnResult.typeValue<LiteralSpecification>.value', handler) \ .watch('ownedOperation.formalParameter.lowerValue<LiteralSpecification>.value', handler) \ .watch('ownedOperation.formalParameter.upperValue<LiteralSpecification>.value', handler) \ .watch('ownedOperation.formalParameter.typeValue<LiteralSpecification>.value', handler) \ .watch('ownedOperation.formalParameter.defaultValue<LiteralSpecification>.value', handler) \ .register_handlers() tree_view.connect('destroy', self.watcher.unregister_handlers) return page
def construct(self): page = gtk.VBox() if not self.item.subject: return page # Show attributes toggle hbox = gtk.HBox() label = gtk.Label('') label.set_justify(gtk.JUSTIFY_LEFT) hbox.pack_start(label, expand=False) button = gtk.CheckButton(_('Show attributes')) button.set_active(self.item.show_attributes) button.connect('toggled', self._on_show_attributes_change) hbox.pack_start(button) page.pack_start(hbox, expand=False) def create_model(): return ClassAttributes(self.item, (str, bool, object)) self.model = create_model() tip = """\ Add and edit class attributes according to UML syntax. Attribute syntax examples - attr - + attr: int - # /attr: int """ tree_view = create_tree_view(self.model, (_('Attributes'), _('S')), tip) page.pack_start(tree_view) @async(single=True) def handler(event): # Single it's asynchronous, make sure all properties are still there if not tree_view.props.has_focus and self.item and self.item.subject: self.model = create_model() tree_view.set_model(self.model) self.watcher.watch('ownedAttribute.name', handler) \ .watch('ownedAttribute.isDerived', handler) \ .watch('ownedAttribute.visibility', handler) \ .watch('ownedAttribute.isStatic', handler) \ .watch('ownedAttribute.lowerValue<LiteralSpecification>.value', handler) \ .watch('ownedAttribute.upperValue<LiteralSpecification>.value', handler) \ .watch('ownedAttribute.defaultValue<LiteralSpecification>.value', handler) \ .watch('ownedAttribute.typeValue<LiteralSpecification>.value', handler) \ .register_handlers() tree_view.connect('destroy', self.watcher.unregister_handlers) return page
def verify_orphans(self): """Verify that no orphaned elements are saved. This method checks of there are any orphan references in the element factory. If orphans are found, a dialog is displayed asking the user if it is OK to unlink them.""" orphans = verify.orphan_references(self.element_factory) if orphans: main_window = self.main_window dialog = QuestionDialog( _( "The model contains some references" " to items that are not maintained." " Do you want to clean this before" " saving the model?" ), parent=main_window.window, ) answer = dialog.answer dialog.destroy() if not answer: for orphan in orphans: orphan.unlink()
def construct(self): page = super(TransitionPropertyPage, self).construct() subject = self.subject if not subject: return page hbox = create_hbox_label(self, page, _('Guard')) entry = gtk.Entry() v = subject.guard.specification entry.set_text(v if v else '') entry.connect('changed', self._on_guard_change) changed_id = entry.connect('changed', self._on_guard_change) hbox.pack_start(entry) def handler(event): entry.handler_block(changed_id) v = event.new_value entry.set_text(v if v else '') entry.handler_unblock(changed_id) self.watcher.watch('guard<Constraint>.specification', handler).register_handlers() entry.connect('destroy', self.watcher.unregister_handlers) return page
def save_dialog(self, diagram, title, ext): filename = (diagram.name or "export") + ext file_dialog = FileDialog(title, action="save", filename=filename) save = False while True: filename = file_dialog.selection if os.path.exists(filename): question = ( _( "The file %s already exists. Do you want to " "replace it with the file you are exporting " "to?" ) % filename ) question_dialog = QuestionDialog(question) answer = question_dialog.answer question_dialog.destroy() if answer: save = True break else: save = True break file_dialog.destroy() if save and filename: return filename
def construct(self): subject = self.subject page = gtk.VBox() if not subject: return page label = gtk.Label(_('Comment')) label.set_justify(gtk.JUSTIFY_LEFT) page.pack_start(label, expand=False) buffer = gtk.TextBuffer() if subject.body: buffer.set_text(subject.body) text_view = gtk.TextView() text_view.set_buffer(buffer) text_view.show() text_view.set_size_request(-1, 100) page.pack_start(text_view) page.set_data('default', text_view) changed_id = buffer.connect('changed', self._on_body_change) def handler(event): if not text_view.props.has_focus: buffer.handler_block(changed_id) buffer.set_text(event.new_value) buffer.handler_unblock(changed_id) self.watcher.watch('body', handler) \ .register_handlers() text_view.connect("destroy", self.watcher.unregister_handlers) return page
def construct(self): subject = self.subject page = gtk.VBox() if not subject: return page label = gtk.Label(_('Comment')) label.set_justify(gtk.JUSTIFY_LEFT) page.pack_start(label, expand=False) buffer = gtk.TextBuffer() if subject.body: buffer.set_text(subject.body) text_view = gtk.TextView() text_view.set_buffer(buffer) text_view.show() text_view.set_size_request(-1, 100) page.pack_start(text_view) page.set_data('default', text_view) changed_id = buffer.connect('changed', self._on_body_change) def handler(event): if not text_view.props.has_focus: buffer.handler_block(changed_id) buffer.set_text(event.new_value) buffer.handler_unblock(changed_id) self.watcher.watch('body', handler) \ .register_handlers() text_view.connect("destroy", self.watcher.unregister_handlers) return page
def construct(self): page = super(InterfacePropertyPage, self).construct() item = self.item # Fold toggle hbox = gtk.HBox() label = gtk.Label('') label.set_justify(gtk.JUSTIFY_LEFT) self.size_group.add_widget(label) hbox.pack_start(label, expand=False) button = gtk.CheckButton(_("Folded")) button.set_active(item.folded) button.connect('toggled', self._on_fold_change) connected_items = [c.item for c in item.canvas.get_connections(connected=item)] allowed = (items.DependencyItem, items.ImplementationItem) can_fold = len(connected_items) == 0 \ or len(connected_items) == 1 and isinstance(connected_items[0], allowed) button.set_sensitive(can_fold) hbox.pack_start(button) page.pack_start(hbox, expand=False) return page
def construct(self): page = super(InterfacePropertyPage, self).construct() item = self.item # Fold toggle hbox = gtk.HBox() label = gtk.Label('') label.set_justify(gtk.JUSTIFY_LEFT) self.size_group.add_widget(label) hbox.pack_start(label, expand=False) button = gtk.CheckButton(_("Folded")) button.set_active(item.folded) button.connect('toggled', self._on_fold_change) connected_items = [ c.item for c in item.canvas.get_connections(connected=item) ] allowed = (items.DependencyItem, items.ImplementationItem) can_fold = len(connected_items) == 0 \ or len(connected_items) == 1 and isinstance(connected_items[0], allowed) button.set_sensitive(can_fold) hbox.pack_start(button) page.pack_start(hbox, expand=False) return page
def construct(self): page = super().construct() item = self.item # Fold toggle hbox = Gtk.HBox() label = Gtk.Label(label="") label.set_justify(Gtk.Justification.LEFT) self.size_group.add_widget(label) hbox.pack_start(label, False, True, 0) button = Gtk.CheckButton(_("Folded")) button.set_active(item.folded) button.connect("toggled", self._on_fold_change) connected_items = [ c.item for c in item.canvas.get_connections(connected=item) ] allowed = (DependencyItem, ImplementationItem) can_fold = (len(connected_items) == 0 or len(connected_items) == 1 and isinstance(connected_items[0], allowed)) button.set_sensitive(can_fold) hbox.pack_start(button, True, True, 0) page.pack_start(hbox, False, True, 0) return page
def construct(self): page = Gtk.VBox() subject = self.item.subject if subject is None: return None stereotypes = UML.model.get_stereotypes(self.element_factory, subject) if not stereotypes: return None # show stereotypes attributes toggle if isinstance(self.item, StereotypeSupport): hbox = Gtk.HBox() label = Gtk.Label(label="") hbox.pack_start(label, False, True, 0) button = Gtk.CheckButton(label=_("Show stereotypes attributes")) button.set_active(self.item.show_stereotypes_attrs) button.connect("toggled", self._on_show_stereotypes_attrs_change) hbox.pack_start(button, True, True, 0) page.pack_start(hbox, False, True, 0) # stereotype attributes # self.model = StereotypeAttributes(self.item.subject) self.model = Gtk.TreeStore.new( [str, str, bool, object, object, object]) tree_view = create_stereotype_tree_view(self.model, self._toggle_stereotype, self._set_value) page.pack_start(tree_view, True, True, 0) page.show_all() self.refresh() return page
def construct(self): page = Gtk.VBox() subject = self.item.subject if subject is None: return None stereotypes = UML.model.get_stereotypes(self.element_factory, subject) if not stereotypes: return None # show stereotypes attributes toggle if isinstance(self.item, StereotypeSupport): hbox = Gtk.HBox() label = Gtk.Label(label="") hbox.pack_start(label, False, True, 0) button = Gtk.CheckButton(label=_("Show stereotypes attributes")) button.set_active(self.item.show_stereotypes_attrs) button.connect("toggled", self._on_show_stereotypes_attrs_change) hbox.pack_start(button, True, True, 0) page.pack_start(hbox, False, True, 0) # stereotype attributes # self.model = StereotypeAttributes(self.item.subject) self.model = Gtk.TreeStore.new([str, str, bool, object, object, object]) tree_view = create_stereotype_tree_view( self.model, self._toggle_stereotype, self._set_value ) page.pack_start(tree_view, True, True, 0) page.show_all() self.refresh() return page
def construct(self): subject = self.subject page = Gtk.VBox() if not subject: return page label = Gtk.Label(label=_("Comment")) label.set_justify(Gtk.Justification.LEFT) page.pack_start(label, False, True, 0) buffer = Gtk.TextBuffer() if subject.body: buffer.set_text(subject.body) text_view = Gtk.TextView() text_view.set_buffer(buffer) text_view.show() text_view.set_size_request(-1, 100) page.pack_start(text_view, True, True, 0) page.default = text_view changed_id = buffer.connect("changed", self._on_body_change) def handler(event): if not text_view.props.has_focus: buffer.handler_block(changed_id) buffer.set_text(event.new_value) buffer.handler_unblock(changed_id) self.watcher.watch("body", handler).subscribe_all() text_view.connect("destroy", self.watcher.unsubscribe_all) return page
def save_dialog(self, diagram, title, ext): filename = (diagram.name or 'export') + ext file_dialog = FileDialog(title, action='save', filename=filename) save = False while True: filename = file_dialog.selection if os.path.exists(filename): question = _("The file %s already exists. Do you want to "\ "replace it with the file you are exporting "\ "to?") % filename question_dialog = QuestionDialog(question) answer = question_dialog.answer question_dialog.destroy() if answer: save = True break else: save = True break file_dialog.destroy() if save and filename: return filename
def construct(self): page = super(TransitionPropertyPage, self).construct() subject = self.subject if not subject: return page hbox = create_hbox_label(self, page, _('Guard')) entry = gtk.Entry() v = subject.guard.specification.value entry.set_text(v if v else '') entry.connect('changed', self._on_guard_change) changed_id = entry.connect('changed', self._on_guard_change) hbox.pack_start(entry) def handler(event): entry.handler_block(changed_id) v = event.new_value entry.set_text(v if v else '') entry.handler_unblock(changed_id) self.watcher.watch('guard<Constraint>.specification<LiteralSpecification>.value', handler).register_handlers() entry.connect('destroy', self.watcher.unregister_handlers) return page
def verify_orphans(self): """Verify that no orphaned elements are saved. This method checks of there are any orphan references in the element factory. If orphans are found, a dialog is displayed asking the user if it is OK to unlink them.""" orphans = verify.orphan_references(self.element_factory) if orphans: main_window = self.main_window dialog = QuestionDialog( _( "The model contains some references" " to items that are not maintained." " Do you want to clean this before" " saving the model?" ), parent=main_window.window, ) answer = dialog.answer dialog.destroy() if not answer: for orphan in orphans: orphan.unlink()
class XMIExport(Service, ActionProvider): menu_xml = """ <ui> <menubar action="mainwindow"> <menu action="file"> <menu action="file-export"> <menuitem action="file-export-xmi" /> </menu> </menu> </menubar> </ui>""" def __init__(self, element_factory, file_manager): self.element_factory = element_factory self.file_manager = file_manager self.action_group = build_action_group(self) def shutdown(self): pass @action( name="file-export-xmi", label=_("Export to XMI"), tooltip=_("Export model to XMI (XML Model Interchange) format"), ) def execute(self): filename = self.file_manager.filename if filename: filename = filename.replace(".gaphor", ".xmi") else: filename = "model.xmi" file_dialog = FileDialog(_("Export model to XMI file"), action="save", filename=filename) filename = file_dialog.selection if filename and len(filename) > 0: logger.debug(f"Exporting XMI model to: {filename}") export = exportmodel.XMIExport(self.element_factory) try: export.export(filename) except Exception as e: logger.error( f"Error while saving model to file {filename}: {e}")
def construct(self): page = super(MessagePropertyPage, self).construct() item = self.item subject = item.subject if not subject: return page if item.is_communication(): self._messages = CommunicationMessageModel(item) tree_view = create_tree_view(self._messages, (_('Message'),)) tree_view.set_headers_visible(False) frame = gtk.Frame(label=_('Additional Messages')) frame.add(tree_view) page.pack_start(frame) self._inverted_messages = CommunicationMessageModel(item, inverted=True) tree_view = create_tree_view(self._inverted_messages, (_('Message'),)) tree_view.set_headers_visible(False) frame = gtk.Frame(label=_('Inverted Messages')) frame.add(tree_view) page.pack_end(frame) else: hbox = create_hbox_label(self, page, _('Message sort')) sort_data = self.MESSAGE_SORT lifeline = None cinfo = item.canvas.get_connection(item.tail) if cinfo: lifeline = cinfo.connected # disallow connecting two delete messages to a lifeline if lifeline and lifeline.is_destroyed \ and subject.messageSort != 'deleteMessage': sort_data = list(sort_data) assert sort_data[4][1] == 'deleteMessage' del sort_data[4] combo = self.combo = create_uml_combo(sort_data, self._on_message_sort_change) hbox.pack_start(combo, expand=False) index = combo.get_model().get_index(subject.messageSort) combo.set_active(index) return page
def construct(self): page = super(MessagePropertyPage, self).construct() item = self.item subject = item.subject if not subject: return page if item.is_communication(): self._messages = CommunicationMessageModel(item) tree_view = create_tree_view(self._messages, (_('Message'),)) tree_view.set_headers_visible(False) frame = gtk.Frame(label=_('Additional Messages')) frame.add(tree_view) page.pack_start(frame) self._inverted_messages = CommunicationMessageModel(item, inverted=True) tree_view = create_tree_view(self._inverted_messages, (_('Message'),)) tree_view.set_headers_visible(False) frame = gtk.Frame(label=_('Inverted Messages')) frame.add(tree_view) page.pack_end(frame) else: hbox = create_hbox_label(self, page, _('Message sort')) sort_data = self.MESSAGE_SORT lifeline = None cinfo = item.canvas.get_connection(item.tail) if cinfo: lifeline = cinfo.connected # disallow connecting two delete messages to a lifeline if lifeline and lifeline.is_destroyed \ and subject.messageSort != 'deleteMessage': sort_data = list(sort_data) assert sort_data[4][1] == 'deleteMessage' del sort_data[4] combo = self.combo = create_uml_combo(sort_data, self._on_message_sort_change) hbox.pack_start(combo, expand=False) index = combo.get_model().get_index(subject.messageSort) combo.set_active(index) return page
class MetaclassNamePropertyPage(NamedElementPropertyPage): """ Metaclass name editor. Provides editable combo box entry with predefined list of names of UML classes. """ order = 10 NAME_LABEL = _("Name") CLASSES = list( sorted( n for n in dir(UML) if _issubclass(getattr(UML, n), UML.Element) and n != "Stereotype" ) ) def construct(self): if not UML.model.is_metaclass(self.subject): return super().construct() page = Gtk.VBox() subject = self.subject if not subject: return page hbox = create_hbox_label(self, page, self.NAME_LABEL) model = Gtk.ListStore(str) for c in self.CLASSES: model.append([c]) cb = Gtk.ComboBox.new_with_model_and_entry(model) completion = Gtk.EntryCompletion() completion.set_model(model) completion.set_minimum_key_length(1) completion.set_text_column(0) cb.get_child().set_completion(completion) entry = cb.get_child() entry.set_text(subject and subject.name or "") hbox.pack_start(cb, True, True, 0) page.default = entry # monitor subject.name attribute changed_id = entry.connect("changed", self._on_name_change) def handler(event): if event.element is subject and event.new_value is not None: entry.handler_block(changed_id) entry.set_text(event.new_value) entry.handler_unblock(changed_id) self.watcher.watch("name", handler).subscribe_all() entry.connect("destroy", self.watcher.unsubscribe_all) page.show_all() return page
def action_open(self): """This menu action opens the standard model open dialog.""" filters = [{'name':_('Gaphor Models'), 'pattern':'*.gaphor'},\ {'name':_('All Files'), 'pattern':'*'}] file_dialog = FileDialog(_('Open Gaphor Model'),\ filters = filters) filename = file_dialog.selection file_dialog.destroy() log.debug(filename) if filename: self.load(filename) self.component_registry.handle(FileManagerStateChanged(self))
def action_open(self): """This menu action opens the standard model open dialog.""" filters = [{'name':_('Gaphor Models'), 'pattern':'*.gaphor'},\ {'name':_('All Files'), 'pattern':'*'}] file_dialog = FileDialog(_('Open Gaphor Model'),\ filters = filters) filename = file_dialog.selection file_dialog.destroy() log.debug(filename) if filename: self.load(filename) self.component_registry.handle(FileManagerStateChanged(self))
class HelpService(Service, ActionProvider): menu_xml = """ <ui> <menubar name="mainwindow"> <menu action="help"> <placeholder name="ternary"> <menuitem action="help-about" /> </placeholder> </menu> </menubar> </ui> """ def __init__(self, main_window): self.main_window = main_window self.action_group = build_action_group(self) def shutdown(self): pass @action(name="help-about", label=_("About Gaphor"), icon_name="help-about") def about(self): logo_file = importlib_metadata.distribution("gaphor").locate_file( "gaphor/ui/pixmaps/gaphor-96x96.png" ) logo = GdkPixbuf.Pixbuf.new_from_file(str(logo_file)) about = Gtk.AboutDialog.new() about.set_logo(logo) about.set_title("About Gaphor") about.set_program_name("Gaphor") about.set_comments("Gaphor is the simple modeling tool written in Python") about.set_version(str(__version__)) about.set_copyright("Copyright (c) 2001-2019 Arjan J. Molenaar and Dan Yeaw") about.set_license( "This software is published under the terms of the\n" "Apache Software License, version 2.0.\n" "See the LICENSE.txt file for details." ) about.set_website("https://github.com/gaphor/gaphor") about.set_website_label("Fork me on GitHub") about.set_authors( [ "Arjan Molenaar, Artur Wroblewski,", "Jeroen Vloothuis, Dan Yeaw, ", "Enno Groeper, Adam Boduch, ", "Alexis Howells, Melis DoÄŸan", ] ) about.set_translator_credits( "Jordi Mallach (ca), " "Antonin Delpeuch (fr), " "Ygor Mutti (pt_BR)" ) about.set_transient_for(self.main_window.window) about.show_all() about.run() about.destroy()
def action_open(self): """This menu action opens the standard model open dialog.""" filters = [ {"name": _("Gaphor Models"), "pattern": "*.gaphor"}, {"name": _("All Files"), "pattern": "*"}, ] file_dialog = FileDialog(_("Open Gaphor Model"), filters=filters) filename = file_dialog.selection file_dialog.destroy() log.debug(filename) if filename: self.load(filename) self.event_manager.handle(FilenameChanged(self, filename))
def load(self, filename): """Load the Gaphor model from the supplied file name. A status window displays the loading progress. The load generator updates the progress queue. The loader is passed to a GIdleThread which executes the load generator. If loading is successful, the filename is set.""" log.info("Loading file") log.debug("Path is %s" % filename) queue = Queue() try: main_window = self.main_window status_window = StatusWindow( _("Loading..."), _("Loading model from %s") % filename, parent=main_window.window, queue=queue, ) except component.interfaces.ComponentLookupError: status_window = None try: loader = storage.load_generator( filename.encode("utf-8"), self.element_factory ) worker = GIdleThread(loader, queue) worker.start() worker.wait() if worker.error: worker.reraise() self.filename = filename except: error_handler( message=_("Error while loading model from file %s") % filename ) raise finally: if status_window is not None: status_window.destroy()
def __init__(self): """Constructor. Build the action group for the element editor window. This will place a button for opening the window in the toolbar. The widget attribute is a PropertyEditor.""" self.action_group = build_action_group(self) self.window = None self.vbox = None self._current_item = None self._expanded_pages = {_("Properties"): True}
def action_new_from_template(self): """This menu action opens the new model from template dialog.""" filters = [{'name':_('Gaphor Models'), 'pattern':'*.gaphor'},\ {'name':_('All Files'), 'pattern':'*'}] file_dialog = FileDialog(_('New Gaphor Model From Template'),\ filters = filters) filename = file_dialog.selection file_dialog.destroy() log.debug(filename) if filename: self.load(filename) self.filename = None self.component_registry.handle(FileManagerStateChanged(self))
def load(self, filename): """Load the Gaphor model from the supplied file name. A status window displays the loading progress. The load generator updates the progress queue. The loader is passed to a GIdleThread which executes the load generator. If loading is successful, the filename is set.""" log.info("Loading file") log.debug("Path is %s" % filename) queue = Queue() try: main_window = self.main_window status_window = StatusWindow( _("Loading..."), _("Loading model from %s") % filename, parent=main_window.window, queue=queue, ) except component.interfaces.ComponentLookupError: status_window = None try: loader = storage.load_generator( filename.encode("utf-8"), self.element_factory ) worker = GIdleThread(loader, queue) worker.start() worker.wait() if worker.error: worker.reraise() self.filename = filename except: error_handler( message=_("Error while loading model from file %s") % filename ) raise finally: if status_window is not None: status_window.destroy()
def __init__(self): """Constructor. Build the action group for the element editor window. This will place a button for opening the window in the toolbar. The widget attribute is a PropertyEditor.""" self.action_group = build_action_group(self) self.window = None self.vbox = None self._current_item = None self._expanded_pages = {_("Properties"): True}
def action_open(self): """This menu action opens the standard model open dialog.""" filters = [ {"name": _("Gaphor Models"), "pattern": "*.gaphor"}, {"name": _("All Files"), "pattern": "*"}, ] file_dialog = FileDialog(_("Open Gaphor Model"), filters=filters) filename = file_dialog.selection file_dialog.destroy() log.debug(filename) if filename: self.load(filename) self.component_registry.handle(FileManagerStateChanged(self))
def action_new_from_template(self): """This menu action opens the new model from template dialog.""" filters = [{'name':_('Gaphor Models'), 'pattern':'*.gaphor'},\ {'name':_('All Files'), 'pattern':'*'}] file_dialog = FileDialog(_('New Gaphor Model From Template'),\ filters = filters) filename = file_dialog.selection file_dialog.destroy() log.debug(filename) if filename: self.load(filename) self.filename = None self.component_registry.handle(FileManagerStateChanged(self))
def save(self, filename): """Save the current UML model to the specified file name. Before writing the model file, this will verify that there are no orphan references. It will also verify that the filename has the correct extension. A status window is displayed while the GIdleThread is executed. This thread actually saves the model.""" log.info("Saving file") log.debug("File name is %s" % filename) if not filename or not len(filename): return self.verify_orphans() filename = self.verify_filename(filename) main_window = self.main_window queue = Queue() status_window = StatusWindow( _("Saving..."), _("Saving model to %s") % filename, parent=main_window.window, queue=queue, ) try: with open(filename.encode("utf-8"), "w") as out: saver = storage.save_generator(XMLWriter(out), self.element_factory) worker = GIdleThread(saver, queue) worker.start() worker.wait() if worker.error: worker.reraise() self.filename = filename except: error_handler(message=_("Error while saving model to file %s") % filename) raise finally: status_window.destroy()
def action_new_from_template(self): """This menu action opens the new model from template dialog.""" filters = [ {"name": _("Gaphor Models"), "pattern": "*.gaphor"}, {"name": _("All Files"), "pattern": "*"}, ] file_dialog = FileDialog(_("New Gaphor Model From Template"), filters=filters) filename = file_dialog.selection file_dialog.destroy() log.debug(filename) if filename: self.load(filename) self.filename = None self.component_registry.handle(FileManagerStateChanged(self))
def action_new_from_template(self): """This menu action opens the new model from template dialog.""" filters = [ {"name": _("Gaphor Models"), "pattern": "*.gaphor"}, {"name": _("All Files"), "pattern": "*"}, ] file_dialog = FileDialog(_("New Gaphor Model From Template"), filters=filters) filename = file_dialog.selection file_dialog.destroy() log.debug(filename) if filename: self.load(filename) self.filename = None self.event_manager.handle(FilenameChanged(self))
def dock_item_factory(parent, title, tooltip, icon_name=None, stock_id=None, pos=None, vispos=None, current=None, name=None): item = DockItem(_(title), _(tooltip), icon_name, stock_id) if name: item.set_name(name) if pos: pos = int(pos) if vispos: vispos = int(vispos) parent.insert_item(item, pos, vispos) item.show() return item
def save(self, filename): """Save the current UML model to the specified file name. Before writing the model file, this will verify that there are no orphan references. It will also verify that the filename has the correct extension. A status window is displayed while the GIdleThread is executed. This thread actually saves the model.""" log.info("Saving file") log.debug("File name is %s" % filename) if not filename or not len(filename): return self.verify_orphans() filename = self.verify_filename(filename) main_window = self.main_window queue = Queue() status_window = StatusWindow( _("Saving..."), _("Saving model to %s") % filename, parent=main_window.window, queue=queue, ) try: with open(filename.encode("utf-8"), "w") as out: saver = storage.save_generator(XMLWriter(out), self.element_factory) worker = GIdleThread(saver, queue) worker.start() worker.wait() if worker.error: worker.reraise() self.filename = filename except: error_handler(message=_("Error while saving model to file %s") % filename) raise finally: status_window.destroy()
class NamedElementPropertyPage(object): """ An adapter which works for any named item view. It also sets up a table view which can be extended. """ interface.implements(IPropertyPage) component.adapts(uml2.NamedElement) order = 10 NAME_LABEL = _('Name') def __init__(self, subject): assert subject is None or isinstance( subject, uml2.NamedElement), '%s' % type(subject) self.subject = subject self.watcher = EventWatcher(subject) self.size_group = gtk.SizeGroup(gtk.SIZE_GROUP_HORIZONTAL) def construct(self): page = gtk.VBox() subject = self.subject if not subject: return page hbox = create_hbox_label(self, page, self.NAME_LABEL) entry = gtk.Entry() entry.set_text(subject and subject.name or '') hbox.pack_start(entry) page.set_data('default', entry) # monitor subject.name attribute changed_id = entry.connect('changed', self._on_name_change) def handler(event): if event.element is subject and event.new_value is not None: entry.handler_block(changed_id) entry.set_text(event.new_value) entry.handler_unblock(changed_id) self.watcher.watch('name', handler) \ .register_handlers() entry.connect("destroy", self.watcher.unregister_handlers) return page @transactional def _on_name_change(self, entry): self.subject.name = entry.get_text()
def construct(self): page = Gtk.VBox() hbox = create_hbox_label(self, page, _("Dependency type")) self.combo = create_uml_combo(self.DEPENDENCY_TYPES, self._on_dependency_type_change) hbox.pack_start(self.combo, False, True, 0) hbox = create_hbox_label(self, page, "") button = Gtk.CheckButton(_("Automatic")) button.set_active(self.item.auto_dependency) button.connect("toggled", self._on_auto_dependency_change) hbox.pack_start(button, True, True, 0) self.watcher.watch("subject", self._on_subject_change).subscribe_all() button.connect("destroy", self.watcher.unsubscribe_all) self.update() return page
def load(self, filename): """Load the Gaphor model from the supplied file name. A status window displays the loading progress. The load generator updates the progress queue. The loader is passed to a GIdleThread which executes the load generator. If loading is successful, the filename is set.""" queue = Queue() status_window: Optional[StatusWindow] try: main_window = self.main_window status_window = StatusWindow( _("Loading..."), _("Loading model from %s") % filename, parent=main_window.window, queue=queue, ) except: log.warning("Could not create status window, proceding without.") status_window = None try: loader = storage.load_generator(filename.encode("utf-8"), self.element_factory) worker = GIdleThread(loader, queue) worker.start() worker.wait() if worker.error: worker.reraise() self.filename = filename except: error_handler(message=_("Error while loading model from file %s") % filename) raise finally: if status_window is not None: status_window.destroy()
def construct(self): page = gtk.VBox() hbox = create_hbox_label(self, page, _('Dependency type')) self.combo = create_uml_combo(self.DEPENDENCY_TYPES, self._on_dependency_type_change) hbox.pack_start(self.combo, expand=False) hbox = create_hbox_label(self, page, '') button = gtk.CheckButton(_('Automatic')) button.set_active(self.item.auto_dependency) button.connect('toggled', self._on_auto_dependency_change) hbox.pack_start(button) self.watcher.watch('subject', self._on_subject_change).register_handlers() button.connect('destroy', self.watcher.unregister_handlers) self.update() return page
def construct(self): page = gtk.VBox() hbox = create_hbox_label(self, page, _('Dependency type')) self.combo = create_uml_combo(self.DEPENDENCY_TYPES, self._on_dependency_type_change) hbox.pack_start(self.combo, expand=False) hbox = create_hbox_label(self, page, '') button = gtk.CheckButton(_('Automatic')) button.set_active(self.item.auto_dependency) button.connect('toggled', self._on_auto_dependency_change) hbox.pack_start(button) self.watcher.watch('subject', self._on_subject_change).register_handlers() button.connect('destroy', self.watcher.unregister_handlers) self.update() return page
def action_new(self): """The new model menu action. This action will create a new UML model. This will trigger a FileManagerStateChange event.""" element_factory = self.element_factory main_window = self.main_window if element_factory.size(): dialog = QuestionDialog( _( "Opening a new model will flush the" " currently loaded model.\nAny changes" " made will not be saved. Do you want to" " continue?" ), parent=main_window.window, ) answer = dialog.answer dialog.destroy() if not answer: return element_factory.flush() with element_factory.block_events(): model = element_factory.create(UML.Package) model.name = _("New model") diagram = element_factory.create(UML.Diagram) diagram.package = model diagram.name = _("main") self.filename = None element_factory.notify_model() # main_window.select_element(diagram) # main_window.show_diagram(diagram) self.event_manager.handle(FilenameChanged(self))
def file_quit(self): """ Ask user to close window if the model has changed. The user is asked to either discard the changes, keep the application running or save the model and quit afterwards. """ if self.main_window.model_changed: dialog = Gtk.MessageDialog( self.main_window.window, Gtk.DialogFlags.MODAL | Gtk.DialogFlags.DESTROY_WITH_PARENT, Gtk.MessageType.WARNING, Gtk.ButtonsType.NONE, _("Save changed to your model before closing?"), ) dialog.format_secondary_text( _("If you close without saving, your changes will be discarded." )) dialog.add_buttons( _("Close _without saving"), Gtk.ResponseType.REJECT, Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL, Gtk.STOCK_SAVE, Gtk.ResponseType.YES, ) dialog.set_default_response(Gtk.ResponseType.YES) response = dialog.run() dialog.destroy() if response == Gtk.ResponseType.YES: saved = self.action_save() if saved: self.main_window.quit() if response == Gtk.ResponseType.REJECT: self.main_window.quit() else: self.main_window.quit()
def save(self, filename): """Save the current UML model to the specified file name. Before writing the model file, this will verify that there are no orphan references. It will also verify that the filename has the correct extension. A status window is displayed while the GIdleThread is executed. This thread actually saves the model.""" self.logger.info('Saving file') self.logger.debug('File name is %s' % filename) if not filename or not len(filename): return self.verify_orphans() filename = self.verify_filename(filename) main_window = self.main_window queue = Queue() status_window = StatusWindow(_('Saving...'),\ _('Saving model to %s') % filename,\ parent=main_window.window,\ queue=queue) out = open(filename, 'w') saver = storage.save_generator(XMLWriter(out), self.element_factory) worker = GIdleThread(saver, queue) worker.start() worker.wait() if worker.error: self.logger.error('Error saving file') self.logger.error(worker.error) out.close() status_window.destroy() self.filename = filename
def construct(self): page = super(JoinNodePropertyPage, self).construct() subject = self.subject if not subject: return page hbox = gtk.HBox() page.pack_start(hbox, expand=False) if isinstance(subject, UML.JoinNode): hbox = create_hbox_label(self, page, _('Join specification')) entry = gtk.Entry() entry.set_text(subject.joinSpec or '') entry.connect('changed', self._on_join_spec_change) hbox.pack_start(entry) button = gtk.CheckButton(_('Horizontal')) button.set_active(self.item.matrix[2] != 0) button.connect('toggled', self._on_horizontal_change) page.pack_start(button, expand=False) return page
def construct(self): page = super(JoinNodePropertyPage, self).construct() subject = self.subject if not subject: return page hbox = gtk.HBox() page.pack_start(hbox, expand=False) if isinstance(subject, uml2.JoinNode): hbox = create_hbox_label(self, page, _('Join specification')) entry = gtk.Entry() entry.set_text(subject.joinSpec or '') entry.connect('changed', self._on_join_spec_change) hbox.pack_start(entry) button = gtk.CheckButton(_('Horizontal')) button.set_active(self.item.matrix[2] != 0) button.connect('toggled', self._on_horizontal_change) page.pack_start(button, expand=False) return page
def construct(self): page = super(JoinNodePropertyPage, self).construct() subject = self.subject if not subject: return page hbox = Gtk.HBox() page.pack_start(hbox, False, True, 0) if isinstance(subject, UML.JoinNode): hbox = create_hbox_label(self, page, _("Join specification")) entry = Gtk.Entry() entry.set_text(subject.joinSpec or "") entry.connect("changed", self._on_join_spec_change) hbox.pack_start(entry, True, True, 0) button = Gtk.CheckButton(_("Horizontal")) button.set_active(self.item.matrix[2] != 0) button.connect("toggled", self._on_horizontal_change) page.pack_start(button, False, True, 0) return page
class NamedElementPropertyPage(PropertyPageBase): """An adapter which works for any named item view. It also sets up a table view which can be extended. """ order = 10 NAME_LABEL = _("Name") def __init__(self, subject): assert subject is None or isinstance(subject, UML.NamedElement), "%s" % type( subject ) self.subject = subject self.watcher = subject.watcher() self.size_group = Gtk.SizeGroup.new(Gtk.SizeGroupMode.HORIZONTAL) def construct(self): page = Gtk.VBox() subject = self.subject if not subject: return page hbox = create_hbox_label(self, page, self.NAME_LABEL) entry = Gtk.Entry() entry.set_text(subject and subject.name or "") hbox.pack_start(entry, True, True, 0) page.default = entry # monitor subject.name attribute changed_id = entry.connect("changed", self._on_name_change) def handler(event): if event.element is subject and event.new_value is not None: entry.handler_block(changed_id) entry.set_text(event.new_value) entry.handler_unblock(changed_id) self.watcher.watch("name", handler).subscribe_all() entry.connect("destroy", self.watcher.unsubscribe_all) return page @transactional def _on_name_change(self, entry): self.subject.name = entry.get_text()
def construct(self): page = super().construct() subject = self.subject if not subject: return page hbox = Gtk.HBox() page.pack_start(hbox, False, True, 0) button = Gtk.CheckButton(_("Indirectly instantiated")) button.set_active(subject.isIndirectlyInstantiated) button.connect("toggled", self._on_ii_change) hbox.pack_start(button, False, True, 0) return page