Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Parts and references #330

Merged
merged 6 commits into from
May 30, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
129 changes: 125 additions & 4 deletions gaphor/SysML/blocks/block.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,130 @@
from gaphor.core import gettext
from gaphor.core.modeling.properties import attribute
from gaphor.diagram.presentation import (
Classified,
ElementPresentation,
from_package_str,
)
from gaphor.diagram.shapes import (
Box,
EditableText,
FontStyle,
FontWeight,
Text,
TextAlign,
VerticalAlign,
draw_border,
draw_top_separator,
)
from gaphor.diagram.support import represents
from gaphor.SysML.sysml import Block
from gaphor.UML.classes import ClassItem
from gaphor.UML.classes.klass import (
attribute_watches,
stereotype_compartments,
stereotype_watches,
)
from gaphor.UML.modelfactory import stereotypes_str
from gaphor.UML.umlfmt import format_attribute


@represents(Block)
class BlockItem(ClassItem):
def additional_stereotypes(self):
return ["block"]
class BlockItem(ElementPresentation[Block], Classified):
def __init__(self, id=None, model=None):
super().__init__(id, model)

self.watch("show_stereotypes", self.update_shapes).watch(
"show_parts", self.update_shapes
).watch("show_references", self.update_shapes).watch(
"subject[NamedElement].name"
).watch(
"subject[NamedElement].namespace.name"
).watch(
"subject[Classifier].isAbstract", self.update_shapes
).watch(
"subject[Class].ownedAttribute.aggregation", self.update_shapes
)
attribute_watches(self, "Block")
stereotype_watches(self)

show_stereotypes: attribute[int] = attribute("show_stereotypes", int)

show_parts: attribute[int] = attribute("show_parts", int, default=False)

show_references: attribute[int] = attribute("show_references", int, default=False)

def update_shapes(self, event=None):
self.shape = Box(
Box(
Text(
text=lambda: stereotypes_str(self.subject, ["block"]),
style={"min-width": 0, "min-height": 0},
),
EditableText(
text=lambda: self.subject.name or "",
width=lambda: self.width - 4,
style={
"font-weight": FontWeight.BOLD,
"font-style": FontStyle.ITALIC
if self.subject and self.subject.isAbstract
else FontStyle.NORMAL,
},
),
Text(
text=lambda: from_package_str(self),
style={"font-size": 10, "min-width": 0, "min-height": 0},
),
style={"padding": (12, 4, 12, 4)},
),
*(
self.show_parts
and self.subject
and [
self.block_compartment(
gettext("parts"),
lambda a: a.association and a.aggregation == "composite",
)
]
or []
),
*(
self.show_references
and self.subject
and [
self.block_compartment(
gettext("references"),
lambda a: a.association and a.aggregation != "composite",
)
]
or []
),
*(self.show_stereotypes and stereotype_compartments(self.subject) or []),
style={
"min-width": 100,
"min-height": 50,
"vertical-align": VerticalAlign.TOP,
},
draw=draw_border,
)

def block_compartment(self, name, predicate):
# We need to fix the attribute value, since the for loop changes it.
def lazy_format(attribute):
return lambda: format_attribute(attribute) or gettext("unnamed")

return Box(
Text(
text=name,
style={
"padding": (0, 0, 4, 0),
"font-size": 10,
"font-style": FontStyle.ITALIC,
},
),
*(
Text(text=lazy_format(attribute), style={"text-align": TextAlign.LEFT})
for attribute in self.subject.ownedAttribute
if predicate(attribute)
),
style={"padding": (4, 4, 4, 4), "min-height": 8},
draw=draw_top_separator,
)
52 changes: 52 additions & 0 deletions gaphor/SysML/propertypages.glade
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,58 @@ Edit, from the popup menu, will allow you to add cell
renderers and such.</property>
<property name="xalign">0</property>
</object>
<object class="GtkExpander" id="parts-and-references-editor">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="margin_top">12</property>
<property name="expanded">True</property>
<child>
<object class="GtkBox">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="margin_top">6</property>
<property name="orientation">vertical</property>
<property name="spacing">6</property>
<child>
<object class="GtkCheckButton" id="show-parts">
<property name="label" translatable="yes">Show parts</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">False</property>
<property name="draw_indicator">True</property>
<signal name="toggled" handler="show-parts-changed" swapped="no"/>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkCheckButton" id="show-references">
<property name="label" translatable="yes">Show references</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">False</property>
<property name="draw_indicator">True</property>
<signal name="toggled" handler="show-references-changed" swapped="no"/>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
</object>
</child>
<child type="label">
<object class="GtkLabel">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Parts and References</property>
</object>
</child>
</object>
<object class="GtkTextBuffer" id="requirement-text-buffer"/>
<object class="GtkBox" id="requirement-editor">
<property name="visible">True</property>
Expand Down
49 changes: 49 additions & 0 deletions gaphor/SysML/propertypages.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@
from gaphor.core import transactional
from gaphor.diagram.propertypages import PropertyPageBase, PropertyPages
from gaphor.SysML import sysml
from gaphor.SysML.blocks.block import BlockItem
from gaphor.SysML.requirements.requirement import RequirementItem
from gaphor.UML.classes.classespropertypages import AttributesPage, OperationsPage


def new_builder(*object_ids):
Expand Down Expand Up @@ -70,3 +73,49 @@ def _on_text_changed(self, buffer):
self.subject.text = buffer.get_text(
buffer.get_start_iter(), buffer.get_end_iter(), False
)


