Merge pull request #863 from gaphor/feature/element-notes

Feature/element notes
This commit is contained in:
Dan Yeaw 2021-06-16 21:04:52 -04:00 committed by GitHub
commit 443731b537
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 347 additions and 158 deletions

View File

@ -55,7 +55,7 @@ class ClassAttributes(EditableTreeModel):
def get_rows(self):
for attr in self._item.subject.ownedAttribute:
if not attr.association:
yield [format(attr), attr.isStatic, attr]
yield [format(attr, note=True), attr.isStatic, attr]
def create_object(self):
attr = self._item.model.create(UML.Property)
@ -67,13 +67,13 @@ class ClassAttributes(EditableTreeModel):
attr = row[-1]
if col == 0:
parse(attr, value)
row[0] = format(attr)
row[0] = format(attr, note=True)
elif col == 1:
attr.isStatic = not attr.isStatic
row[1] = attr.isStatic
elif col == 2:
# Value in attribute object changed:
row[0] = format(attr)
row[0] = format(attr, note=True)
row[1] = attr.isStatic
def swap_objects(self, o1, o2):
@ -92,7 +92,7 @@ class ClassOperations(EditableTreeModel):
def get_rows(self):
for operation in self._item.subject.ownedOperation:
yield [
format(operation),
format(operation, note=True),
operation.isAbstract,
operation.isStatic,
operation,
@ -108,7 +108,7 @@ class ClassOperations(EditableTreeModel):
operation = row[-1]
if col == 0:
parse(operation, value)
row[0] = format(operation)
row[0] = format(operation, note=True)
elif col == 1:
operation.isAbstract = not operation.isAbstract
row[1] = operation.isAbstract
@ -116,7 +116,7 @@ class ClassOperations(EditableTreeModel):
operation.isStatic = not operation.isStatic
row[2] = operation.isStatic
elif col == 3:
row[0] = format(operation)
row[0] = format(operation, note=True)
row[1] = operation.isAbstract
row[2] = operation.isStatic
@ -335,7 +335,11 @@ class AttributesPage(PropertyPageBase):
attribute = event.element
for row in self.model:
if row[-1] is attribute:
row[:] = [format(attribute), attribute.isStatic, attribute]
row[:] = [
format(attribute, note=True),
attribute.isStatic,
attribute,
]
self.watcher.watch("ownedAttribute.name", handler).watch(
"ownedAttribute.isDerived", handler
@ -409,7 +413,7 @@ class OperationsPage(PropertyPageBase):
for row in self.model:
if row[-1] is operation:
row[:] = [
format(operation),
format(operation, note=True),
operation.isAbstract,
operation.isStatic,
operation,

View File

@ -435,7 +435,7 @@ renderers and such.</property>
Attribute syntax examples
- attr
- + attr: int
- # /attr: int
- # /attr: int # a note
Press ENTER to edit item, BS/DEL to remove item.
Use -/= to move items up or down.</property>
@ -768,7 +768,7 @@ Use -/= to move items up or down.</property>
<property name="can-focus">True</property>
<property name="tooltip-text" translatable="yes">Add and edit class operations according to UML syntax. Operation syntax examples
- call()
- + call(a: int, b: str)
- + call(a: int, b: str) # a note
- # call(a: int: b: str): bool
Press ENTER to edit item, BS/DEL to remove item.

View File

@ -38,6 +38,8 @@ def add_tag_is_foo_metadata_field(e, factory):
("- myattr:int[0..1]", "- myattr: int[0..1]"),
("/myattr:int", "+ /myattr: int"),
("myattr:int=3", "+ myattr: int = 3"),
("myattr: int#some note", "+ myattr: int # some note"),
("# myattr:int=3 #some note", "# myattr: int = 3 # some note"),
],
)
def test_attribute(factory, text, formatted_text):
@ -45,7 +47,7 @@ def test_attribute(factory, text, formatted_text):
a = factory.create(UML.Property)
parse(a, text)
assert formatted_text == format(a)
assert formatted_text == format(a, note=True)
def test_attribute_with_applied_stereotype(factory):
@ -110,6 +112,7 @@ def test_association_end_with_applied_stereotype(factory):
"- myoper(in p1: str[2], in p2: int[1..*])",
),
("+ (param: str): int", "+ (param: str): int"),
("+ myoper(param: str): int#a note", "+ myoper(in param: str): int # a note"),
],
)
def test_operation(factory, text, formatted_text):
@ -117,7 +120,7 @@ def test_operation(factory, text, formatted_text):
o = factory.create(UML.Operation)
parse(o, text)
assert formatted_text == format(o)
assert formatted_text == format(o, note=True)
def test_slot(factory):

