Since version 2.0, Gaphor supports the concept of Modeling languages. This allows for development of separate modeling languages separate from the Gaphor core application.
The main language was, and will be UML. Gaphor now also supports a subset of SysML, RAAML and the C4 model.
A modeling language in Gaphor is defined by a class implementing the
gaphor.abc.ModelingLanguage abstract base class. The modeling language should
be registered as a
gaphor.modelinglanguage entry point.
ModelingLanguage interface is fairly minimal. It allows other services to
look up elements and diagram items, as well as a toolbox, and diagram types.
However, the responsibilities of a modeling language do not stop there. Parts of
functionality will be implemented by registering handlers to a set of generic
But let’s not get ahead of ourselves. What is the functionality a modeling language implementation can offer?
A data model (elements) and diagram items
A toolbox definition
Connectors, allow diagram items to connect
Grouping, allow elements to be nested in one another
Dropping, allow elements to be dragged from the tree view onto a diagram
Editor pages, shown in the collapsible pane on the right side
Automatic cleanup rules to keep the model consistent
Copy/paste behavior when element copying is not trivial, for example with more than one element is involved
The first three by functionalities are exposed by the
The other functionalities can be extended by adding handlers to the respective
- class gaphor.abc.ModelingLanguage
A model provider is a special service that provides an entrypoint to a model implementation, such as UML, SysML, RAAML.
- abstract property diagram_types: Iterable[DiagramType]
Iterate diagram types.
- abstract lookup_element(name: str) type[Element] | None
Look up a model element type by (class) name.
- abstract property toolbox_definition: ToolboxDefinition
Get structure for the toolbox.
Connectors are used to connect one element to another.
Connectors should adhere to the
Normally you would inherit from
- class gaphor.diagram.connectors.BaseConnector(element: gaphor.core.modeling.presentation.Presentation[gaphor.core.modeling.element.Element], line: gaphor.core.modeling.presentation.Presentation[gaphor.core.modeling.element.Element])
Connection adapter for Gaphor diagram items.
lineconnects with a handle to a connectable item
line (Presentation) – connecting item
element (Presentation) – connectable item
The following methods are required to make this work:
allow(): is the connection allowed at all (during mouse movement for example).
connect(): Establish a connection between element and line. Also takes care of disconnects, if required (e.g. 1:1 relationships)
disconnect(): Break connection, called when dropping a handle on a point where it can not connect.
By convention the adapters are registered by (element, line) – in that order.
- allow(handle: gaphas.handle.Handle, port: gaphas.port.Port) bool
Determine if items can be connected.
Returns True if connection is allowed.
- connect(handle: gaphas.handle.Handle, port: gaphas.port.Port) bool
Connect to an element. Note that at this point the line may be connected to some other, or the same element. Also the connection at model level still exists.
Returns True if a connection is established.
Grouping is done by dragging one item on top of another, in a diagram or in the tree view.
- gaphor.diagram.group.group(parent: Element, element: Element) bool
Group an element in a parent element. The grouping can be based on ownership, but other types of grouping are also possible.
- gaphor.diagram.group.ungroup(parent: Element, element: Element) bool
Remove the grouping from an element. The function needs to check if the provided parent node is the right one.
Dropping is performed by dragging an element from the tree view and drop it on a diagram. This is an easy way to extend a diagram with already existing model elements.
- gaphor.diagram.drop.drop(element: Element, diagram: Diagram, x: float, y: float) Presentation | None
The drop function creates a new presentation for an element on the diagram. For relationships, a drop only works if both connected elements are present in the same diagram.
The big difference with dragging an element from the toolbox, is that dragging from the toolbox will actually place a new
Presentationelement on the diagram.
dropworks the other way around: it starts with a model element and creates an accompanying
Editor property pages
The editor page is constructed from snippets. For example: almost each element has a name, so there is a UI snippet that allows you to edit a name.
Each property page (snippet) should inherit from
Instant (diagram) editor popups
When you double click on an item in a diagram, a popup can show up so you can easily change the name.
By default this works for any named element. You can register your own inline editor function if you need to.
- gaphor.diagram.inlineeditors.InlineEditor(item: Item, view, event_manager, pos: Optional[Tuple[int, int]] = None) bool
Show a small editor popup in the diagram. Makes for easy editing without resorting to the Element editor.
In case of a mouse press event, the mouse position (relative to the element) are also provided.
Automated model cleanup
Gaphor wants to keep the model in sync with the diagrams.
A little dispatch function is used to determine if a model element can be removed.
Copy and paste
Copy and paste works out of the box for simple items: one diagram item with one model element (the
It leveages the
save() methods of the elements to ensure all relevant data is copied.
Sometimes items need more than one model element to work. For example an Association: it has two association ends.
In those specific cases you need to implement your own copy and paste functions. To create such a thing you’ll need to create two functions: one for copying and one for pasting.
- gaphor.diagram.copypaste.copy(obj: Element) Iterator[tuple[Id, Opaque]]
Create a copy of an element (or list of elements). The returned type should be distinct, so the paste() function can properly dispatch.
- gaphor.diagram.copypaste.paste(copy_data: T, diagram: Diagram, lookup: Callable[[str], Element | None]) Iterator[Element]
Paste previously copied data. Based on the data type created in the
copy()function, try to duplicate the copied elements. Returns the newly created item or element
Create a copy of the Presentation element, but try to link the underlaying model element. A shallow copy.
- gaphor.diagram.copypaste.paste_full(copy_data: CopyData, diagram: Diagram, lookup: Callable[[str], Element | None]) set[Presentation]:
Create a copy of both Presentation and model element. A deep copy.
To serialize the copied elements and deserialize them again, there are two functions available:
Return a serialized version of a value. If the
valueis an element, it’s referenced.
- gaphor.diagram.copypaste.deserialize(ser, lookup)
Deserialize a value previously serialized with
lookupfunction is used to resolve references to other elements.