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

Namespace show all #336

Merged
merged 6 commits into from
Jun 4, 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
15 changes: 15 additions & 0 deletions gaphor/UML/tests/test_umllex.py
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,21 @@ def test_parse_association_end_derived_end(factory):
assert not p.defaultValue


def test_parse_association_end_with_type(factory):
"""Test parsing of association end, type is ignored
"""
a = factory.create(UML.Association)
p = factory.create(UML.Property)
p.association = a

UML.parse(p, "end: TypeVal")
assert "end" == p.name
assert not p.typeValue
assert not p.lowerValue
assert not p.upperValue
assert not p.defaultValue


def test_parse_operation(factory):
"""Test parsing simple operation
"""
Expand Down
11 changes: 5 additions & 6 deletions gaphor/UML/umlfmt.py
Original file line number Diff line number Diff line change
Expand Up @@ -59,10 +59,8 @@ def format_attribute(
will not give you the same result.
"""
name = el.name
if not name:
return name

if no_render_pat.match(name):
if name and no_render_pat.match(name):
return name

# Render all fields if they all are set to False
Expand All @@ -71,14 +69,15 @@ def format_attribute(

s = []

if visibility:
if name and visibility:
s.append(vis_map[el.visibility])
s.append(" ")

if is_derived and el.isDerived:
if name and is_derived and el.isDerived:
s.append("/")

s.append(name)
if name:
s.append(name)

if type and el.typeValue:
s.append(f": {el.typeValue}")
Expand Down
12 changes: 8 additions & 4 deletions gaphor/UML/umllex.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,12 +34,12 @@ def parse(el, text):
# name (required) ::= name
name_subpat = r"\s*(?P<name>[a-zA-Z_]\w*)"

# Multiplicity (added to type_subpat) ::= '[' [mult_l ..] mult_u ']'
# Multiplicity ::= '[' [mult_l ..] mult_u ']'
mult_subpat = r"\s*(\[\s*((?P<mult_l>[0-9]+)\s*\.\.)?\s*(?P<mult_u>([0-9]+|\*))\s*\])?"
multa_subpat = r"\s*(\[?((?P<mult_l>[0-9]+)\s*\.\.)?\s*(?P<mult_u>([0-9]+|\*))\]?)?"

# Type and multiplicity (optional) ::= ':' type [mult]
type_subpat = r"\s*(:\s*(?P<type>\w+)\s*" + mult_subpat + r")?"
# Type and multiplicity (optional) ::= ':' type
type_subpat = r"\s*(:\s*(?P<type>\w+))?"

# default value (optional) ::= '=' default
default_subpat = r"\s*(=\s*(?P<default>\S+))?"
Expand Down Expand Up @@ -72,6 +72,7 @@ def compile(regex):
+ derived_subpat
+ name_subpat
+ type_subpat
+ mult_subpat
+ default_subpat
+ tags_subpat
+ garbage_subpat
Expand All @@ -85,6 +86,7 @@ def compile(regex):
+ vis_subpat
+ derived_subpat
+ name_subpat
+ type_subpat
+ mult_subpat
+ ")?"
+ tags_subpat
Expand All @@ -103,6 +105,7 @@ def compile(regex):
+ name_subpat
+ params_subpat
+ type_subpat
+ mult_subpat
+ tags_subpat
+ garbage_subpat
)
Expand All @@ -114,14 +117,15 @@ def compile(regex):
+ dir_subpat
+ name_subpat
+ type_subpat
+ mult_subpat
+ default_subpat
+ tags_subpat
+ rest_subpat
)

# Lifeline:
# [name] [: type]
lifeline_pat = compile("^" + name_subpat + type_subpat + garbage_subpat)
lifeline_pat = compile("^" + name_subpat + type_subpat + mult_subpat + garbage_subpat)


def _set_visibility(el: uml.Feature, vis: str):
Expand Down
63 changes: 28 additions & 35 deletions gaphor/ui/namespace.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,31 +26,13 @@
from gaphor.ui.actiongroup import create_action_group
from gaphor.ui.event import DiagramOpened
from gaphor.ui.iconname import get_icon_name
from gaphor.UML.umlfmt import format_attribute, format_operation
from gaphor.UML.umllex import parse

if TYPE_CHECKING:
from gaphor.core.modeling import ElementFactory
from gaphor.core.eventmanager import EventManager

# The following items will be shown in the treeview, although they
# are UML.Namespace elements.
_default_filter_list = (
UML.Class,
UML.Interface,
UML.Package,
UML.Component,
UML.Device,
UML.Node,
UML.Artifact,
UML.Interaction,
UML.UseCase,
UML.Actor,
Diagram,
UML.Profile,
UML.Stereotype,
UML.Property,
UML.Operation,
)


log = logging.getLogger(__name__)

Expand Down Expand Up @@ -120,10 +102,15 @@ def expand_root_nodes(self):
def _set_pixbuf(self, column, cell, model, iter, data):
element = model.get_value(iter, 0)

icon_name = get_icon_name(element)
if isinstance(element, (UML.Property, UML.Operation)):
cell.set_property("icon-name", None)
cell.set_property("visible", False)
else:
icon_name = get_icon_name(element)
cell.set_property("visible", True)

if icon_name:
cell.set_property("icon-name", icon_name)
if icon_name:
cell.set_property("icon-name", icon_name)

def _set_text(self, column, cell, model, iter, data):
"""
Expand All @@ -138,6 +125,10 @@ def _set_text(self, column, cell, model, iter, data):
isinstance(element, UML.Classifier) or isinstance(element, UML.Operation)
) and element.isAbstract:
text = f"<i>{text}</i>"
elif isinstance(element, UML.Property):
text = format_attribute(element) or "&lt;None&gt;"
elif isinstance(element, UML.Operation):
text = format_operation(element)