View File

@ -59,7 +59,7 @@ def test_parse_property_complex(factory):
"""Test complex property parsing."""
a = factory.create(UML.Property)
parse(a, '+ / name : str[0..*] = "aap" { static }')
parse(a, '+ / name : str[0..*] = "aap" { static }# and a note')
assert "public" == a.visibility
assert a.isDerived
assert "name" == a.name
@ -67,6 +67,7 @@ def test_parse_property_complex(factory):
assert "0" == a.lowerValue
assert "*" == a.upperValue
assert '"aap"' == a.defaultValue
assert "and a note" == a.note
def test_parse_property_with_space_in_name(factory):
@ -79,6 +80,16 @@ def test_parse_property_with_space_in_name(factory):
assert "str" == a.typeValue
def test_parse_property_with_default_value_and_note(factory):
a = factory.create(UML.Property)
parse(a, "name=3 #note")
assert "name" == a.name
assert "3" == a.defaultValue
assert "note" == a.note
def test_parse_property_invalid(factory):
"""Test parsing property with invalid syntax."""
a = factory.create(UML.Property)
@ -161,6 +172,16 @@ def test_parse_association_end_with_type(factory):
assert not p.defaultValue
def test_parse_association_end_with_note(factory):
a = factory.create(UML.Association)
p = factory.create(UML.Property)
p.association = a
parse(p, "end # some note")
assert "end" == p.name
assert "some note" == p.note
def test_parse_operation(factory):
"""Test parsing simple operation."""
o = factory.create(UML.Operation)
@ -221,3 +242,11 @@ def test_parse_operation_invalid_syntax(factory):
o = factory.create(UML.Operation)
parse(o, "- myfunc2: myType2")
assert "- myfunc2: myType2" == o.name
def test_parse_operation_with_note(factory):
"""Test parsing simple operation."""
o = factory.create(UML.Operation)
parse(o, "myfunc() # and a note")
assert "myfunc" == o.name
assert "and a note" == o.note

View File