PropertyPages.register(RequirementItem)(AttributesPage)
PropertyPages.register(RequirementItem)(OperationsPage)


@PropertyPages.register(BlockItem)
class PartsAndReferencesPage(PropertyPageBase):
"""An editor for Block items."""

order = 30

def __init__(self, item):
super().__init__()
self.item = item
self.watcher = item.subject and item.subject.watcher()

def construct(self):
if not self.item.subject:
return

builder = new_builder("parts-and-references-editor")

show_parts = builder.get_object("show-parts")
show_parts.set_active(self.item.show_parts)

show_references = builder.get_object("show-references")
show_references.set_active(self.item.show_references)

builder.connect_signals(
{
"show-parts-changed": (self._on_show_parts_change,),
"show-references-changed": (self._on_show_references_change,),
}
)
return builder.get_object("parts-and-references-editor")

@transactional
def _on_show_parts_change(self, button):
self.item.show_parts = button.get_active()
self.item.request_update()

@transactional
def _on_show_references_change(self, button):
self.item.show_references = button.get_active()
self.item.request_update()
46 changes: 33 additions & 13 deletions gaphor/SysML/requirements/requirement.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,9 @@
from gaphor.diagram.presentation import from_package_str
from gaphor.core.modeling.properties import attribute
from gaphor.diagram.presentation import (
Classified,
ElementPresentation,
from_package_str,
)
from gaphor.diagram.shapes import (
Box,
EditableText,
Expand All @@ -13,34 +18,49 @@
from gaphor.diagram.support import represents
from gaphor.SysML.sysml import Requirement
from gaphor.UML.classes.klass import (
ClassItem,
attribute_watches,
attributes_compartment,
operation_watches,
operations_compartment,
stereotype_compartments,
stereotype_watches,
)
from gaphor.UML.modelfactory import stereotypes_str


@represents(Requirement)
class RequirementItem(ClassItem):
class RequirementItem(ElementPresentation[Requirement], Classified):
def __init__(self, id=None, model=None):
super().__init__(id, model)

self.show_attributes = False
self.show_operations = False
self.watch("subject[AbstractRequirement].externalId", self.update_shapes)
self.watch("subject[AbstractRequirement].text", self.update_shapes)
self.watch("show_stereotypes", self.update_shapes).watch(
"show_attributes", self.update_shapes
).watch("show_operations", self.update_shapes).watch(
"subject[NamedElement].name"
).watch(
"subject[NamedElement].namespace.name"
).watch(
"subject[Classifier].isAbstract", self.update_shapes
).watch(
"subject[AbstractRequirement].externalId", self.update_shapes
).watch(
"subject[AbstractRequirement].text", self.update_shapes
)
attribute_watches(self, "Requirement")
operation_watches(self, "Requirement")
stereotype_watches(self)

show_stereotypes: attribute[int] = attribute("show_stereotypes", int)

show_attributes: attribute[int] = attribute("show_attributes", int, default=False)

def additional_stereotypes(self):
return ["requirement"]
show_operations: attribute[int] = attribute("show_operations", int, default=False)

def update_shapes(self, event=None):
self.shape = Box(
Box(
Text(
text=lambda: stereotypes_str(
self.subject, self.additional_stereotypes()
),
text=lambda: stereotypes_str(self.subject, ["requirement"]),
style={"min-width": 0, "min-height": 0},
),
EditableText(
Expand Down Expand Up @@ -82,7 +102,7 @@ def update_shapes(self, event=None):
)

def id_and_text_compartment(self):
subject: Requirement = self.subject # type: ignore[assignment]
subject = self.subject
if subject and (subject.externalId or subject.text):
return Box(
*(
Expand Down
23 changes: 13 additions & 10 deletions gaphor/UML/classes/klass.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,21 +45,12 @@ def __init__(self, id=None, model=None):
"subject[NamedElement].name"
).watch(
"subject[NamedElement].namespace.name"
).watch(
"subject.appliedStereotype", self.update_shapes
).watch(
"subject.appliedStereotype.classifier.name"
).watch(
"subject.appliedStereotype.slot", self.update_shapes
).watch(
"subject.appliedStereotype.slot.definingFeature.name"
).watch(
"subject.appliedStereotype.slot.value", self.update_shapes
).watch(
"subject[Classifier].isAbstract", self.update_shapes
)
attribute_watches(self, "Class")
operation_watches(self, "Class")
stereotype_watches(self)

show_stereotypes: attribute[int] = attribute("show_stereotypes", int)

Expand Down Expand Up @@ -140,6 +131,8 @@ def attribute_watches(presentation, cast):
f"subject[{cast}].ownedAttribute.upperValue"
).watch(
f"subject[{cast}].ownedAttribute.defaultValue"
).watch(
f"subject[{cast}].ownedAttribute.type"
).watch(
f"subject[{cast}].ownedAttribute.typeValue"
)
Expand Down Expand Up @@ -171,6 +164,16 @@ def operation_watches(presentation, cast):
)


def stereotype_watches(presentation):
presentation.watch("subject.appliedStereotype", presentation.update_shapes).watch(
"subject.appliedStereotype.classifier.name"
).watch("subject.appliedStereotype.slot", presentation.update_shapes).watch(
"subject.appliedStereotype.slot.definingFeature.name"
).watch(
"subject.appliedStereotype.slot.value", presentation.update_shapes
)


def attributes_compartment(subject):
# We need to fix the attribute value, since the for loop changes it.
def lazy_format(attribute):
Expand Down