cell.set_property("markup", text)

Expand All @@ -152,7 +143,10 @@ def _text_edited(self, cell, path_str, new_text):
model = self.get_property("model")
iter = model.get_iter_from_string(path_str)
element = model.get_value(iter, 0)
element.name = new_text
if isinstance(element, (UML.Property, UML.Operation)):
parse(element, new_text)
else:
element.name = new_text
except Exception:
log.error(f'Could not create path from string "{path_str}"')

Expand Down Expand Up @@ -213,7 +207,7 @@ def on_drag_data_received(self, context, x, y, selection, info, time):
element = self.element_factory.lookup(element_id)
assert isinstance(
element, (Diagram, UML.Package, UML.Type)
), f"Element with id {element_id} is not part of the model"
), f"Element {element} can not be moved"
path, position = drop_info
iter = model.get_iter(path)
dest_element = model.get_value(iter, 0)
Expand Down Expand Up @@ -259,7 +253,6 @@ def __init__(self, event_manager: EventManager, element_factory: ElementFactory)
self.element_factory = element_factory
self._namespace: Optional[NamespaceView] = None
self.model = Gtk.TreeStore.new([object])
self.toplevel_types = _default_filter_list

def open(self):
em = self.event_manager
Expand Down Expand Up @@ -406,10 +399,11 @@ def iter_for_element(self, element, old_namespace=0):
return None

def _visible(self, element):
# Special case: Non-navigable properties
return type(element) in self.toplevel_types and not (
isinstance(element, UML.Property) and element.namespace is None
)
""" Special case: Non-navigable properties. """
return (
(isinstance(element, UML.NamedElement) and element.namespace)
or isinstance(element, UML.PackageableElement)
) and not isinstance(element, (UML.InstanceSpecification, UML.Relationship))

def _add(self, element, iter=None):
if self._visible(element):
Expand All @@ -431,13 +425,12 @@ def _on_model_ready(self, event=None):
self.model.clear()

toplevel = self.element_factory.select(
lambda e: isinstance(e, UML.NamedElement)
and type(e) in self.toplevel_types
and not e.namespace
lambda e: isinstance(e, UML.PackageableElement) and not e.namespace
)

for element in toplevel:
self._add(element)
if self._visible(element):
self._add(element)

# Expand all root elements:
if self._namespace: # None for testing
Expand All @@ -458,7 +451,7 @@ def _on_element_create(self, event: ElementCreated):
@event_handler(ElementDeleted)
def _on_element_delete(self, event: ElementDeleted):
element = event.element
if type(element) in self.toplevel_types:
if isinstance(element, UML.NamedElement):
iter = self.iter_for_element(element)
# iter should be here, unless we try to delete an element who's
# parent element is already deleted, so let's be lenient.
Expand Down
2 changes: 1 addition & 1 deletion gaphor/ui/tests/test_namespace.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ def test_root_element(namespace, element_factory):


def test_should_not_add_non_namespace_element(namespace, element_factory):
element_factory.create(UML.Activity)
element_factory.create(UML.Action)

assert namespace.model.iter_n_children(None) == 0

Expand Down