@ -20,6 +20,7 @@ def format_property(
multiplicity=False,
default=False,
tags=False,
note=False,
):
"""Create a OCL representation of the attribute, Returns the attribute as a
string. If one or more of the parameters (visibility, is_derived, type,
@ -66,6 +67,10 @@ def format_property(
slots = [format(slot) for slot in el.appliedStereotype[:].slot if slot]
if slots:
s.append(" { %s }" % ", ".join(slots))
if note and el.note:
s.append(f" # {el.note}")
return "".join(s)
@ -101,6 +106,7 @@ def format_operation(
default=False,
tags=False,
direction=False,
note=False,
):
"""Create a OCL representation of the operation, Returns the operation as a
string."""
@ -138,6 +144,10 @@ def format_operation(
rr = next((p for p in el.ownedParameter if p.direction == "return"), None)
if rr:
s.append(format(rr, type=type, multiplicity=multiplicity, default=default))
if note and el.note:
s.append(f" # {el.note}")
return "".join(s)

View File

@ -44,6 +44,9 @@ rest_subpat = r"\s*(,\s*(?P<rest>.*))?"
# Direction of a parameter (optional, default in) ::= 'in' | 'out' | 'inout'
dir_subpat = r"\s*((?P<dir>in|out|inout)\s)?"
# A note ::= '#' text
note_subpat = r"\s*(#\s*(?P<note>.*))?"
# Some trailing garbage => no valid syntax...
garbage_subpat = r"\s*(?P<garbage>.*)"
@ -63,6 +66,7 @@ attribute_pat = compile(
+ mult_subpat
+ default_subpat
+ tags_subpat
+ note_subpat
+ garbage_subpat
)
@ -78,6 +82,7 @@ association_end_name_pat = compile(
+ mult_subpat
+ ")?"
+ tags_subpat
+ note_subpat
+ garbage_subpat
)
@ -95,6 +100,7 @@ operation_pat = compile(
+ type_subpat
+ mult_subpat
+ tags_subpat
+ note_subpat
+ garbage_subpat
)
@ -151,6 +157,8 @@ def parse_attribute(el: uml.Property, s: str) -> None:
el.upperValue = None
if el.defaultValue:
el.defaultValue = None
if el.note:
el.note = None
else:
g = m.group
_set_visibility(el, g("vis"))
@ -160,6 +168,7 @@ def parse_attribute(el: uml.Property, s: str) -> None:
el.lowerValue = g("mult_l")
el.upperValue = g("mult_u")
el.defaultValue = g("default")
el.note = g("note")
def parse_association_end(el: uml.Property, s: str) -> None:
@ -192,10 +201,12 @@ def parse_association_end(el: uml.Property, s: str) -> None:
el.name = s
del el.visibility
del el.isDerived
del el.note
else:
_set_visibility(el, g("vis"))
el.isDerived = g("derived") and True or False
el.name = g("name")
el.note = g("note")
# Optionally, the multiplicity and tagged values may be defined:
if g("mult_l"):
el.lowerValue = g("mult_l")
@ -232,6 +243,7 @@ def parse_operation(el: uml.Operation, s: str) -> None:
create = el.model.create
_set_visibility(el, g("vis"))
el.name = g("name")
el.note = g("note")
defined_params = set()
if g("type"):

View File

@ -31,6 +31,7 @@ class Comment(Element):
# defined in gaphor.core.modeling.presentation
Element.note = attribute("note", str)
Diagram.name = attribute("name", str)
Comment.body = attribute("body", str)
# 12: override StyleSheet.styleSheet

View File

@ -11,7 +11,12 @@ from typing import TYPE_CHECKING, Callable, Iterator, Optional, Type, TypeVar, o
from typing_extensions import Protocol
from gaphor.core.modeling.event import ElementUpdated
from gaphor.core.modeling.properties import relation_many, relation_one, umlproperty
from gaphor.core.modeling.properties import (
attribute,
relation_many,
relation_one,
umlproperty,
)
if TYPE_CHECKING:
from gaphor.core.modeling.coremodel import Comment
@ -37,6 +42,7 @@ Id = str
class Element:
"""Base class for all model data classes."""
note: attribute[str]
appliedStereotype: relation_many[Element]
comment: relation_many[Comment]
directedRelationship: relation_many[Presentation]

View File

@ -45,6 +45,7 @@ renderers and such.</property>
<property name="shadow-type">in</property>
<child>
<object class="GtkTextView" id="comment">
<property name="height-request">96</property>
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="wrap-mode">word</property>
@ -61,6 +62,126 @@ renderers and such.</property>
</packing>
</child>
</object>
<object class="GtkExpander" id="enumerations-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="GtkBox">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="spacing">6</property>
<child>
<object class="GtkLabel">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="label" translatable="yes">Show Enumeration Literals</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkSwitch" id="show-enumerations">
<property name="visible">True</property>
<property name="can-focus">True</property>
<signal name="notify::active" handler="show-enumerations-changed" swapped="no"/>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="pack-type">end</property>
<property name="position">1</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkFrame">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="label-xalign">0</property>
<property name="shadow-type">in</property>
<child>
<object class="GtkTreeView" id="enumerations-list">
<property name="height-request">112</property>
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="tooltip-text" translatable="yes">Add and edit enumeration literals according to UML syntax.
Enumeration literal syntax examples
- enum
Press ENTER to edit item, BS/DEL to remove item.
Use -/= to move items up or down.</property>
<property name="headers-clickable">False</property>
<property name="reorderable">True</property>
<property name="enable-search">False</property>
<property name="show-expanders">False</property>
<property name="enable-grid-lines">horizontal</property>
<signal name="destroy" handler="tree-view-destroy" swapped="no"/>
<signal name="key-press-event" handler="enumerations-keypress" swapped="no"/>
<child internal-child="selection">
<object class="GtkTreeSelection"/>
</child>
<child>
<object class="GtkTreeViewColumn">
<property name="resizable">True</property>
<property name="title" translatable="yes">Enumeration Literals</property>
<property name="expand">True</property>
<child>
<object class="GtkCellRendererText">
<property name="xpad">2</property>
<property name="ypad">2</property>
<property name="xalign">0</property>
<property name="editable">True</property>
<signal name="edited" handler="enumerations-name-edited" swapped="no"/>
</object>
<attributes>
<attribute name="text">0</attribute>
</attributes>
</child>
</object>
</child>
</object>
</child>
<child type="label_item">
<placeholder/>
</child>
</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">Enumeration Literals</property>
<attributes>
<attribute name="weight" value="bold"/>
</attributes>
</object>
</child>
</object>
<object class="GtkExpander" id="line-editor">
<property name="visible">True</property>
<property name="can-focus">True</property>
@ -117,120 +238,36 @@ renderers and such.</property>
</object>
</child>
</object>
<object class="GtkExpander" id="enumerations-editor">
<object class="GtkExpander" id="note-editor">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="margin_top">12</property>
<property name="can-focus">True</property>
<property name="margin-top">12</property>
<property name="expanded">True</property>
<child>
<object class="GtkBox">
<object class="GtkFrame">
<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>
<property name="can-focus">False</property>
<property name="label-xalign">0</property>
<property name="margin-top">6</property>
<property name="shadow-type">in</property>
<child>
<object class="GtkBox">
<object class="GtkTextView" id="note">
<property name="height-request">78</property>
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="spacing">6</property>
<child>
<object class="GtkLabel">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Show Enumeration Literals</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkSwitch" id="show-enumerations">
<property name="visible">True</property>
<property name="can_focus">True</property>
<signal name="notify::active" handler="show-enumerations-changed" swapped="no"/>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="pack_type">end</property>
<property name="position">1</property>
</packing>
</child>
<property name="can-focus">True</property>
<property name="wrap-mode">word</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkFrame">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label_xalign">0</property>
<property name="shadow_type">in</property>
<child>
<object class="GtkTreeView" id="enumerations-list">
<property name="height_request">112</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="tooltip_text" translatable="yes">Add and edit enumeration literals according to UML syntax.
Enumeration literal syntax examples
- enum
Press ENTER to edit item, BS/DEL to remove item.
Use -/= to move items up or down.</property>
<property name="headers_clickable">False</property>
<property name="reorderable">True</property>
<property name="enable_search">False</property>
<property name="show_expanders">False</property>
<property name="enable_grid_lines">horizontal</property>
<signal name="destroy" handler="tree-view-destroy" swapped="no"/>
<signal name="key-press-event" handler="enumerations-keypress" swapped="no"/>
<child internal-child="selection">
<object class="GtkTreeSelection"/>
</child>
<child>
<object class="GtkTreeViewColumn">
<property name="resizable">True</property>
<property name="title" translatable="yes">Enumeration Literals</property>
<property name="expand">True</property>
<child>
<object class="GtkCellRendererText">
<property name="xpad">2</property>
<property name="ypad">2</property>
<property name="xalign">0</property>
<property name="editable">True</property>
<signal name="edited" handler="enumerations-name-edited" swapped="no"/>
</object>
<attributes>
<attribute name="text">0</attribute>
</attributes>
</child>
</object>
</child>
</object>
</child>
<child type="label_item">
<placeholder/>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
<child type="label_item">
<placeholder/>
</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">Enumeration Literals</property>
<property name="can-focus">False</property>
<property name="label" translatable="yes">Note / Remark</property>
<attributes>
<attribute name="weight" value="bold"/>
</attributes>

View File

@ -295,3 +295,47 @@ class LineStylePage(PropertyPageBase):
def _on_horizontal_change(self, button):
self.item.horizontal = button.get_active()
self.item.diagram.update_now((self.item,))
@PropertyPages.register(Element)
class NotePropertyPage(PropertyPageBase):
"""A facility to add a little note/remark."""
order = 300
def __init__(self, subject):
self.subject = subject
self.watcher = subject and subject.watcher()
def construct(self):
subject = self.subject
if not subject:
return
builder = new_builder("note-editor")
text_view = builder.get_object("note")
buffer = Gtk.TextBuffer()
if subject.note:
buffer.set_text(subject.note)
text_view.set_buffer(buffer)
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 or "")
buffer.handler_unblock(changed_id)
self.watcher.watch("note", handler)
text_view.connect("destroy", self.watcher.unsubscribe_all)
return builder.get_object("note-editor")
@transactional
def _on_body_change(self, buffer):
self.subject.note = buffer.get_text(
buffer.get_start_iter(), buffer.get_end_iter(), False
)

View File

@ -67,4 +67,27 @@ renderers and such.</property>
</object>
</child>
</object>
<object class="GtkExpander" id="note-editor">
<property name="margin-top">12</property>
<property name="expanded">1</property>
<child type="label">
<object class="GtkLabel">
<property name="label" translatable="yes">Note / Remark</property>
<property name="xalign">0</property>
<attributes>
<attribute name="weight" value="bold"></attribute>
</attributes>
</object>
</child>
<child>
<object class="GtkFrame">
<property name="margin-top">6</property>
<property name="child">
<object class="GtkTextView" id="note">
<property name="wrap-mode">word</property>
</object>
</property>
</object>
</child>
</object>
</interface>

View File

@ -1,5 +1,5 @@
from gaphor.diagram.general import Line
from gaphor.diagram.propertypages import LineStylePage
from gaphor.diagram.propertypages import LineStylePage, NotePropertyPage
from gaphor.diagram.tests.fixtures import find
@ -22,3 +22,13 @@ def test_line_style_page_orientation(diagram):
flip_orientation.set_active(True)
assert item.horizontal
def test_note_page(diagram):
item = diagram.create(Line)
property_page = NotePropertyPage(item)
widget = property_page.construct()
note = find(widget, "note")
note.get_buffer().set_text("A new note")
assert item.note == "A new note"

View File

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<gaphor xmlns="http://gaphor.sourceforge.net/model" version="3.0" gaphor-version="2.4.1">
<gaphor xmlns="http://gaphor.sourceforge.net/model" version="3.0" gaphor-version="2.5.0">
<Package id="3867dda4-7a95-11ea-a112-7f953848cf85">
<name>
<val>Core</val>
@ -23,6 +23,9 @@
</ownedType>
</Package>
<Diagram id="3867dda5-7a95-11ea-a112-7f953848cf85">
<element>
<ref refid="3867dda4-7a95-11ea-a112-7f953848cf85"/>
</element>
<name>
<val>main</val>
</name>
@ -48,11 +51,8 @@
<ref refid="1cb6f4e2-b9a9-11eb-93ad-535118859f0b"/>
</reflist>
</ownedPresentation>
<package>
<ref refid="3867dda4-7a95-11ea-a112-7f953848cf85"/>
</package>
<canvas>
<item id="4cda498f-7a95-11ea-a112-7f953848cf85" type="ClassItem">
</Diagram>
<ClassItem id="4cda498f-7a95-11ea-a112-7f953848cf85">
<matrix>
<val>(1.0, 0.0, 0.0, 1.0, 495.59873557593505, 36.538360595703125)</val>
</matrix>
@ -71,8 +71,8 @@
<subject>
<ref refid="4cda498e-7a95-11ea-a112-7f953848cf85"/>
</subject>
</item>
<item id="5cdae47f-7a95-11ea-a112-7f953848cf85" type="ClassItem">
</ClassItem>
<ClassItem id="5cdae47f-7a95-11ea-a112-7f953848cf85">
<matrix>
<val>(1.0, 0.0, 0.0, 1.0, 560.8694152832031, 521.4187622070312)</val>
</matrix>
@ -91,8 +91,8 @@
<subject>
<ref refid="5cdae47e-7a95-11ea-a112-7f953848cf85"/>
</subject>
</item>
<item id="639b48d1-7a95-11ea-a112-7f953848cf85" type="ClassItem">
</ClassItem>
<ClassItem id="639b48d1-7a95-11ea-a112-7f953848cf85">
<matrix>
<val>(1.0, 0.0, 0.0, 1.0, 221.6815955120582, 389.32879638671875)</val>
</matrix>
@ -111,8 +111,8 @@
<subject>
<ref refid="639b48d0-7a95-11ea-a112-7f953848cf85"/>
</subject>
</item>
<item id="68e63fac-7a95-11ea-a112-7f953848cf85" type="AssociationItem">
</ClassItem>
<AssociationItem id="68e63fac-7a95-11ea-a112-7f953848cf85">
<diagram>
<ref refid="3867dda5-7a95-11ea-a112-7f953848cf85"/>
</diagram>
@ -146,8 +146,8 @@
<tail-connection>
<ref refid="639b48d1-7a95-11ea-a112-7f953848cf85"/>
</tail-connection>
</item>
<item id="1875194e-7a96-11ea-a112-7f953848cf85" type="GeneralizationItem">
</AssociationItem>
<GeneralizationItem id="1875194e-7a96-11ea-a112-7f953848cf85">
<diagram>
<ref refid="3867dda5-7a95-11ea-a112-7f953848cf85"/>
</diagram>
@ -172,8 +172,8 @@
<tail-connection>
<ref refid="5cdae47f-7a95-11ea-a112-7f953848cf85"/>
</tail-connection>
</item>
<item id="c9b0922c-7a97-11ea-a112-7f953848cf85" type="GeneralizationItem">
</GeneralizationItem>
<GeneralizationItem id="c9b0922c-7a97-11ea-a112-7f953848cf85">
<diagram>
<ref refid="3867dda5-7a95-11ea-a112-7f953848cf85"/>
</diagram>
@ -198,8 +198,8 @@
<tail-connection>
<ref refid="639b48d1-7a95-11ea-a112-7f953848cf85"/>
</tail-connection>
</item>
<item id="4b561cdd-7cf9-11ea-b719-1f391582df99" type="GeneralizationItem">
</GeneralizationItem>
<GeneralizationItem id="4b561cdd-7cf9-11ea-b719-1f391582df99">
<diagram>
<ref refid="3867dda5-7a95-11ea-a112-7f953848cf85"/>
</diagram>
@ -224,8 +224,8 @@
<tail-connection>
<ref refid="5175e1cd-7cf9-11ea-b719-1f391582df99"/>
</tail-connection>
</item>
<item id="5175e1cd-7cf9-11ea-b719-1f391582df99" type="ClassItem">
</GeneralizationItem>
<ClassItem id="5175e1cd-7cf9-11ea-b719-1f391582df99">
<matrix>
<val>(1.0, 0.0, 0.0, 1.0, 894.1235656738281, 241.19900512695312)</val>
</matrix>
@ -244,8 +244,8 @@
<subject>
<ref refid="5175e1cc-7cf9-11ea-b719-1f391582df99"/>
</subject>
</item>
<item id="15e4b0b3-9f17-11ea-b537-dfaaecc5bf61" type="ClassItem">
</ClassItem>
<ClassItem id="15e4b0b3-9f17-11ea-b537-dfaaecc5bf61">
<matrix>
<val>(1.0, 0.0, 0.0, 1.0, 772.714640616123, 521.4187622070312)</val>
</matrix>
@ -264,8 +264,8 @@
<subject>
<ref refid="15e4b0b2-9f17-11ea-b537-dfaaecc5bf61"/>
</subject>
</item>
<item id="29de062c-9f17-11ea-b537-dfaaecc5bf61" type="GeneralizationItem">
</ClassItem>
<GeneralizationItem id="29de062c-9f17-11ea-b537-dfaaecc5bf61">
<diagram>
<ref refid="3867dda5-7a95-11ea-a112-7f953848cf85"/>
</diagram>
@ -290,8 +290,8 @@
<tail-connection>
<ref refid="15e4b0b3-9f17-11ea-b537-dfaaecc5bf61"/>
</tail-connection>
</item>
<item id="9bdd3fed-9f17-11ea-b537-dfaaecc5bf61" type="CommentItem">
</GeneralizationItem>
<CommentItem id="9bdd3fed-9f17-11ea-b537-dfaaecc5bf61">
<matrix>
<val>(1.0, 0.0, 0.0, 1.0, 879.1386901855469, 418.12652587890625)</val>
</matrix>
@ -307,8 +307,8 @@
<subject>
<ref refid="9bdd3fec-9f17-11ea-b537-dfaaecc5bf61"/>
</subject>
</item>
<item id="ada170c7-9f17-11ea-b537-dfaaecc5bf61" type="CommentLineItem">
</CommentItem>
<CommentLineItem id="ada170c7-9f17-11ea-b537-dfaaecc5bf61">
<diagram>
<ref refid="3867dda5-7a95-11ea-a112-7f953848cf85"/>
</diagram>
@ -330,8 +330,8 @@
<tail-connection>
<ref refid="9bdd3fed-9f17-11ea-b537-dfaaecc5bf61"/>
</tail-connection>
</item>
<item id="cf596824-e0b9-11ea-b7ab-f5b4c130f24e" type="AssociationItem">
</CommentLineItem>
<AssociationItem id="cf596824-e0b9-11ea-b7ab-f5b4c130f24e">
<diagram>
<ref refid="3867dda5-7a95-11ea-a112-7f953848cf85"/>
</diagram>
@ -365,8 +365,8 @@
<tail-connection>
<ref refid="5175e1cd-7cf9-11ea-b719-1f391582df99"/>
</tail-connection>
</item>
<item id="216581ca-4465-11eb-8946-9bdfa28f7a50" type="AssociationItem">
</AssociationItem>
<AssociationItem id="216581ca-4465-11eb-8946-9bdfa28f7a50">
<diagram>
<ref refid="3867dda5-7a95-11ea-a112-7f953848cf85"/>
</diagram>
@ -400,8 +400,8 @@
<tail-connection>
<ref refid="5cdae47f-7a95-11ea-a112-7f953848cf85"/>
</tail-connection>
</item>
<item id="446a3744-4465-11eb-8946-9bdfa28f7a50" type="AssociationItem">
</AssociationItem>
<AssociationItem id="446a3744-4465-11eb-8946-9bdfa28f7a50">
<diagram>
<ref refid="3867dda5-7a95-11ea-a112-7f953848cf85"/>
</diagram>
@ -435,8 +435,8 @@
<tail-connection>
<ref refid="639b48d1-7a95-11ea-a112-7f953848cf85"/>
</tail-connection>
</item>
<item id="d6e5886b-478f-11eb-a938-8fcfae32d12c" type="CommentItem">
</AssociationItem>
<CommentItem id="d6e5886b-478f-11eb-a938-8fcfae32d12c">
<matrix>
<val>(1.0, 0.0, 0.0, 1.0, 456.234375, 311.32879638671875)</val>
</matrix>
@ -452,8 +452,8 @@
<subject>
<ref refid="d6e5886a-478f-11eb-a938-8fcfae32d12c"/>
</subject>
</item>
<item id="f4982c28-478f-11eb-a938-8fcfae32d12c" type="CommentLineItem">
</CommentItem>
<CommentLineItem id="f4982c28-478f-11eb-a938-8fcfae32d12c">
<diagram>
<ref refid="3867dda5-7a95-11ea-a112-7f953848cf85"/>
</diagram>
@ -475,8 +475,8 @@
<tail-connection>
<ref refid="d6e5886b-478f-11eb-a938-8fcfae32d12c"/>
</tail-connection>
</item>
<item id="1cb6f4e2-b9a9-11eb-93ad-535118859f0b" type="AssociationItem">
</CommentLineItem>
<AssociationItem id="1cb6f4e2-b9a9-11eb-93ad-535118859f0b">
<diagram>
<ref refid="3867dda5-7a95-11ea-a112-7f953848cf85"/>
</diagram>
@ -507,9 +507,7 @@
<tail-connection>
<ref refid="5cdae47f-7a95-11ea-a112-7f953848cf85"/>
</tail-connection>
</item>
</canvas>
</Diagram>
</AssociationItem>
<Class id="4cda498e-7a95-11ea-a112-7f953848cf85">
<isAbstract>
<val>1</val>
@ -522,6 +520,7 @@
<ref refid="d092794e-e0b9-11ea-b7ab-f5b4c130f24e"/>
<ref refid="69c2575a-7a95-11ea-a112-7f953848cf85"/>
<ref refid="1ee6aec6-b9a9-11eb-93ad-535118859f0b"/>
<ref refid="a4c6f704-ce0f-11eb-abe3-018035c40dd4"/>
</reflist>
</ownedAttribute>
<package>
@ -1098,4 +1097,15 @@ diagram {
<val>String</val>
</typeValue>
</Property>
<Property id="a4c6f704-ce0f-11eb-abe3-018035c40dd4">
<class_>
<ref refid="4cda498e-7a95-11ea-a112-7f953848cf85"/>
</class_>
<name>
<val>note</val>
</name>
<typeValue>
<val>str</val>
</typeValue>
</Property>
</gaphor>