def test_braking_big_diamond(self): """ Test diamond shaped dependencies a -> b -> c -> d, a -> b' -> c' -> d """ a = A() watcher = EventWatcher(a, self._handler) watcher.watch('one.two.one.two') #watcher.watch('one.one.one.one') watcher.register_handlers() a.one = A() a.one.two = A() a.one.two = A() a.one.two[0].one = A() a.one.two[1].one = A() a.one.two[0].one.two = A() a.one.two[1].one.two = a.one.two[0].one.two[0] self.assertEquals(7, len(self.events)) self.assertEquals(6, len(self.dispatcher._handlers)) del a.one.two[0].one #a.unlink() watcher.unregister_handlers() watcher.unregister_handlers() self.assertEquals(0, len(self.dispatcher._handlers))
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()
class CommentItemPropertyPage(object): """ Property page for Comments """ interface.implements(IPropertyPage) component.adapts(uml2.Comment) order = 0 def __init__(self, subject): self.subject = subject self.watcher = EventWatcher(subject) 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 @transactional def _on_body_change(self, buffer): self.subject.body = buffer.get_text(buffer.get_start_iter(), buffer.get_end_iter())
class CommentItemPropertyPage(object): """ Property page for Comments """ interface.implements(IPropertyPage) component.adapts(UML.Comment) order = 0 def __init__(self, subject): self.subject = subject self.watcher = EventWatcher(subject) 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 @transactional def _on_body_change(self, buffer): self.subject.body = buffer.get_text(buffer.get_start_iter(), buffer.get_end_iter())
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(UML.NamedElement) 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 = 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()
class NamedElementPropertyPage(object): """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 = EventWatcher(subject) 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).register_handlers() entry.connect("destroy", self.watcher.unregister_handlers) return page @transactional def _on_name_change(self, entry): self.subject.name = entry.get_text()
class CommentItemPropertyPage(PropertyPageBase): """Property page for Comments.""" order = 0 def __init__(self, subject): self.subject = subject self.watcher = EventWatcher(subject) 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).register_handlers() text_view.connect("destroy", self.watcher.unregister_handlers) return page @transactional def _on_body_change(self, buffer): self.subject.body = buffer.get_text( buffer.get_start_iter(), buffer.get_end_iter(), False )
def test_diamond(self): """ Test diamond shaped dependencies a -> b -> c, a -> b' -> c """ a = A() watcher = EventWatcher(a, self._handler) watcher.watch('one.two.one.two') #watcher.watch('one.one.one.one') watcher.register_handlers() a.one = A() a.one.two = A() a.one.two = A() a.one.two[0].one = A() a.one.two[1].one = a.one.two[0].one a.one.two[0].one.two = A() self.assertEquals(6, len(self.events)) a.unlink() watcher.unregister_handlers() watcher.unregister_handlers()
def test_cyclic(self): """ Test cyclic dependency a -> b -> c -> a. """ a = A() watcher = EventWatcher(a, self._handler) watcher.watch('one.two.one.two') #watcher.watch('one.one.one.one') watcher.register_handlers() a.one = A() a.one.two = A() a.one.two = A() a.one.two[0].one = a self.assertEquals(4, len(self.events)) #a.one.two[0].one.two = A() #a.one.two[0].one.two = A() a.unlink() self.assertEquals(1, len(self.dispatcher._handlers))
class AttributesPage(object): """ An editor for attributes associated with classes and interfaces. """ interface.implements(IPropertyPage) component.adapts(items.ClassItem) order = 20 def __init__(self, item): super(AttributesPage, self).__init__() self.item = item self.watcher = EventWatcher(item.subject) 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 @transactional def _on_show_attributes_change(self, button): self.item.show_attributes = button.get_active() self.item.request_update()
class AssociationEndPropertyPage(PropertyPageBase): """Property page for association end properties.""" order = 0 NAVIGABILITY = [None, False, True] def __init__(self, subject): self.subject = subject self.watcher = EventWatcher(subject) def construct(self): vbox = Gtk.VBox() entry = Gtk.Entry() # entry.set_text(UML.format(self.subject, visibility=True, is_derived=Truemultiplicity=True) or '') # monitor subject attribute (all, cause it contains many children) changed_id = entry.connect("changed", self._on_end_name_change) def handler(event): if not entry.props.has_focus: entry.handler_block(changed_id) entry.set_text( UML.format( self.subject, visibility=True, is_derived=True, multiplicity=True, ) or "") # entry.set_text(UML.format(self.subject, multiplicity=True) or '') entry.handler_unblock(changed_id) handler(None) self.watcher.watch("name", handler).watch( "aggregation", handler).watch("visibility", handler).watch( "lowerValue", handler).watch("upperValue", handler).register_handlers() entry.connect("destroy", self.watcher.unregister_handlers) vbox.pack_start(entry, True, True, 0) entry.set_tooltip_text("""\ Enter attribute name and multiplicity, for example - name + name [1] - name [1..2] ~ 1..2 - [1..2]\ """) combo = Gtk.ComboBoxText() for t in ("Unknown navigation", "Not navigable", "Navigable"): combo.append_text(t) nav = self.subject.navigability combo.set_active(self.NAVIGABILITY.index(nav)) combo.connect("changed", self._on_navigability_change) vbox.pack_start(combo, False, True, 0) combo = Gtk.ComboBoxText() for t in ("No aggregation", "Shared", "Composite"): combo.append_text(t) combo.set_active(["none", "shared", "composite"].index(self.subject.aggregation)) combo.connect("changed", self._on_aggregation_change) vbox.pack_start(combo, False, True, 0) return vbox @transactional def _on_end_name_change(self, entry): UML.parse(self.subject, entry.get_text()) @transactional def _on_navigability_change(self, combo): nav = self.NAVIGABILITY[combo.get_active()] UML.model.set_navigability(self.subject.association, self.subject, nav) @transactional def _on_aggregation_change(self, combo): self.subject.aggregation = ("none", "shared", "composite")[combo.get_active()]
class DependencyPropertyPage(PropertyPageBase): """Dependency item editor.""" order = 0 element_factory = inject("element_factory") DEPENDENCY_TYPES = ( (_("Dependency"), UML.Dependency), (_("Usage"), UML.Usage), (_("Realization"), UML.Realization), (_("Implementation"), UML.Implementation), ) def __init__(self, item): super(DependencyPropertyPage, self).__init__() self.item = item self.size_group = Gtk.SizeGroup(Gtk.SizeGroupMode.HORIZONTAL) self.watcher = EventWatcher(self.item) 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).register_handlers() button.connect("destroy", self.watcher.unregister_handlers) self.update() return page def _on_subject_change(self, event): self.update() def update(self): """ Update dependency type combo box. Disallow dependency type when dependency is established. """ combo = self.combo item = self.item index = combo.get_model().get_index(item.dependency_type) combo.props.sensitive = not item.auto_dependency combo.set_active(index) @transactional def _on_dependency_type_change(self, combo): combo = self.combo cls = combo.get_model().get_value(combo.get_active()) self.item.dependency_type = cls if self.item.subject: self.element_factory.swap_element(self.item.subject, cls) self.item.request_update() @transactional def _on_auto_dependency_change(self, button): self.item.auto_dependency = button.get_active() self.update()
class OperationsPage(PropertyPageBase): """An editor for operations associated with classes and interfaces.""" order = 30 name = "Operations" def __init__(self, item): super(OperationsPage, self).__init__() self.item = item self.watcher = EventWatcher(item.subject) def construct(self): page = Gtk.VBox() if not self.item.subject: return page # Show operations toggle hbox = Gtk.HBox() label = Gtk.Label(label="") label.set_justify(Gtk.Justification.LEFT) hbox.pack_start(label, False, True, 0) button = Gtk.CheckButton(label=_("Show operations")) button.set_active(self.item.show_operations) button.connect("toggled", self._on_show_operations_change) hbox.pack_start(button, True, True, 0) page.pack_start(hbox, False, True, 0) 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, True, True, 0) @AsyncIO(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", handler ).watch("ownedOperation.returnResult.upperValue", handler).watch( "ownedOperation.returnResult.typeValue", handler).watch( "ownedOperation.formalParameter.lowerValue", handler).watch( "ownedOperation.formalParameter.upperValue", handler).watch( "ownedOperation.formalParameter.typeValue", handler).watch( "ownedOperation.formalParameter.defaultValue", handler).register_handlers() tree_view.connect("destroy", self.watcher.unregister_handlers) return page @transactional def _on_show_operations_change(self, button): self.item.show_operations = button.get_active() self.item.request_update()
class AttributesPage(object): """ An editor for attributes associated with classes and interfaces. """ interface.implements(IPropertyPage) component.adapts(items.ClassItem) order = 20 def __init__(self, item): super(AttributesPage, self).__init__() self.item = item self.watcher = EventWatcher(item.subject) 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', handler) \ .watch('ownedAttribute.upperValue', handler) \ .watch('ownedAttribute.defaultValue', handler) \ .watch('ownedAttribute.typeValue', handler) \ .register_handlers() tree_view.connect('destroy', self.watcher.unregister_handlers) return page @transactional def _on_show_attributes_change(self, button): self.item.show_attributes = button.get_active() self.item.request_update()
class OperationsPage(object): """ An editor for operations associated with classes and interfaces. """ interface.implements(IPropertyPage) component.adapts(items.ClassItem) order = 30 def __init__(self, item): super(OperationsPage, self).__init__() self.item = item self.watcher = EventWatcher(item.subject) 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 @transactional def _on_show_operations_change(self, button): self.item.show_operations = button.get_active() self.item.request_update()
class DependencyPropertyPage(object): """ Dependency item editor. """ interface.implements(IPropertyPage) component.adapts(items.DependencyItem) order = 0 element_factory = inject('element_factory') DEPENDENCY_TYPES = ( (_('Dependency'), UML.Dependency), (_('Usage'), UML.Usage), (_('Realization'), UML.Realization), (_('Implementation'), UML.Implementation)) def __init__(self, item): super(DependencyPropertyPage, self).__init__() self.item = item self.size_group = gtk.SizeGroup(gtk.SIZE_GROUP_HORIZONTAL) self.watcher = EventWatcher(self.item) 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 _on_subject_change(self, event): self.update() def update(self): """ Update dependency type combo box. Disallow dependency type when dependency is established. """ combo = self.combo item = self.item index = combo.get_model().get_index(item.dependency_type) combo.props.sensitive = not item.auto_dependency combo.set_active(index) @transactional def _on_dependency_type_change(self, combo): combo = self.combo cls = combo.get_model().get_value(combo.get_active()) self.item.dependency_type = cls if self.item.subject: self.element_factory.swap_element(self.item.subject, cls) self.item.request_update() @transactional def _on_auto_dependency_change(self, button): self.item.auto_dependency = button.get_active() self.update()
class DiagramItem( UML.Presentation, StereotypeSupport, EditableTextSupport, metaclass=DiagramItemMeta ): """ Basic functionality for all model elements (lines and elements!). This class contains common functionality for model elements and relationships. It provides an interface similar to UML.Element for connecting and disconnecting signals. This class is not very useful on its own. It contains some glue-code for diacanvas.DiaCanvasItem and gaphor.UML.Element. Example: class ElementItem(diacanvas.CanvasElement, DiagramItem): connect = DiagramItem.connect disconnect = DiagramItem.disconnect ... @cvar style: styles information (derived from DiagramItemMeta) """ dispatcher = inject("element_dispatcher") element_factory = inject("element_factory") def __init__(self, id=None): UML.Presentation.__init__(self, factory=self.element_factory) EditableTextSupport.__init__(self) StereotypeSupport.__init__(self) self._id = id # properties, which should be saved in file self._persistent_props = set() def update(event): self.request_update() self.watcher = EventWatcher(self, default_handler=update) self.watch("subject").watch( "subject.appliedStereotype.classifier.name", self.on_element_applied_stereotype, ) id = property(lambda self: self._id, doc="Id") def set_prop_persistent(self, name): """ Specify property of diagram item, which should be saved in file. """ self._persistent_props.add(name) # TODO: Use adapters for load/save functionality def save(self, save_func): if self.subject: save_func("subject", self.subject) save_func("show_stereotypes_attrs", self.show_stereotypes_attrs) # save persistent properties for p in self._persistent_props: save_func(p, getattr(self, p.replace("-", "_"))) def load(self, name, value): if name == "subject": type(self).subject.load(self, value) elif name == "show_stereotypes_attrs": self._show_stereotypes_attrs = eval(value) else: try: setattr(self, name.replace("-", "_"), eval(value)) except: logger.warning( "%s has no property named %s (value %s)" % (self, name, value) ) def postload(self): if self.subject: self.update_stereotype() self.update_stereotypes_attrs() def save_property(self, save_func, name): """ Save a property, this is a shorthand method. """ save_func(name, getattr(self, name.replace("-", "_"))) def save_properties(self, save_func, *names): """ Save a property, this is a shorthand method. """ for name in names: self.save_property(save_func, name) def unlink(self): """ Remove the item from the canvas and set subject to None. """ if self.canvas: self.canvas.remove(self) super(DiagramItem, self).unlink() def request_update(self): """ Placeholder for gaphor.Item's request_update() method. """ pass def pre_update(self, context): EditableTextSupport.pre_update(self, context) def post_update(self, context): EditableTextSupport.post_update(self, context) def draw(self, context): EditableTextSupport.draw(self, context) def item_at(self, x, y): return self def on_element_applied_stereotype(self, event): if self.subject: self.update_stereotype() self.request_update() def watch(self, path, handler=None): """ Watch a certain path of elements starting with the DiagramItem. The handler is optional and will default to a simple self.request_update(). Watches should be set in the constructor, so they can be registered and unregistered in one shot. This interface is fluent(returns self). """ self.watcher.watch(path, handler) return self def register_handlers(self): self.watcher.register_handlers() def unregister_handlers(self): self.watcher.unregister_handlers()
class DependencyPropertyPage(object): """ Dependency item editor. """ interface.implements(IPropertyPage) component.adapts(items.DependencyItem) order = 0 element_factory = inject('element_factory') DEPENDENCY_TYPES = ((_('Dependency'), uml2.Dependency), (_('Usage'), uml2.Usage), (_('Realization'), uml2.Realization), (_('Implementation'), uml2.Implementation)) def __init__(self, item): super(DependencyPropertyPage, self).__init__() self.item = item self.size_group = gtk.SizeGroup(gtk.SIZE_GROUP_HORIZONTAL) self.watcher = EventWatcher(self.item) 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 _on_subject_change(self, event): self.update() def update(self): """ Update dependency type combo box. Disallow dependency type when dependency is established. """ combo = self.combo item = self.item index = combo.get_model().get_index(item.dependency_type) combo.props.sensitive = not item.auto_dependency combo.set_active(index) @transactional def _on_dependency_type_change(self, combo): combo = self.combo cls = combo.get_model().get_value(combo.get_active()) self.item.dependency_type = cls if self.item.subject: self.element_factory.swap_element(self.item.subject, cls) self.item.request_update() @transactional def _on_auto_dependency_change(self, button): self.item.auto_dependency = button.get_active() self.update()
class OperationsPage(object): """ An editor for operations associated with classes and interfaces. """ interface.implements(IPropertyPage) component.adapts(items.ClassItem) order = 30 def __init__(self, item): super(OperationsPage, self).__init__() self.item = item self.watcher = EventWatcher(item.subject) 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', handler) \ .watch('ownedOperation.returnResult.upperValue', handler) \ .watch('ownedOperation.returnResult.typeValue', handler) \ .watch('ownedOperation.formalParameter.lowerValue', handler) \ .watch('ownedOperation.formalParameter.upperValue', handler) \ .watch('ownedOperation.formalParameter.typeValue', handler) \ .watch('ownedOperation.formalParameter.defaultValue', handler) \ .register_handlers() tree_view.connect('destroy', self.watcher.unregister_handlers) return page @transactional def _on_show_operations_change(self, button): self.item.show_operations = button.get_active() self.item.request_update()
class DiagramItem( with_metaclass( DiagramItemMeta, type('NewBase', (UML.Presentation, StereotypeSupport, EditableTextSupport), {}))): """ Basic functionality for all model elements (lines and elements!). This class contains common functionallity for model elements and relationships. It provides an interface similar to UML.Element for connecting and disconnecting signals. This class is not very useful on its own. It contains some glue-code for diacanvas.DiaCanvasItem and gaphor.UML.Element. Example: class ElementItem(diacanvas.CanvasElement, DiagramItem): connect = DiagramItem.connect disconnect = DiagramItem.disconnect ... @cvar style: styles information (derived from DiagramItemMeta) """ dispatcher = inject('element_dispatcher') def __init__(self, id=None): UML.Presentation.__init__(self) EditableTextSupport.__init__(self) StereotypeSupport.__init__(self) self._id = id # properties, which should be saved in file self._persistent_props = set() def update(event): self.request_update() self.watcher = EventWatcher(self, default_handler=update) self.watch('subject') \ .watch('subject.appliedStereotype.classifier.name', self.on_element_applied_stereotype) id = property(lambda self: self._id, doc='Id') def set_prop_persistent(self, name): """ Specify property of diagram item, which should be saved in file. """ self._persistent_props.add(name) # TODO: Use adapters for load/save functionality def save(self, save_func): if self.subject: save_func('subject', self.subject) save_func('show_stereotypes_attrs', self.show_stereotypes_attrs) # save persistent properties for p in self._persistent_props: save_func(p, getattr(self, p.replace('-', '_'))) def load(self, name, value): if name == 'subject': type(self).subject.load(self, value) elif name == 'show_stereotypes_attrs': self._show_stereotypes_attrs = eval(value) else: try: setattr(self, name.replace('-', '_'), eval(value)) except: logger.warning('%s has no property named %s (value %s)'%\ (self, name, value)) def postload(self): if self.subject: self.update_stereotype() self.update_stereotypes_attrs() def save_property(self, save_func, name): """ Save a property, this is a shorthand method. """ save_func(name, getattr(self, name.replace('-', '_'))) def save_properties(self, save_func, *names): """ Save a property, this is a shorthand method. """ for name in names: self.save_property(save_func, name) def unlink(self): """ Remove the item from the canvas and set subject to None. """ if self.canvas: self.canvas.remove(self) super(DiagramItem, self).unlink() def request_update(self): """ Placeholder for gaphor.Item's request_update() method. """ pass def pre_update(self, context): EditableTextSupport.pre_update(self, context) def post_update(self, context): EditableTextSupport.post_update(self, context) def draw(self, context): EditableTextSupport.draw(self, context) def item_at(self, x, y): return self def on_element_applied_stereotype(self, event): if self.subject: self.update_stereotype() self.request_update() def watch(self, path, handler=None): """ Watch a certain path of elements starting with the DiagramItem. The handler is optional and will default to a simple self.request_update(). Watches should be set in the constructor, so they can be registered and unregistered in one shot. This interface is fluent(returns self). """ self.watcher.watch(path, handler) return self def register_handlers(self): self.watcher.register_handlers() def unregister_handlers(self): self.watcher.unregister_handlers()
class AttributesPage(PropertyPageBase): """An editor for attributes associated with classes and interfaces.""" order = 20 name = "Attributes" def __init__(self, item): super(AttributesPage, self).__init__() self.item = item self.watcher = EventWatcher(item.subject) def construct(self): page = Gtk.VBox() if not self.item.subject: return page # Show attributes toggle hbox = Gtk.HBox() label = Gtk.Label(label="") label.set_justify(Gtk.Justification.LEFT) hbox.pack_start(label, False, True, 0) button = Gtk.CheckButton(label=_("Show attributes")) button.set_active(self.item.show_attributes) button.connect("toggled", self._on_show_attributes_change) hbox.pack_start(button, True, True, 0) page.pack_start(hbox, False, True, 0) 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, True, True, 0) @AsyncIO(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", handler).watch( "ownedAttribute.upperValue", handler).watch("ownedAttribute.defaultValue", handler).watch("ownedAttribute.typeValue", handler).register_handlers() tree_view.connect("destroy", self.watcher.unregister_handlers) return page @transactional def _on_show_attributes_change(self, button): self.item.show_attributes = button.get_active() self.item.request_update()
class AssociationEndPropertyPage(object): """ Property page for association end properties. """ interface.implements(IPropertyPage) component.adapts(UML.Property) order = 0 NAVIGABILITY = [None, False, True] def __init__(self, subject): self.subject = subject self.watcher = EventWatcher(subject) def construct(self): vbox = gtk.VBox() entry = gtk.Entry() #entry.set_text(UML.format(self.subject, visibility=True, is_derived=Truemultiplicity=True) or '') # monitor subject attribute (all, cause it contains many children) changed_id = entry.connect('changed', self._on_end_name_change) def handler(event): if not entry.props.has_focus: entry.handler_block(changed_id) entry.set_text(UML.format(self.subject, visibility=True, is_derived=True, multiplicity=True) or '') #entry.set_text(UML.format(self.subject, multiplicity=True) or '') entry.handler_unblock(changed_id) handler(None) self.watcher.watch('name', handler) \ .watch('aggregation', handler)\ .watch('visibility', handler)\ .watch('lowerValue<LiteralSpecification>.value', handler)\ .watch('upperValue<LiteralSpecification>.value', handler)\ .register_handlers() entry.connect("destroy", self.watcher.unregister_handlers) vbox.pack_start(entry) entry.set_tooltip_text("""\ Enter attribute name and multiplicity, for example - name + name [1] - name [1..2] ~ 1..2 - [1..2]\ """) combo = gtk.combo_box_new_text() for t in ('Unknown navigation', 'Not navigable', 'Navigable'): combo.append_text(t) nav = self.subject.navigability combo.set_active(self.NAVIGABILITY.index(nav)) combo.connect('changed', self._on_navigability_change) vbox.pack_start(combo, expand=False) combo = gtk.combo_box_new_text() for t in ('No aggregation', 'Shared', 'Composite'): combo.append_text(t) combo.set_active(['none', 'shared', 'composite'].index(self.subject.aggregation)) combo.connect('changed', self._on_aggregation_change) vbox.pack_start(combo, expand=False) return vbox @transactional def _on_end_name_change(self, entry): UML.parse(self.subject, entry.get_text()) @transactional def _on_navigability_change(self, combo): nav = self.NAVIGABILITY[combo.get_active()] UML.model.set_navigability(self.subject.association, self.subject, nav) @transactional def _on_aggregation_change(self, combo): self.subject.aggregation = ('none', 'shared', 'composite')[combo.get_active()]
class AssociationEndPropertyPage(object): """ Property page for association end properties. """ interface.implements(IPropertyPage) component.adapts(uml2.Property) order = 0 NAVIGABILITY = [None, False, True] def __init__(self, subject): self.subject = subject self.watcher = EventWatcher(subject) def construct(self): vbox = gtk.VBox() entry = gtk.Entry() #entry.set_text(format(self.subject, visibility=True, is_derived=Truemultiplicity=True) or '') # monitor subject attribute (all, cause it contains many children) changed_id = entry.connect('changed', self._on_end_name_change) def handler(event): if not entry.props.has_focus: entry.handler_block(changed_id) entry.set_text( format(self.subject, visibility=True, is_derived=True, multiplicity=True) or '') #entry.set_text(format(self.subject, multiplicity=True) or '') entry.handler_unblock(changed_id) handler(None) self.watcher.watch('name', handler) \ .watch('aggregation', handler)\ .watch('visibility', handler)\ .watch('lowerValue', handler)\ .watch('upperValue', handler)\ .register_handlers() entry.connect("destroy", self.watcher.unregister_handlers) vbox.pack_start(entry) entry.set_tooltip_text("""\ Enter attribute name and multiplicity, for example - name + name [1] - name [1..2] ~ 1..2 - [1..2]\ """) combo = gtk.combo_box_new_text() for t in ('Unknown navigation', 'Not navigable', 'Navigable'): combo.append_text(t) nav = self.subject.navigability combo.set_active(self.NAVIGABILITY.index(nav)) combo.connect('changed', self._on_navigability_change) vbox.pack_start(combo, expand=False) combo = gtk.combo_box_new_text() for t in ('No aggregation', 'Shared', 'Composite'): combo.append_text(t) combo.set_active(['none', 'shared', 'composite'].index(self.subject.aggregation)) combo.connect('changed', self._on_aggregation_change) vbox.pack_start(combo, expand=False) return vbox @transactional def _on_end_name_change(self, entry): parse(self.subject, entry.get_text()) @transactional def _on_navigability_change(self, combo): nav = self.NAVIGABILITY[combo.get_active()] modelfactory.set_navigability(self.subject.association, self.subject, nav) @transactional def _on_aggregation_change(self, combo): self.subject.aggregation = ('none', 'shared', 'composite')[combo.get_active()]