Acerca de Gaphor#
Nota
La documentación está actualizada para Gaphor 2.19.0
Gaphor es una aplicación de modelado UML y SysML escrita en Python. Está diseñado para ser fácil de usar, sin dejar de ser potente. Gaphor implementa un modelo de datos UML 2 totalmente compatible, por lo que es mucho más que una herramienta de dibujo de imágenes.
Puede usar Gaphor para visualizar rápidamente distintos aspectos de un sistema, así como para crear modelos completos de gran complejidad.

Gaphor is 100% Open source, available under a friendly Apache 2 license. The code and issue tracker can be found on GitHub.
¿A qué espera? ¡Comencemos!
Para obtener instrucciones de descarga y consultar el blog, visite el sitio web de Gaphor.
Did you know Gaphor has excellent integration with Sphinx and Jupyter notebooks?
Primeros pasos con Gaphor#
Gaphor es más que un editor de diagramas: es un entorno de modelado. Mientras que los editores de diagramas sencillos como Microsoft Visio y draw.io permiten crear imágenes, Gaphor realiza un seguimiento de los elementos que se añaden al modelo. En Gaphor puede crear diagramas para seguir y visualizar diferentes aspectos del sistema que está desarrollando.
Dejémonos de cháchara, empecemos.
You can find installers for Gaphor on the Gaphor Website. Gaphor can be installed on Linux (Flatpak), Windows, and macOS.
Una vez que se inicia Gaphor, aparece una pantalla de bienvenida. En ella se muestran los modelos y plantillas de modelos abiertos anteriormente.
Puede seleccionar una plantilla para empezar.
Genérico: un modelo en blanco para empezar
UML: Una plantilla del Lenguaje Unificado de Modelado para modelar un sistema de software
SysML: Una plantilla del Lenguaje de Modelado de Sistemas para modelar una amplia gama de sistemas y sistemas de sistemas
RAAML: Una plantilla para el Lenguaje de Modelado de Análisis y Evaluación de Riesgos para análisis de seguridad y fiabilidad
C4 Model: A template for Context, Containers, Components, and Code which is for lean modeling of software architecture
Una vez cargada la interfaz del modelo, verá la interfaz de modelado.
La disposición de la interfaz Gaphor se divide en cuatro secciones:
Modelo de navegador
Caja de herramientas de elementos de diagrama
Diagramas
Editor de propiedades
Cada sección tiene su función específica.
Modelo de navegador#
La sección Navegador de modelos de la interfaz muestra una vista jerárquica de su modelo. Cada elemento del modelo que cree se insertará en el Navegador de modelos. Esta vista actúa como un árbol en el que puede expandir y contraer diferentes elementos de su modelo. Esto proporciona una manera fácil de ver los elementos de su modelo desde una perspectiva elidida. Es decir, puede contraer aquellos elementos del modelo que son irrelevantes para la tarea que está realizando.
En la figura anterior, verá que hay dos elementos en el Navegador de modelos. El elemento raíz, Modelo nuevo es un paquete. Observe la pequeña flecha al lado de Modelo nuevo que apunta hacia abajo. Esto indica que el elemento está expandido. También observará que los dos subelementos están ligeramente sangrados con respecto a Modelo nuevo. El elemento principal es un diagrama.
En la vista del Navegador de modelos, también puede hacer clic con el botón derecho del ratón en los elementos del modelo para obtener un menú contextual. Este menú contextual le permite averiguar en qué diagrama se muestran los elementos del modelo, añadir nuevos diagramas y paquetes, y eliminar un elemento.
Haciendo doble clic en un elemento del diagrama se mostrará en la sección Diagrama. Los elementos como clases y paquetes pueden arrastrarse desde la vista en árbol a los diagramas.
Caja de herramientas#
La caja de herramientas se usa para añadir elementos nuevos a un diagrama. Seleccione el elemento que desea añadir haciendo clic sobre él. Al hacer clic en el diagrama, se crea el elemento seleccionado. La flecha vuelve a estar seleccionada, por lo que el elemento puede manipularse.
Las herramientas pueden seleccionarse simplemente haciendo clic con el botón izquierdo del ratón sobre ellas. Por defecto, la herramienta puntero se selecciona después de cada colocación de un elemento. Esto puede cambiarse desactivando la opción «Restablecer herramienta» en la ventana de Preferencias. Las herramientas también pueden seleccionarse mediante atajos del teclado. El atajo del teclado puede mostrarse como información sobre la herramienta pasando el ratón por encima del botón de la herramienta en la caja de herramientas. Por último, también es posible arrastrar elementos sobre el Diagrama desde la caja de herramientas.
Diagramas#
La sección de diagramas contiene diagramas del modelo y es la que ocupa más espacio en la interfaz de usuario porque es donde se realiza la mayor parte del modelado. Los diagramas constan de elementos colocados en el diagrama. Hay dos tipos principales de elementos:
Elementos
Relaciones
Se pueden abrir varios diagramas a la vez: se muestran en pestañas. Las pestañas se pueden cerrar pulsando Ctrl+w o haciendo clic con el botón izquierdo del ratón en la x de la pestaña del diagrama.
Elementos#
Los elementos son las formas que se añaden a un diagrama y, junto con las Relaciones, permiten construir un modelo.
Para cambiar el tamaño de un elemento del diagrama, haga clic con el botón izquierdo del ratón en el elemento para seleccionarlo y, a continuación, arrastre los tiradores de cambio de tamaño que aparecen en cada esquina.
Para mover un elemento en el diagrama, arrastre el elemento donde desee colocarlo manteniendo pulsado el botón izquierdo del ratón y moviendo el ratón antes de soltar el botón.
Relaciones#
Las relaciones son elementos en forma de línea que forman relaciones entre los elementos del diagrama. Cada extremo de una relación se encuentra en uno de dos estados:
Conectado a un elemento y la manilla se vuelve roja
Desconectado de un elemento y la manilla se vuelve verde
Si ambos extremos de una relación están desconectados, la relación puede desplazarse haciendo clic con el botón izquierdo del ratón y arrastrándola.
Se puede añadir un nuevo segmento en una relación haciendo clic con el botón izquierdo del ratón en la relación para seleccionarla y, a continuación, pasando el ratón por encima. Aparecerá un asa verde en medio de los segmentos de línea existentes. Arrastre el asa para añadir otro segmento. Por ejemplo, cuando se crea una nueva relación, ésta sólo tendrá un segmento. Si arrastra el asa del segmento, ahora tendrá dos segmentos con la rodilla de los dos segmentos donde estaba el asa.
Deshacer y rehacer#
Para deshacer un cambio pulse Ctrl+z o haga clic con el botón izquierdo del ratón en la flecha para deshacer situada en la parte superior del Editor de Propiedades. Para rehacer un cambio, pulse Ctrl+Mayús+z o pulse la flecha de rehacer en la parte superior del Editor de propiedades.
Editor de propiedades#
The Property Editor is present on the right side of the diagrams. When no item
is selected in the diagram, it shows you some tips and tricks. When an item is
selected on the diagram, it contains the item details like name, attributes and
stereotypes. It can be opened with F9 and the
icon in
the header bar.
Las propiedades que se muestran dependen del elemento seleccionado.
Preferencias del modelo#
El Editor de propiedades también contiene las preferencias del modelo: Haga clic en el botón . Aquí puede establecer algunos ajustes relacionados con el modelo y editar la style sheet.
Su primer modelo#
Nota
En este tutorial hacemos referencia a las diferentes partes de la interfaz gaphor: Navegador de modelos, Caja de herramientas, Editor de propiedades.
Although the names should speak for themselves, you can check out the Getting Started page for more information.
Una vez iniciado Gaphor, puede iniciar un modelo nuevo con la plantilla Genérico. El diagrama inicial ya está abierto en la sección Diagrama.
Seleccione un elemento que desee colocar, en este caso una Clase () haciendo clic en el icono en la Caja de herramientas y haga clic en el diagrama. Esto colocará una nueva instancia de elemento Clase en el diagrama y añadirá una Clase nueva al modelo – se muestra en el Navegador de modelos. La herramienta seleccionada se restablecerá a la herramienta Puntero después de colocar el elemento en el diagrama.
El Editor de propiedades de la derecha le mostrará detalles sobre la clase recién añadida, como su nombre (Clase nueva), atributos y operaciones (métodos).
Añadir elementos a un diagrama es muy sencillo.
Gaphor no hace suposiciones sobre qué elementos deben colocarse en un diagrama. Un diagrama es un diagrama. UML define todos los diferentes tipos de diagramas, tales como diagramas de clase, diagramas de componentes, diagramas de acción, diagramas de secuencia. Pero Gaphor no impone ninguna restricción.
Añadir relaciones#
Añada otra clase. Cambie los nombres a Forma
y Círculo
. Definamos que Círculo
es un subtipo de Forma
. Puede hacerlo seleccionando uno y cambiando el nombre en el Editor de propiedades, o haciendo doble clic en el elemento.
Seleccione Generalización ().
Mueva el cursor del ratón sobre Forma
. Pulse, mantenga pulsado y arrastre el extremo de la línea sobre Círculo
. Suelte el botón del ratón y tendrá la relación entre Forma
y Círculo
. Puede ver que ambos extremos de la relación están en rojo, indicando que están conectados a su clase.
Opcionalmente, puede ejecutar el diseño automático ( → Herramientas → Diseño automático) para alinear los elementos en el diagrama.
Crear diagramas nuevos#
Para crear un diagrama nuevo, use el Navegador de modelos. Seleccione el elemento que debe contener el nuevo diagrama. Por ahora, seleccione Modelo nuevo. Haga clic en el menú Diagrama nuevo () en la barra de cabecera.
Seleccione Diagrama genérico nuevo y se creará un diagrama nuevo.
Ahora arrastre los elementos del Navegador de modelos al diagrama nuevo. Primero las clases Forma
y Círculo
. Añada la generalización en último lugar. Suéltela en algún lugar entre las dos clases. La relación se creará en el diagrama.
Ahora cambie el nombre de la clase Círculo
por Elipse
. Compruebe el otro diagrama. El nombre ha cambiado allí también.
Importante
Los elementos de un diagrama son sólo una representación de los elementos del modelo subyacente. El modelo es lo que se ve en el Navegador de modelos.
Los elementos del modelo se eliminan automáticamente cuando ya no hay representaciones en ninguno de los diagramas.
Tutorial: Coffee Machine#
Nota
En este tutorial hacemos referencia a las diferentes partes de la interfaz gaphor: Navegador de modelos, Caja de herramientas, Editor de propiedades.
Aunque los nombres deberían hablar por sí solos, puede consultar la página Primeros pasos para obtener más información sobre estas secciones.
Introduction#
In the bustling town of Antville, a colony of ants had formed a Systems Engineering consulting company called AntSource. They value collaboration, transparency, and community-driven engineering, and seeks to empower their employees and customers through open communication and participation in the systems engineering process.
The engineers at AntSource all have nicknames that reflect the key principles and concepts of their craft: Qual-ant, Reli-ant, Safe-ant, Usa-ant, and Sust-ant. They were experts in designing and optimizing complex systems, and they took pride in their work.
One day, a new client approached AntSource with an unusual request. Cappuccino, a cat who owned a popular coffee shop called Milk & Whiskers Café, needed a custom espresso machine designed specifically for felines. Cats just love their coffee strong, with a creamy and smooth body and topped with the perfect foamy layer of crema. The ants were intrigued by the challenge and immediately set to work.
Qual-ant was responsible for ensuring that the machine met all quality standards and specifications, while Reli-ant was tasked with making sure that the machine was dependable and would work correctly every time it was used. Safe-ant designed the machine with safety in mind, ensuring that it wouldn’t cause harm to anyone who used it. Usa-ant designed the machine to be easy and intuitive to use, while Sust-ant ensured that the machine was environmentally friendly and sustainable. In this tutorial we follow the adventures of AntSource to create the perfect kittie espresso machine.
The first thing the ants did was to open Gaphor to the Greeter window and start a new model with the SysML template.
Abstraction Levels#
Abstraction is a way of simplifying complex systems by focusing on only the most important details, while ignoring the rest. It’s a process of reducing complexity by removing unnecessary details and highlighting the key aspects of a system in order to focus on the problem to be solved. It is the key to rigorous analysis of a system.
To understand abstraction, think about a painting. When you look at a painting, you see a representation of something - perhaps a person, a landscape, or an object. The artist has simplified the real world into a set of lines, shapes, and colors that represent the most important details of the subject. In the same way, systems engineers, like our friends the ants, use abstraction to represent complex systems by breaking them down into their essential components and highlighting the most important aspects.
Abstraction levels refer to the different levels of detail at which a system can be represented. These levels are used to break down complex systems into smaller, more manageable parts that can be analyzed and optimized. Said another way, abstraction levels group portions of a design where similar types of questions are answered.
There are typically three levels of abstraction in systems engineering and these are the three levels used in the SysML template:
Concept Level: Sometimes also called Conceptual Level. Defines the problem being solved. This is the highest level of abstraction, where the system is described in terms of its overall purpose, goals, and functions. At this level, the focus is on understanding the system’s requirements and how it will interact with other systems.
Logical Level: Defines a technology-agnostic solution. This is the middle level of abstraction, where the system is described in terms of its structure and behavior. At this level, the focus is on how the system components are organized and how they interact with each other.
Technology Level: Sometimes also called Physical level. Defines the detailed technical solution. This is the lowest level of abstraction, where the system is described in terms of its components and their properties. At this level, the focus is on the details of the system’s implementation.
Each level of abstraction provides a different perspective on the system, and each level is important for different aspects of system design and analysis. For example, the conceptual level is important for understanding the overall goals and requirements of the system, while the physical level is important for understanding how the system will be built and how it will interact with the environment.
There is a fourth abstraction level called the Implementation Level that isn’t modeled, which is the concrete built system.
In the upper left hand corner of Gaphor, the Model Browser shows the three top level packages, dividing up the model in to these three abstraction levels.
Pillars#
There are four pillars of SysML which help classify the types of diagrams based on what they represent:
Behavior: The functionality of a system
Structure: How a system is formed using parts and connections
Requirements: Written statements that constrain the system
Parametrics: Enforces mathematical rules across values in the system
If you want to learn more about these four pillars, there is a 30-minute video by Rick Steiner called The Four Pillars of SysML.
Since Parametrics Diagrams are one of the least used diagram types in SysML, we are going to only focus on the first three. The power of SysML comes in being able to make relationships between these three pillars. For example, by allocating behavior like an activity to an element of the structure like a block.
If you expand the top-level Abstraction Level packages in the Model Browser, each one contains three more packages, one for each pillar. It is in these packages that we will start to build up the design for the espresso machine.
Table of Contents#
Coffee Machine: Concept Level#
Introduction#
The concept level defines the problem we are trying to solve. For the espresso machine, we are going to use diagrams at this abstraction level to answer questions like:
Who will use the machine and what are their goals while using it?
What sequence of events will a person take while operating the machine?
What are the key features and capabilities required for the machine to perform its intended function?
What are the design constraints and requirements that must be considered when designing the machine?
What are the key performance metrics that the machine must meet in order to be considered successful?
How will the machine fit into the larger context of the café, and how will it interact with other systems and components within the café?
What are the needs of others like those marketing, selling, manufacturing, or buying the machine?
At this level, the focus is on understanding the big picture of the espresso machine and its role within the café system. The answers to these questions will help guide the design and development of the machine at the logical and technology levels of abstraction.
Use Case Diagram#
First the ants work on the behavior of the system. Expand the Behavior package in the Model Browser and double-click on the diagram named Use Cases.
A use case diagram is a type of visual representation used in systems engineering to describe the functional requirements of a system, such as an espresso machine. In the context of the espresso machine, a use case diagram would be used to identify and define the different ways in which the machine will be used by its users, such as the café staff and customers.
The diagram would typically include different actors or users, such as the barista, the customer, and possibly a manager or maintenance technician. It would also include different «use cases» or scenarios, which describe the different actions that the users can take with the machine, such as placing an order, making an espresso, or cleaning the machine.
The use case diagram helps to ensure that all the necessary functional requirements of the espresso machine are identified and accounted for, and that the system is designed to meet the needs of its users. It can also be used as a communication tool between the different stakeholders involved in the development of the machine, such as the ants and Cappuccino the cat.
The ants need your help updating the diagrams, so let’s get started:
Double-click on the actor to pop up the rename dialog, and replace User with Barista.
Update the name of the oval Use Case from Use Case #1 to Brew espresso.
Update the name of the rectangle Block from Feature to Espresso Machine
A barista interacts with the espresso machine. The barista is provided a simple interface with a few push buttons.
In this particular use case diagram, we have one actor named Barista and one use case called Brew espresso, which is allocated to a block called Espresso Machine. The actor, in this case, is a cat barista who interacts with the system (an espresso machine) to accomplish a particular task, which is brewing espresso.
The use case Brew espresso represents a specific functionality or action that the system (the Espresso Machine block) can perform. It describes the steps or interactions necessary to complete the task of brewing espresso, such as selecting the appropriate settings, starting the brewing process, and stopping the process once it’s complete.
The use case diagram shows the relationship between the actor and the use case. It is represented by an oval shape with the use case name inside and an association with the actor. The association represents the interaction from the actor to the use case.
Domain Diagram#
A domain diagram is a graphical representation of the concepts, terms, and relationships within a specific domain. In the case of a coffee shop, a domain diagram could represent the key elements and relationships within the coffee shop domain.
The following is a domain diagram that builds upon the context diagram with additional blocks:
Barista
Coffee Machine
Roasted Coffee
Coffee Grinder
Water Supply
Customer
Each block represents a key concept within the coffee shop domain, and the containment relationship is used between the domain and the blocks to show that they are part of the domain.
The Barista block is responsible for preparing and serving the coffee to the customers. The Roasted Coffee block contains the types of coffee available for the barista to use. The Coffee Grinder block grinds the roasted coffee beans to the desired consistency before brewing. The Water Supply block contains the water source for the coffee machine, and finally the Customer block represents the person who orders and receives the coffee.
The ants need more of your help to rename the Feature Domain diagram and update it so that it matches the one above.
The domain diagram provides a high-level view of the coffee shop domain and the key concepts and relationships involved in it. It can be a useful tool for understanding the relationships between different elements of the domain and for communicating these relationships to others.
Context Diagram#
The context diagram is a high-level view of the system, and it shows its interaction with external entities. In the case of a coffee machine, a context diagram provides a clear and concise representation of the system and its interactions with the external environment.
The context diagram for a coffee machine shows the coffee machine as the system at the center, with all its external entities surrounding it. The external entities include the barista, the power source, the coffee grinder, and the water source.
The ants need more of your help to rename the Feature Context diagram and update it so that it matches the one above.
Overall, the context diagram for a coffee machine provides a high-level view of the system and its interactions with external entities. It is a useful tool for understanding the system and its role in the broader environment.
Concept Requirements#
Concept requirements are typically collected by analyzing the needs of the stakeholders involved in the development of the coffee machine. This involves identifying and gathering input from various stakeholders, such as the barista, the other engineers working on the product, manufacturing, and service.
To collect concept requirements, stakeholders may be asked questions about what they want the coffee machine to do, what features it should have, and what problems it should solve. They may also be asked to provide feedback on existing coffee machines to identify areas where improvements could be made.
Once the needs of the stakeholders have been gathered, they can be analyzed to identify common themes and requirements. This information can then be used to develop the concept requirements for the coffee machine, which serve as a starting point for the design process.
The following are some concept requirements for a coffee machine that addresses a water tank, heat-up time, and HMI button:
Water Tank: The coffee machine should have a water tank of sufficient size to make multiple cups of coffee before needing a refill. The water tank should be easy to access and fill.
Heat-up Time: The coffee machine should have a heat-up time of no more than 10 minutes from the time the user turns on the machine until it’s ready to brew coffee.
HMI Button: The coffee machine should have an HMI with a 1 cup brew button to make it easy for the user to select the amount of coffee they want to brew. The HMI should be intuitive and easy to use.
Help the ants update the Concept Requirements diagram with these requirements.
Throughout the design process, the concept requirements will be refined and expanded upon as more information becomes available and the needs of the stakeholders become clearer. This iterative process ensures that the final design of the coffee machine meets the needs of all stakeholders and delivers a high-quality product.
Coffee Machine: Logical Level#
Introduction#
At the logical Level, we’ll define a technology-agnostic solution. This is the middle level of abstraction, where the system is described in terms of its structure and behavior. At this level, the focus is on how the system components are organized and how they interact with each other.
Functional Boundary Behavior#
A Functional Boundary Behavior diagram is a type of SysML Activity diagram used to show the interactions between different logical blocks. The swim lanes divide the diagram into different areas, each representing a different functional block or component.
In this case, the diagram includes swimlanes for the HMI, Controller, Water Pump, Water Heater, Grouphead, and Portafilter. The HMI receives the button press from the barista and then sends a command to the Controller. The Controller then commands the Water Pump and Water Heater to start, and once the water has reached the correct temperature, the Controller commands the Pump and Heater to start. The water would then be pumped through the Grouphead and into the Portafilter, brewing the coffee. The diagram shows the flow of information and actions between the different logical blocks, and help to ensure that the behavior that each block provides is properly connected and integrated into the system.
From the Logical package, expand the Behavior package in the Model Browser and double-click on the diagram named Functional Boundary Behavior. Additional swimlanes can be added by clicking on the swimlanes and add additional partitions in the Property Editor.
In the Structure package, right-click on the Blocks with the B symbol and rename them from the context menu so that the names of the Logical Blocks in each swimlane are correct. The name of the partition before the colon can also be changed in the Property Editor.
Additional Object Flows, pins, and actions can be created using the Toolbox. The Parameter Nodes which are attached to the Activity on the very left and right of the diagram are renamed and created by clicking on the Activity and modifying them in the Property Editor.
Logical State Machine#
The logical state machine for the coffee machine is a diagram that shows the different states and transitions that the machine goes through to make coffee. In this case, there are two main states: On and Off.
When the coffee machine is turned on, it enters the On state. Inside the On state, there are some substates, starting with the heat water state. The machine will transition from the heat water state to the ready state when the temperature reaches the set point.
Once the machine is in the ready state, the user can select one or two cup mode. Depending on the mode selected, the machine will transition to either the one cup mode or two cup mode.
Open the Logical States diagram and use the Toolbox to add the additional substates and transition. Guards for the transitions, shown surrounded by brackets, are added by selecting the transition and adding the guard in the Property Editor.
The logical state machine diagram for the coffee machine shows these states, and the different conditions that trigger the transitions. This helps the ants designing the machine to understand how the coffee machine works and ensure that it functions properly.
Logical Structure#
The logical structure shows which logical blocks the espresso machine is made up of. Since we are at the logical level, these blocks should be agnostic to technical choices.
The following logical blocks are part of the espresso machine:
Water tank
Water pump
Water heater
Portafilter
Controller
Grouphead
HMI
Each block represents a key portion of the espresso machine, and the containment relationship is used between the espresso machine and its logical parts.
Water tank: The water tank is a container that stores the water used in the espresso machine. It typically has a specific capacity and is designed for easy filling and cleaning. The water tank supplies water to the water pump when needed.
Water pump: The water pump is responsible for drawing water from the water tank and creating the necessary pressure to force the water through the coffee grounds in the portafilter. It plays a crucial role in the espresso extraction process by ensuring a consistent flow of water.
Water heater: The water heater, also known as the boiler or heating element, is responsible for heating the water to the optimal temperature for brewing espresso. It maintains the water at the desired temperature to ensure proper extraction and flavor.
Portafilter: The portafilter is a detachable handle-like device that holds the coffee grounds. It is attached to the espresso machine and acts as a filter holder. The water from the pump is forced through the coffee grounds in the portafilter to extract the flavors and create the espresso.
Controller: The controller, often a microcontroller or a dedicated circuit board, is the brain of the espresso machine. It manages and coordinates the operation of various components, such as the water pump, water heater, and HMI, to ensure the correct brewing process. It monitors and controls temperature, pressure, and other parameters to maintain consistency and deliver the desired results.
Grouphead: The grouphead is a part of the espresso machine where the portafilter attaches. It provides a secure connection between the portafilter and the machine, allowing the brewed espresso to flow out of the portafilter and into the cup. The grouphead also helps to maintain proper temperature and pressure during the brewing process.
HMI (Human-Machine Interface): The HMI is the user interface of the espresso machine. It provides a means for the user to interact with the machine, usually through buttons, switches, or a touchscreen. The HMI allows the user to select different brewing options, adjust settings, and monitor the status of the machine. It provides feedback and displays information related to the brewing process, such as brewing time, temperature, and cup size selection.
We didn’t make any technical choices at this time, for example we didn’t specify which type of controller, the pump capacity, or the model of the grouphead. These details will be defined once we get to the Technology level.
The ants need more of your help to update the Logical Structure diagram so that it matches the one above.
Logical Boundary#
The Logical Boundary is a type of Internal Block Diagram that represents the internal structure of a system, illustrating the relationships between its internal components or blocks. It helps to visualize how these blocks interact and exchange information within the system. The term boundary used here means a clear box view inside the espresso machine at the logical boundary. It uses part properties of the blocks that were in the Logical Structure diagram above.
The interactions between the part properties inside the espresso machine are shown as ItemFlows on the Connectors.
Water: Represents the flow of water from the water tank to the water pump.
On/Off: Represents the command or signal to turn the espresso machine on or off.
Volume Adjustment: Represents the user-selected volume adjustment for the coffee output.
Pressurized Water: Represents the water flow under pressure for extracting coffee.
Heat Command: Represents the command or signal to activate the water heater and initiate the heating process.
Temperature: Represents the feedback signal indicating the current temperature of the water.
Hot Pressurized Water: Represents the pressurized hot water for brewing coffee.
Coffee Water Mixture: Represents the mixture of hot water and coffee grounds during the brewing process.
Atención
Notice that we aren’t actually showing anything entering or leaving the boundary of the espresso machine, like the input from the barista or the resulting coffee. Gaphor doesn’t current support adding ports to the boundary of an internal block diagram, but hopefully we’ll be able to add support soon!
These item flows capture the essential interactions and exchanges within the espresso machine. They represent the flow of water, control signals, temperature feedback, and the resulting coffee water mixture. The item flows illustrate the sequence and connections between the various components, allowing for a better understanding of how the machine functions as a whole.
Once again, help the ants by updating the Logical Boundary diagram so that it matches the one above.
Logical Requirements#
Logical requirements refer to the high-level specifications and functionalities that describe what a system or product should accomplish without specifying how it will be implemented. These requirements focus on the desired outcomes and behavior of the system rather than the specific technical details.
We have also already defined the behavior and the structure of the espresso machine at the logical level, so the main task now is to translate that information in to words as requirement statements.
Truco
If you need help writing good requirements, the INCOSE Guide to Needs and Requirements and the Easy Approach to Requirements Syntax are recommended resources.
We use the Derive Requirement relation from the Logical Requirement to the Concept Requirements that we previously created. The direction of this relationship is in the derived from direction, which might be opposite to what you are used to where the higher level requirement points to the lower level requirement.
Here we derive two requirements:
Controller commands heatup
900kPa of water pressure
Update the Logical Requirements diagram with these requirements. If you want, you can also develop additional requirements for all the logical behavior and structure that we specified in the other diagrams.
Coffee Machine: Summary#
The Technology Level design uses a very similar approach as the Logical Level. Work on the behavior, structure, and then the requirements. At this level, you will now specify all the design details for how this specific espresso machine will work. We’ll leave this exercise up to you to do, and we would be glad to have contributions of this design back in to this tutorial if you are interested in getting involved in Gaphor.
As they worked, the ants encountered numerous challenges. They had to ensure that the machine was safe, efficient, and easy to use, all while meeting the unique needs of their feline client. But with their deep understanding of systems engineering and their commitment to key principles and concepts, they were able to overcome these challenges and design an exceptional espresso machine.
In the end, Cappuccino was thrilled with the machine, which worked flawlessly and was a big hit with his customers. He was so impressed with the ants” work that he offered them a long-term contract to design all of his café’s systems. The ants were proud of their success, knowing that it was all thanks to their expertise and deep understanding of systems engineering principles. They had proven that, with the right tools and approach, anything is possible.
Change Log#
This is a curated list of the changes per version.
Nota
The latest version may not have been released yet.
2.19.1#
(unreleased)
2.19.0#
Dropped support for AppImage
Add Information Flow support for Associations
Interactions: fixed DnD for partially connected messages
Restore CSS auto-complete
Docs: A coffee machine tutorial has been added
Make model loading more lenient to model corruption
CLI: export diagrams and run scripts within Gaphor
Enable PyPI Trusted Publisher
Replace deprecated Gtk.TreeView with ListView: Activity Parameter Nodes
Use consistent naming for element_factory in storage module
Use new style Dropdowns for selecting items in property editor
Updates to translations
2.18.1#
Make operations visible on Blocks
A quick fix for crashes in the CSS editor, disable autocomplete
Fix doc translation catalogs not found
Fix encoding warnings for no encoding argument
Update AppImage build with GTK 4.10
Add non-goals to README
Enable translation of docs, and add Crotian, German, and Dutch
Updates to most translations and add Tamil
2.18.0#
Support for manually resolving Git merge conflicts
Drop support for GTK3, bundle macOS with GTK4
Enable middle-click mouse scrolling of diagrams
Support for changing the spoken language in a model
Add diagrams in diagrams
Upgrade development build to GNOME 44
Clean up application architecture for copy service
Css editor dark mode
macOS: update notarize, staple, and cert actions
Just load modules for gaphor.modules entry points
Finnish, Dutch, Spanish, Polish, Portuguese (BRA) translation update
Toggle the «no tabs» background based on notebook activity
Fix drag from model browser
Fix orthogonal lines during copy/paste
Update diagram directly when partitions change
Make main window always available to avoid warnings
2.17.0#
Add support for diagram metadata
macOS: Fix freeze creating new diagram
Properly unsubscribe when property page is removed
Package GSettings daemon schemas for AppImage
Consider only default modifiers in toolbox shortcuts
New status page icon
Workaround removing skip-changelog labels
Update gvsbuild to version 2023.2.0
meta: Add .doap-file
Update «Keep model in sync» design principle
Update to using the GNOME Code of Conduct
Add Polish translation
Spanish, Dutch, Croatian, Turkish, and German Translation Updates
2.16.0#
Automatic switching to dark mode in diagrams
Add Model browser multi select and popup menu
Refactor and improve model browser
Use normal + icon for new diagram dropdown
Add support for CSS variables and named colors
Apply development mode for dev releases
Show diagram name in header
Show something when no diagrams are opened
Fix the packaged data dirs
Stabilize macOS/GTK tests
Add a comments option to our documentation
Split tips in to multiple labels
Win and macOS: Fix wrong language selected when region not default
Fix translation warning never logged with missing mo files
Spanish, Russian, Hungarian, Czech translation update
2.15.0#
Add basic git merge conflict support by asking which model to load
Improvements to CSS autocomplete with function completion
Insert colons, spaces, and () automatically for CSS autocomplete
Use native file chooser in Windows
Fix translations not loading in Windows, macOS, and AppImage
Fix PyInstaller versionfile parse error with pre-release versions
Update CI to publish to PyPI after all other jobs have passed
Replace pytest-mock with monkeypatch for tests
Fix PEP597 encoding warnings
Fix regression that caused line handles to not snap to elements
Add Turkish, and update French, Russian, and Swedish translations
Remove translation Makefile
2.14.2#
Fix macOS release failed
2.14.1#
Add autocompletion for CSS properties
Fix coredumps on Flatpak
Hide New Package menu unless package selected
Update Getting Started pages
Spanish translation update
2.14.0#
Simplify the greeter and provide more info to new users
New element handle and toolbox styles
Use system fonts by default for diagrams
Add tooltips to the application header icons
Make sequence diagram messages horizontal by default
Make keyboard shortcuts more standard especially on macOS
macOS: cursor shortcuts for text entry widgets
Load template as part of CI self-test
Update docs to make it more clear how to edit CSS
Switch doc style to Furo
Add custom style sheet language
Support non-standard Sphinx directory structures
Continue to make model loading and saving more reliable
Move Control Flow line style to CSS
Do not auto-layout sequence diagrams
Use new actions/cache/(save|restore)
Remove querymixin from modeling lists
Improve Windows build reliability by limiting cores to 2
Croatian, Hungarian, Czech, Swedish, and Finnish translation updates
2.13.0#
Auto-layout for diagrams
Relations to actors can connect below actor name
Export to EPS
Zoom with Ctrl+scroll wheel works again
Recent files is disabled if none are present
Windows and AppImage are upgraded to GTK4
Update packaging to use Python 3.11
Many GTK4 improvements: About window, diagram tabs, message dialogs
Ensure toolbox is always visible
Add additional tests around architectural rules
Many translation updates and bug fixes
2.12.1#
Fix/move connected handle
Fix error when disconnecting line with multiple segments
Fail CI build if Windows certificate signing fails
namespace.py: Actually set properties for rectangle
Update Shortcuts window
2.12.0#
GTK4 is now the default for Flatpak; Windows, macOS, and AppImage still use GTK3
Save folder is remembered across save actions
State machine functionality has been expanded, including support for regions
Resize of partition keeps actions in the same swimlane
Activities (behaviors) can be assigned to classifiers
Stereotypes can be inherited from other stereotypes
Many GTK4 fixes: rename, search, instant editors
Many translation updates
2.11.0#
Add Copy/Paste for GTK4
Make dialogs work with GTK4
Fix instant editors for GTK4
Update list view for GTK4
Make SysML Enumerations also ValueTypes
Add union types
Let Gaphor check for its own health
Add error reports window
Add element to diagram by double click
Ensure all models are saved with UTF-8 encoding
Fix states can’t transition to themselves
Fix unlinking elements from the model
Fix issue with fully pasting a diagram
Fix scroll speed for touch screens
Fix codeql warnings and error
Improve text placement for Associations
Enable additional pre-commit hooks
Add example in docs of color for comments using CSS
Hungarian translation updates
2.10.0#
Pin support for activity diagram
Add Activity item to diagram
Allow to drag and drop all elements from tree view to diagram
Codegen use all defined modeling languages
Fix diagram dependency cycle
Add Skip Duplicate Action and Release-Drafter Permissions
Update permissions for CodeQL GitHub Action
Include all diagram items in test model
Fix GTK4 property page layouts
Use official RAAML logo in greeter
Relation metadata to allow better reuse
Rename relationship connector base classes
Add design principles to docs
French, Finnish, Croatian translation update
2.9.2#
Fix Windows build
2.9.1#
Fix bad release of version 2.9.0
Cleanup try except blocks and add more f-strings
2.9.0#
Separate Control and Object Flow
Automatically select dark mode for macOS and Windows
Automatically Enable Rename Prompt for Newly Created Diagrams
New group function for element grouping
Simulate user behavior with Hypothesis and fix uncovered bugs
Proxyport: update ports when proxyport is moved
Fix AppImage Crashes on Save Command
Improve reconnect for relationships
Update connection behavior for Association
Enable preferences shortcut
Rename Component Toolbox to Deployment
Update Finnish, Spanish, Croation, and German translatio
2.8.2#
Fix splitting of lines
Update README to reflect new functionality
Add additional strings to translations
Update Hungarian, Spanish, and Finnish translations
2.8.1#
Fix Gaphor fails to load when launched in German
Simplify the greeter dialogs
Update Hungarian, Finnish, and Chinese (Simplified) translations
2.8.0#
Add diagram type support
Improve the welcoming experience with a greeter window and starting templates
Add a Magnet-tool
Support SysML Item flow
Stereotypes for ItemFlow properties
Full Copy/Paste of model elements
Allow for deleting elements in the tree view
Allocation of structural types to swimlane partitions
User notification when model elements are automatically removed
Store toolbox settings per modeling language
Grow item when an item is dropped on it
Add «values» compartment to Block item and set a minimal height for compartments
Support empty square bracket notation in an Operation
New code generator
Fix AppImage GLIBC Error on Older Distro Versions
Fix Sequence diagram loading when message is close to lifeline body
Support for loading .gaphor files directly from the macOS Finder
Fix positions of nested items during undo
Fix ownership of Connector, ProxyPort, and ItemFlow
Improve GTK4 compatibility
Improve clarity of syntax for attributes and operations using a popover
Clean up Toolbox and remove some legacy code
Invert association creation
Ensure model consistency on save and fork node loading fixes
Core as a separate ModelingLanguage
Use symbolic close icon for notebook tabs
Update to latest gvsbuild, switch to wingtk repo
Spanish, Hungarian, Finnish, Dutch, Portuguese, Croation, Espanian, and Galician translations updates
Add Chinese (Simplified) translation
2.7.1#
Fix lines don’t disconnect when moved
No GTK required anymore for generating docs
Update Python to 3.10.0
Spanish translation updates
2.7.0#
Add Reflexive Message item for Interactions
Allow messages to move freely on Lifeline and ExecutionSpec
Pop-up element name editor on creation of a new element
Add option to show underlying DecisionNode type
Add InformationFlow for Connectors
Swap relationship direction for Generalization, Dependency, Import, Include, and Extend
Use Jedi for autocomplete in the Python Console
Sphinx directive for embedding Gaphor models into docs
Fix lifeline ordering when not all items are linked in a diagram
Allow generalizations to be reused
Allow auto-generated elements (Activity, State Machine, Interaction, Region) to be removed
Fix Windows build by updating to Python 3.9.9
Emit events for Diagram.ownedPresentation and Presentation.diagram after element creation
Show underlying DecisionNode type
Add documentation dependencies to pyproject.toml
Move enumeration layout to UML.classes
Rename packaging to _packaging
Remove names for initial/final nodes
Update to latest gvsbuild
Update to PyInstaller 4.6
Add gtksourceview to Windows docs
Fix Python 3.10 warnings
Fix indentation in Style Sheet docs
Expand the number of strings translated
Hungarian, Spanish, Japanese, Finnish, and Croatian translation updates
2.6.5#
Update style sheet editor to be a code editor
Update strings to improve ability to translate
Ensure all relationships are brought to top
Fix errors in Italian translation which prevented model saving
Add association end properties to editor pane
Restore rename right click option to diagrams in tree view
Add Japanese translation
Update Hungarian, Croatian, and Spanish translations
2.6.4#
Fix Flatpak build failure by reverting to previous dependencies
2.6.3#
Fix about dialog logo
Add translation of more elements
Remove importlib_metadata dependency
Simpler services for about dialog
Up typing compliance to 3.9, and remove typing_extensions
Finnish translation updates
2.6.2#
Fix localization of UI files
Fix icons in dark mode
Update Spanish, Finnish, Hugarian, and Portuguese (Br) translations
2.6.1#
Display guard conditions in square brackets
Use flat buttons in the header bar
Fix translation support
Fix drag and drop of elements does not work on diagrams
Fix parameter is incorrect error with «;;» in path
Fix fork/join node incorrectly rotates
Fix close button on about dialog doesn’t work in Windows
Fix wrong label is displayed when object node ordering is enabled
Improve inline editor undo/redo behavior
Fixed closing of about dialog
Add VSCode debug instructions for Windows
Rename usage of Partitions to Swimlanes
Update Dutch and Hungarian Translations
Croatian translation updates
Simplify attribute and enumeration lookup
2.6.0#
Improve zoom and pan for mouse
Add Finnish, Galician, Hungarian, and Korean, update Spanish translations
Fix disappearing elements from tree view on Windows
Convert CI from mingw to gvsbuild
Upgrade Windows Build Script from Bash to Python
Refactor GitHub Actions to use composite actions
Add translations for UI files
Add information flows to UML model
Add extra rules to avoid cyclic references
Fix typo in UML.gaphor
Refactor class property pages in to multiple modules
Fix Windows and other developer documentation updates
Enable pyupgrade
Update the README for Flatpak string translation
Fix documentation build errors, update dependencies
2.5.1#
Fix app release signing in Windows and macOS
2.5.0#
Add initial support for STPA in RAAML
Add support for notes in property pages and attributes
Allow for diagrams to be nested under all elements
Fix delete and undo of a diagram
Rename C4ContainerDatabaseItem to C4DatabaseItem
Cleanup model loading
Change diagram item management to the element factory
Organize and simplify element events
Cleanup toolbox and diagram action code
2.4.2#
Fix AttributeError when creating composite associations
Add tooltips for A and S in attribute editor
Improve drag and drop for TreeView
Started to add support for GTK4
Upload Linux assets during release automatically
Sign only builds on the master branch
2.4.1#
Fix reordering attributes and operations with drag and drop
2.4.0#
Add support for DataType, ValueType, Primitive, and Enumeration
Model state is stored per model, restores where you left off
Add support for Containment Relationship
Focus already opened model when opening a model file
Remove the New From Template option
Upgrade toolbox to be compatible with GTK 4
Add regression tests
Fix build fails when GitHub Actions secrets are not available
Fix association direction arrow is not updated
2.3.2#
Fix issue where ornaments were not show on associations after loading a model
2.3.1#
Fix scrollbars cause the diagram to disappear
Update Italian translation
Left align the toolbox header labels
2.3.0#
Add support for C4 model
Add support for Fault Tree Analysis with RAAML
Update the UML data model to align closer to version 2.5.1
Enable arrow keys to expand and collapse namespace tree
Allow Gaphor profiles to be copy and pasted between models
Improve diagram drawing and scrolling speed
Add Croatian translation
Remove gray borders around editable text
Complete converting all tests to pytest
Fix guides are misaligned when top-left handle is moved
Update development environment instructions
Fix undo and redo does not set attributes
Fix selection lasso is in the wrong place after scrolling
2.2.2#
Fix undo of deleted elements
Fix requirements are missing ID and text
Add CSS styling to dropzone and grayed out elements
Start to remove use of inline styles
2.2.1#
Fix drawing of composite association
2.2.0#
Guide users to create valid relationships
macOS builds are signed and notarized
New app icon
Improvements to copy and paste, and undo robustness
Fix RuntimeError caused by style sheet creation
Use EventControllers from GTK 3.24
2.1.1#
Fix copy and paste in Linux with Wayland
2.1.0#
Improve swimlane behavior
Add auto select in tree view
Add in-app notifications
Improve file load and save dialogs
Show more elements and relationships in namespace tree
Update Italian translation
Make lifelines and messages owned by interactions
2.0.1#
Fix Gaphor fails to launch in macOS
Use certificate to sign Windows binaries
Fix copy/paste issue that causes association ends to be removed
Improve editing for inline editors (popovers)
Fix undo on diagram items corrupts the model
Fix UML composite and shared association tools
2.0.0#
Add initial support for SysML
Add support for styling using CSS
Translate to Italian
Improve dmg for macOS
Improve Copy/Paste for nested items
Add new modeling language service
Show the element editor by default
Create completely new data model code generator
Add part and shared associations to tool palette
Remove unused imports, enable flake8 checks
Update App icons
Update animation gif in README
Fix Windows Build Errors caused by Missing ZST Archives
Fix installation on Windows
Add extra diagram item tests
Fix macOS Python version problem
Place UML model and diagram items closer together
Refactor Code Generator to New Module and add CLI
Fix MSYS2 package names and disable system update
Remove CI workaround for console plugin
Move core modeling concepts to a separate package
Convert Some Profile Tests to Pytest
Speed up text rendering
Fix tree view text to allow names with angle brackets
Clear the clipboard when diagram items are copied
Fix name change for activity partitions
Style Sheets#
Since Gaphor 2.0, diagrams can have a different look by means of style sheets. Style sheets use the Cascading Style Sheets (CSS) syntax. CSS is used to describe the presentation of a document written in a markup language, and is most commonly used with HTML for web pages.
On the W3C CSS home page, CSS is described as:
Cascading Style Sheets (CSS) is a simple mechanism for adding style (e.g., fonts, colors, spacing) to Web documents.
Its application goes well beyond web documents, though. Gaphor uses CSS to provide style elements to items in diagrams. CSS allows us, users of Gaphor, to change the visual appearance of our diagrams. Color and line styles can be changed to make it easier to read the diagrams.
Since we’re dealing with a diagram, and not a HTML document, some CSS features have been left out.
The style is part of the model, so everyone working on a model will have the same style. To edit the style press the tools page button at the top right corner in gaphor:
Here is a simple example of how to change the background color of a class:
class {
background-color: beige;
}
Or change the color of a component, only when it’s nested in a node:
node component {
background-color: skyblue;
}
The diagram itself is also expressed as a CSS node. It’s pretty easy to define a «dark» style:
diagram {
background-color: #343131;
}
* {
color: white;
text-color: white;
}
Here you already see the first custom attribute: text-color
. This property
allows you to control the color of the text drawn in an item. color
is used
for the lines (strokes) that make the layout of a diagram item.
Supported selectors#
Since we are dealing with diagrams and models, we do not need all the features of CSS. Below you’ll find a summary of all CSS features supported by Gaphor.
|
All items on the diagram, including the diagram itself. |
|
Any component item which is a descendant of a node. |
|
A component item which is a child of a node. |
|
A generalization item with a subject present. |
|
A class with name «Foo». |
|
A diagram with a name starting with «draft». |
|
A diagram with a name ends with «draft». |
|
A diagram with a name containing the text «draft». |
|
A diagram with a name of «draft» or «item». |
|
A diagram with a name is «draft» or starts with «draft-«. |
|
The focused item. Other pseudo classes are:
|
|
A node containing no child nodes in the diagram. |
|
An item is at the top level of the diagram. This is only applicable for the diagram |
|
The item contains any of the provided selectors. E.g. |
|
Match any of the provided selectors. E.g. |
|
Negate the selector. E.g. |
The official specification of CSS3 attribute selectors.
Gaphor provides the
|=
attribute selector for the sake of completeness. It’s probably not very useful in this context, though.Please note that Gaphor CSS does not support IDs for diagram items, so the CSS syntax for IDs (
#some-id
) is not used. Also, class syntax (.some-class
) is not supported currently.
Style properties#
Gaphor supports a subset of CSS properties and some Gaphor specific properties.
The style sheet interpreter is relatively straight forward. All
widths, heights, and sizes are measured in pixels. You can’t use complex style
declarations, like the font
property in HTML/CSS which can contain font
family, size, weight.
Colors#
|
Examples:
|
|
Color used for lines. |
|
Color for text. |
|
Color opacity factor ( |
A color can be any CSS3 color code, as described in the CSS documentation. Gaphor supports all color notations:
rgb()
,rgba()
,hsl()
,hsla()
, Hex code (#ffffff
) and color names.
Text and fonts#
|
A single font name (e.g. |
|
An absolute size (e.g. |
|
Either |
|
Either |
|
Either |
|
Either |
|
Vertical alignment for text. Either |
|
Set vertical spacing for icon-like items (actors, start state). Example: |
font-family
can be only one font name, not a list of (fallback) names, as is used for HTML.font-size
can be a number or CSS absolute-size values. Only the valuesx-small
,small
,medium
,large
andx-large
are supported.
Drawing and spacing#
|
Radius for rectangles: |
|
Style for dashed lines: |
|
Content alignment for boxes. Either |
|
Either |
|
Set the width for lines: |
|
Set minimal height for an item: |
|
Set minimal width for an item: |
|
CSS style padding (top, right, bottom, left). Example: |
padding
is defined by integers in the range of 1 to 4. No unit (px, pt, em) needs to be used. All values are in pixel distance.dash-style
is a list of numbers (line, gap, line, gap, …)line-style
only has an effect when defined on adiagram
. A sloppiness factor can be provided in the range of -2 to 2.
Diagram styles#
Only a few properties can be defined on a diagram, namely background-color
and line-style
. You define the diagram style separately from the diagram item
styles. That way it’s possible to set the background color for diagrams
specifically. The line style can be the normal straight lines, or a more
playful «sloppy» style. For the sloppy style an optional wobliness factor can
be provided to set the level of line wobbliness. 0.5 is default, 0.0 is a
straight line. The value should be between -2.0 and 2.0. Values between 0.0 and
0.5 make for a subtle effect.
Gaphor supports dark and light mode since 2.16.0. Dark and light color schemes are exclusively used
for on-screen editing. When exporting images, only the default color scheme is applied.
Color schemes can be defined with @media
queries. The official prefers-color-scheme = dark
query is supported,
as well as a more convenient dark-mode
.
/* The background you see in exported diagrams: */
diagram {
background-color: transparent;
}
/* Use a slightly grey background in the editor: */
@media light-mode {
diagram {
background-color: #e1e1e1;
}
}
/* And anthracite a slightly grey background in the editor: */
@media dark-mode {
diagram {
background-color: #393D47;
}
}
Variables#
Since Gaphor 2.16.0 you can use CSS variables in your style sheets.
This allows you to define often used values in a more generic way. Think of things like line dash style and colors.
The var()
function has some limitations:
Values can’t have a default value.
Variables can’t have a variable as their value.
Example:
diagram {
--bg-color: whitesmoke;
background-color: var(--bg-color);
}
diagram[diagramType=sd] {
--bg-color: rgb(200, 200, 255);
}
All diagrams have a white background. Sequence diagrams get a blue-ish background.
Working with model elements#
Gaphor has many model elements. How can you find out which item should be styled?
Gaphor only styles the elements that are in the model, so you should be explicit
on their names. For example: Component
inherits from Class
in the UML model,
but changing a color for Class
does not change it for Component
.
If you hover over a button the toolbox (bottom-left section), a popup will appear
with the item’s name and a shortcut. As a general rule, you can use the component
name, glued together as the name in the stylesheet.
A Component can be addressed as component
, Use Case as
usecase
. The name matching is case insensitive.
CSS names are written in lower case by default.
However, since the CSS element names are derived from names used within Gaphor, there are a few exceptions.
Profile |
Group |
Element |
CSS element |
---|---|---|---|
* |
* |
element name |
element name without spaces E.g. |
UML |
Classes |
all Association’s |
|
UML |
Components |
Device/Node |
|
UML |
Actions |
Decision/Merge Node |
|
UML |
Actions |
Fork/Join Node |
|
UML |
Actions |
Swimlane |
|
UML |
Interactions |
Reflexive message |
|
UML |
States |
Initial Pseudostate |
|
UML |
States |
History Pseudostate |
|
UML |
Profiles |
Metaclass |
|
C4 Model |
C4 Model |
Person |
|
C4 Model |
C4 Model |
Software System |
|
C4 Model |
C4 Model |
Component |
|
C4 Model |
C4 Model |
Container |
|
C4 Model |
C4 Model |
Container: Database |
|
SysML |
Blocks |
ValueType |
|
SysML |
Blocks |
Primitive |
|
SysML |
Requirements |
Derive Requirement |
|
RAAML |
FTA |
any AND/OR/… Gate |
|
Ideas#
Here are some ideas that go just beyond changing a color or a font. With the following examples we dig in to Gaphor’s model structure to reveal more information to the users.
To create your own expression you may want to use the Console ( → Tools → Console). Drop us a line on
Gitter and we would be happy to help you.
The drafts package#
All diagrams in the package «Drafts» should be drawn using sloppy lines:
diagram[owner.name=drafts] {
line-style: sloppy 0.3;
}
diagram[owner.name=drafts] * {
font-family: Purisa; /* Or use some other font that's installed on your system */
}
Unconnected relationships#
All items on a diagram that are not backed by a model element, should be drawn in a dark red color. This can be used to spot not-so-well connected relationships, such as Generalization, Implementation, and Dependency. These items will only be backed by a model element once you connect both line ends. This rule will exclude simple elements, like lines and boxes, which will never have a backing model element.
:not([subject], :is(line, box, ellipse, commentline)) {
color: firebrick;
}
Solid Control Flow lines#
In Gaphor, Control Flow lines follow the SysML styling: dashed. If you want, or need to strictly follow the official UML specifications, you can simply make those solid lines.
controlflow {
dash-style: 0;
}
Todo note highlight#
All comments beginning with the phrase «todo» can be highlighted in a different user-specific colour. This can be used to make yourself aware that you have to do some additional work to finalize the diagram.
comment[body^="TODO"] {
background-color: skyblue;
}
Sphinx Extension#
What’s more awesome than to use Gaphor diagrams directly in your Sphinx documentation. Whether you write your docs in reStructured Text or Markdown, we’ve got you covered.
Truco
Here we cover the reStructured Text syntax. If you prefer markdown, we suggest you have a look at the MyST-parser, as it supports Sphinx directives.
It requires minimal effort to set up. Adding a diagram is as simple as:
.. diagram:: main
In case you use multiple Gaphor source files, you need to define a :model:
attribute
and add the model names to the Sphinx configuration file (conf.py
).
.. diagram:: main
:model: example
Diagrams can be referenced by their name, or by their fully qualified name.
.. diagram:: New model.main
Image properties can also be applied:
.. diagram:: main
:width: 50%
:align: right
:alt: A description suitable for an example
Configuration#
To add Gaphor diagram support to Sphinx, make sure Gaphor is listed as a dependency.
Importante
Gaphor requires at least Python 3.9.
Secondly, add the following to your conf.py
file:
Step 1: Add gaphor as extension.
extensions = [
"gaphor.extensions.sphinx",
]
Step 2: Add references to models
# A single model
gaphor_models = "../examples/sequence-diagram.gaphor"
# Or multiple models
gaphor_models = {
"connect": "connect.gaphor",
"example": "../examples/sequence-diagram.gaphor"
}
Now include diagram
directives in your documents.
Read the Docs#
The diagram directive plays nice with Read the docs.
To make diagrams render, it’s best to use a .readthedocs.yaml file in your project.
Make sure to include the extra apt_packages
as shown below.
This is the .readthedocs.yaml
file we use for Gaphor:
version: 2
formats: all
build:
os: ubuntu-22.04
tools:
python: "3.11"
apt_packages:
- libgirepository1.0-dev
- gir1.2-pango-1.0
- graphviz
sphinx:
configuration: docs/conf.py
fail_on_warning: true
python:
install:
- method: pip
path: .
extra_requirements:
- docs
libgirepository1.0-dev
is required to build PyGObject.gir1.2-pango-1.0
is required for text rendering.
Nota
For Gaphor 2.7.0, gir1.2-gtk-3.0
and gir1.2-gtksource-4
are required apt_packages
, although we do not use the GUI.
From Gaphor 2.7.1 onwards all you need is GI-repository and Pango.
Errors#
Errors are shown on the console when the documentation is built and in the document.
An error will appear in the documentation. Something like this:
Error
No diagram ‘Wrong name’ in model ‘example’ (../examples/sequence-diagram.gaphor).
Jupyter and Scripting#
One way to work with models is through the GUI. However, you may also be interested in getting more out of your models by interacting with them through Python scripts and Jupyter notebooks.
You can use scripts to:
Explore the model, check for (in)valid conditions.
Generate code, as is done for Gaphor’s data model.
Update a model from another source, like a CSV file.
Since Gaphor is written in Python, it also functions as a library.
Getting started#
To get started, you’ll need a Python console. You can use the interactive console in Gaphor, use a Jupyter notebook, although that will require setting up a Python development environment.
Query a model#
The first step is to load a model. For this you’ll need an ElementFactory
. The
ElementFactory
is responsible to creating and maintaining the model. It acts
as a repository for the model while you’re working on it.
from gaphor.core.modeling import ElementFactory
element_factory = ElementFactory()
The module gaphor.storage
contains everything to load and save models. Gaphor
supports multiple modeling languages. The
ModelingLanguageService
consolidates those languages and makes it easy for the
loader logic to find the appropriate classes.
Nota
In versions before 2.13, an EventManager
is required. In later versions, the
ModelingLanguageService
can be initialized without event manager.
from gaphor.core.eventmanager import EventManager
from gaphor.services.modelinglanguage import ModelingLanguageService
from gaphor.storage import storage
event_manager = EventManager()
modeling_language = ModelingLanguageService(event_manager=event_manager)
with open("../models/Core.gaphor") as file_obj:
storage.load(
file_obj,
element_factory,
modeling_language,
)
At this point the model is loaded in the element_factory
and can be queried.
Nota
A modeling language consists of the model elements, and diagram items. Graphical components are loaded separately. For the most basic manupilations, GTK (the GUI toolkit we use) is not required, but you may run into situations where Gaphor tries to load the GTK library.
One trick to avoid this (when generating Sphinx docs at least) is to use autodoc’s mock function to mock out the GTK and GDK libraries. However, Pango needs to be installed for text rendering.
A simple query only tells you what elements are in the model. The method
ElementFactory.select()
returns an iterator. Sometimes it’s easier to obtain a
list directly. For those cases you can use ElementFatory.lselect()
. Here we
select the last five elements:
for element in element_factory.lselect()[:5]:
print(element)
<gaphor.UML.uml.Package element 3867dda4-7a95-11ea-a112-7f953848cf85>
<gaphor.core.modeling.diagram.Diagram element 3867dda5-7a95-11ea-a112-7f953848cf85>
<gaphor.UML.classes.klass.ClassItem element 4cda498f-7a95-11ea-a112-7f953848cf85>
<gaphor.UML.classes.klass.ClassItem element 5cdae47f-7a95-11ea-a112-7f953848cf85>
<gaphor.UML.classes.klass.ClassItem element 639b48d1-7a95-11ea-a112-7f953848cf85>
Elements can also be queried by type and with a predicate function:
from gaphor import UML
for element in element_factory.select(UML.Class):
print(element.name)
Element
Diagram
Presentation
Comment
StyleSheet
Property
Tagged
ElementChange
ValueChange
RefChange
PendingChange
ChangeKind
for diagram in element_factory.select(
lambda e: isinstance(e, UML.Class) and e.name == "Diagram"
):
print(diagram)
<gaphor.UML.uml.Class element 5cdae47e-7a95-11ea-a112-7f953848cf85>
Now, let’s say we want to do some simple (pseudo-)code generation. We can iterate class attributes and write some output.
diagram: UML.Class
def qname(element):
return ".".join(element.qualifiedName)
diagram = next(element_factory.select(lambda e: isinstance(e, UML.Class) and e.name == "Diagram"))
print(f"class {diagram.name}({', '.join(qname(g) for g in diagram.general)}):")
for attribute in diagram.attribute:
if attribute.typeValue:
# Simple attribute
print(f" {attribute.name}: {attribute.typeValue}")
elif attribute.type:
# Association
print(f" {attribute.name}: {qname(attribute.type)}")
class Diagram(Core.Element):
diagramType: String
name: String
qualifiedName: String
element: Core.Element
ownedPresentation: Core.Presentation
To find out which relations can be queried, have a look at the modeling language documentation. Gaphor’s data models have been built using the UML language.
You can find out more about a model property by printing it.
print(UML.Class.ownedAttribute)
<association ownedAttribute: Property[0..*] <>-> class_>
In this case it tells us that the type of UML.Class.ownedAttribute
is
UML.Property
. UML.Property.class_
is set to the owner class when
ownedAttribute
is set. It is a bidirectional relation.
Draw a diagram#
Another nice feature is drawing the diagrams. At this moment this requires a
function. This behavior is similar to the diagram
directive.
from gaphor.core.modeling import Diagram
from gaphor.extensions.ipython import draw
d = next(element_factory.select(Diagram))
draw(d, format="svg")
Create a diagram#
(Requires Gaphor 2.13)
Now let’s make something a little more fancy. We still have the core model loaded in the element factory. From this model we can create a custom diagram. With a little help of the auto-layout service, we can make it a readable diagram.
To create the diagram, we drop
elements on the
diagram. Items on a diagram represent an element in the model. We’ll also drop
all associations on the model. Only if both ends can connect, the association
will be added.
from gaphor.diagram.drop import drop
from gaphor.extensions.ipython import auto_layout
temp_diagram = element_factory.create(Diagram)
for name in ["Presentation", "Diagram", "Element"]:
element = next(element_factory.select(
lambda e: isinstance(e, UML.Class) and e.name == name
))
drop(element, temp_diagram, x=0, y=0)
# Drop all assocations, see what sticks
for association in element_factory.lselect(UML.Association):
drop(association, temp_diagram, x=0, y=0)
auto_layout(temp_diagram)
draw(temp_diagram, format="svg")
The diagram is not perfect, but you get the picture.
Update a model#
Updating a model always starts with the element factory: that’s where elements are created.
To create a UML Class instance, you can:
my_class = element_factory.create(UML.Class)
my_class.name = "MyClass"
To give it an attribute, create an attribute type (UML.Property
) and then
assign the attribute values.
my_attr = element_factory.create(UML.Property)
my_attr.name = "my_attr"
my_attr.typeValue = "string"
my_class.ownedAttribute = my_attr
Adding it to the diagram looks like this:
my_diagram = element_factory.create(Diagram)
drop(my_class, my_diagram, x=0, y=0)
draw(my_diagram, format="svg")
If you save the model, your changes are persisted:
with open("../my-model.gaphor", "w") as out:
storage.save(out, element_factory)
What else#
What else is there to know…
Gaphor supports derived associations. For example,
element.owner
points to the owner element. For an attribute that would be its containing class.All data models are described in the
Modeling Languages
section of the docs.If you use Gaphor’s Console, you’ll need to apply all changes in a transaction, or they will result in an error.
If you want a comprehensive example of a code generator, have a look at Gaphor’s
coder
module. This module is used to generate the code for the data models used by Gaphor.This page is rendered with MyST-NB. It’s actually a Jupyter Notebook!
Examples#
Here is another example:
Ejemplo: Servicios de Gaphor#
En este ejemplo estamos haciendo algo un poco menos trivial. En Gaphor, los servicios se definen como puntos de entrada. Cada servicio es una clase, y toma parámetros con nombres que coinciden con otros servicios. Esto permite que los servicios dependan de otros servicios.
Es algo parecido a esto:
# entry point name: my_service
class MyService:
...
# entry point name: my_other_service
class MyOtherService:
def __init__(self, my_service):
...
Carguemos primero los puntos de entrada.
from gaphor.entrypoint import load_entry_points
entry_points = load_entry_points("gaphor.services")
entry_points
/home/docs/checkouts/readthedocs.org/user_builds/gaphor-es/envs/latest/lib/python3.11/site-packages/gaphor/diagram/text.py:6: PyGIWarning: Pango was imported without specifying a version first. Use gi.require_version('Pango', '1.0') before import to ensure that the right version gets loaded.
from gi.repository import Pango, PangoCairo
/home/docs/checkouts/readthedocs.org/user_builds/gaphor-es/envs/latest/lib/python3.11/site-packages/gaphor/diagram/text.py:6: PyGIWarning: PangoCairo was imported without specifying a version first. Use gi.require_version('PangoCairo', '1.0') before import to ensure that the right version gets loaded.
from gi.repository import Pango, PangoCairo
{'auto_layout': gaphor.plugins.autolayout.pydot.AutoLayoutService,
'component_registry': gaphor.services.componentregistry.ComponentRegistry,
'console_window': gaphor.plugins.console.consolewindow.ConsoleWindow,
'copy': gaphor.ui.copyservice.CopyService,
'diagram_export': gaphor.plugins.diagramexport.DiagramExport,
'diagrams': gaphor.ui.diagrams.Diagrams,
'element_dispatcher': gaphor.core.modeling.elementdispatcher.ElementDispatcher,
'element_editor': gaphor.ui.elementeditor.ElementEditor,
'element_factory': gaphor.core.modeling.elementfactory.ElementFactory,
'event_manager': gaphor.core.eventmanager.EventManager,
'export_menu': gaphor.ui.menufragment.MenuFragment,
'file_manager': gaphor.ui.filemanager.FileManager,
'main_window': gaphor.ui.mainwindow.MainWindow,
'model_browser': gaphor.ui.modelbrowser.ModelBrowser,
'modeling_language': gaphor.services.modelinglanguage.ModelingLanguageService,
'properties': gaphor.services.properties.Properties,
'recent_files': gaphor.ui.recentfiles.RecentFiles,
'sanitizer': gaphor.UML.sanitizerservice.SanitizerService,
'toolbox': gaphor.ui.toolbox.Toolbox,
'tools_menu': gaphor.ui.menufragment.MenuFragment,
'undo_manager': gaphor.services.undomanager.UndoManager,
'xmi_export': gaphor.plugins.xmiexport.XMIExport}
Ahora vamos a crear un componente en nuestro modelo para cada servicio.
from gaphor import UML
from gaphor.core.modeling import ElementFactory
element_factory = ElementFactory()
def create_component(name):
c = element_factory.create(UML.Component)
c.name = name
return c
components = {name: create_component(name) for name in entry_points}
components
{'auto_layout': <gaphor.UML.uml.Component element 2f464828-12db-11ee-b024-0242ac110002>,
'component_registry': <gaphor.UML.uml.Component element 2f464b70-12db-11ee-b024-0242ac110002>,
'console_window': <gaphor.UML.uml.Component element 2f464d00-12db-11ee-b024-0242ac110002>,
'copy': <gaphor.UML.uml.Component element 2f464e72-12db-11ee-b024-0242ac110002>,
'diagram_export': <gaphor.UML.uml.Component element 2f464fbc-12db-11ee-b024-0242ac110002>,
'diagrams': <gaphor.UML.uml.Component element 2f4650e8-12db-11ee-b024-0242ac110002>,
'element_dispatcher': <gaphor.UML.uml.Component element 2f46520a-12db-11ee-b024-0242ac110002>,
'element_editor': <gaphor.UML.uml.Component element 2f465354-12db-11ee-b024-0242ac110002>,
'element_factory': <gaphor.UML.uml.Component element 2f4654c6-12db-11ee-b024-0242ac110002>,
'event_manager': <gaphor.UML.uml.Component element 2f4655de-12db-11ee-b024-0242ac110002>,
'export_menu': <gaphor.UML.uml.Component element 2f4656ec-12db-11ee-b024-0242ac110002>,
'file_manager': <gaphor.UML.uml.Component element 2f4657fa-12db-11ee-b024-0242ac110002>,
'main_window': <gaphor.UML.uml.Component element 2f4658ea-12db-11ee-b024-0242ac110002>,
'model_browser': <gaphor.UML.uml.Component element 2f4659e4-12db-11ee-b024-0242ac110002>,
'modeling_language': <gaphor.UML.uml.Component element 2f465ad4-12db-11ee-b024-0242ac110002>,
'properties': <gaphor.UML.uml.Component element 2f465bce-12db-11ee-b024-0242ac110002>,
'recent_files': <gaphor.UML.uml.Component element 2f465cbe-12db-11ee-b024-0242ac110002>,
'sanitizer': <gaphor.UML.uml.Component element 2f465dae-12db-11ee-b024-0242ac110002>,
'toolbox': <gaphor.UML.uml.Component element 2f465e9e-12db-11ee-b024-0242ac110002>,
'tools_menu': <gaphor.UML.uml.Component element 2f465f98-12db-11ee-b024-0242ac110002>,
'undo_manager': <gaphor.UML.uml.Component element 2f466088-12db-11ee-b024-0242ac110002>,
'xmi_export': <gaphor.UML.uml.Component element 2f46616e-12db-11ee-b024-0242ac110002>}
Con todos los componentes mapeados, podemos crear dependencias entre esos componentes, basándonos en los nombres de los parámetros del constructor.
import inspect
for name, cls in entry_points.items():
for param_name in inspect.signature(cls).parameters:
if param_name not in components:
continue
dep = element_factory.create(UML.Usage)
dep.client = components[name]
dep.supplier = components[param_name]
Con todos los elementos en el modelo, podemos crear un diagrama. Vamos a soltar los componentes y las dependencias en el diagrama y dejar que el diseño automático haga su magia.
Para que la dependencia se vea bien, tenemos que añadir una hoja de estilo. Si crea un diagrama nuevo a través de la interfaz gráfica de usuario, este elemento se añade automáticamente.
from gaphor.core.modeling import Diagram, StyleSheet
from gaphor.diagram.drop import drop
element_factory.create(StyleSheet)
diagram = element_factory.create(Diagram)
for element in element_factory.lselect():
drop(element, diagram, x=0, y=0)
El último paso consiste en maquetar y dibujar el diagrama.
from gaphor.extensions.ipython import auto_layout, draw
auto_layout(diagram)
draw(diagram, format="svg")
Eso es todo. Como puede ver en el diagrama, muchos servicios dependen de EventManager
.
Stereotypes#
In UML, stereotypes are way to extend the application of the UML language to new domains. For example: SysML started as a profile for UML.
Gaphor supports stereotypes too. They’re the way for you to adapt your models to your specific needs.
The UML, SysML, RAAML and other models used in Gaphor – the code is generated from Gaphor model files – make use of stereotypes to provide specific information used when generating the data model code.
To create a stereotype, ensure the UML Profile is active and open the Profile
section of the toolbox. First add a Metaclass to your diagram. Next add a
Stereotype, and connect both with a Extension.
The «metaclass»
stereotype will only show once the Extension is connected
both class and stereotype.
Nota
The class names in the metaclass should be a class name from the UML model,
such as Class
, Interface
, Property
, Association
.
Or even Element
if you want to use the stereotype on all elements.
Your stereotype declaration may look something like this:
The Asynchronous
stereotype has a property priority
. This property can
be proved a value once the stereotype is applied to a Property, such as an
association end.
When a stereotype can be applied to a model element, a Stereotype section will appear in the editor.
Resolver conflictos de fusión#
Supongamos que está trabajando en un modelo. Si crea un cambio, mientras que otra persona también ha hecho cambios, hay una buena probabilidad de que termine con un conflicto de fusión.
Gaphor intenta que los cambios en un modelo sean lo más pequeños posible: todos los elementos se almacenan en el mismo orden. Sin embargo, dado que un modelo Gaphor es un gráfico persistente de objetos, fusionar cambios no es tan sencillo como abrir un editor de texto.
A partir de Gaphor 2.18, Gaphor también es capaz de fusionar modelos. Una vez detectado un conflicto de fusión, Gaphor ofrecerá la opción de abrir el modelo actual, el modelo entrante o fusionar los cambios manualmente a través del Editor de fusión.
If you choose Open Merge Editor, both models will be loaded. The current model remains as is. In addition, the changes made to the incoming model are calculated. Those changes are stored as pending change objects in the model.
Truco
Pending changes are part of the model, you can save the model with changes and resolve those at a later point.
The Merge Editor is shown on the right side, replacing the (normal) Property Editor.
Merge actions are grouped by diagram, where possible. When you apply a change, all changes listed as children are also applied. Once changes are applied, they can only be reverted by undoing the change (hit Undo).
Nota
The Merge Editor replaces the Property Editor, as long as there are pending changes in the model.
It is concidered good practice to resolve the merge conflict before you continue modeling.
When all conflicts have been resolved, press Resolve to finish merge conflict resolution.
Plugins#
Importante
Plugins is an experimental feature! The API may change.
We welcome you to try and provide your feedback.
Plugins allow you to extend the functionality of Gaphor beyond the features provided in the standard distributions. In particular, plugins can be helpful if you install the binary distributions available on the download page.
Gaphor can be extended via entry points in several ways:
Application (global) services (
gaphor.appservices
)Session specific services (
gaphor.services
)Modeling languages (
gaphor.modelinglanguages
)(Sub)command line parsers (
gaphor.argparsers
)Indirectly loaded modules (
gaphor.modules
), mainly for UI components
The default location for plugins is $HOME/.local/gaphor/plugins-2
($USER/.local/gaphor/plugins-2
on Windows).
This location can be changed by setting the environment variable GAPHOR_PLUGIN_PATH
and point to a directory.
Install a plugin#
At this moment Gaphor does not have functionality bundled to install and maintain plugins.
To install a plugin, use pip
from a Python installation on your computer. On macOS and Linux, that should be easy,
on Windows you may need to install Python separately from python.org or the Windows Store.
Importante
Since plugins are installed with your system Python version, it’s important that plugins are pure python - e.i. do not contain compiled C code.
For example: to install the Hello World plugin on Linux and macOS, enter:
pip install --target $HOME/.local/gaphor/plugins-2 git+https://github.com/gaphor/gaphor_plugin_helloworld.git
Then start Gaphor as you normally would.
A new Hello World entry has been added to the tools menu ( → Tools → Hello World).
If you want to write a plugin yourself, you can familiarize yourself with Gaphor’s design principles, service oriented architecture, and event driven framework. Next you can have a look at the Hello World plugin available on GitHub.
Gaphor en Linux#
Gaphor can be installed as Flatpak on Linux, some distributions provide packages. Check out the Gaphor download page for details.
Las versiones anteriores están disponibles en GitHub.
También están disponibles construcciones CI.
Entorno de desarrollo#
Hay dos formas de configurar un entorno de desarrollo:
GNOME Builder, ideal para contribuciones «drive by».
GNOME Builder#
Abra GNOME Builder 43 o más reciente, clone el repositorio. Compruebe si la Configuración activa está configurada como org.gaphor.Gaphor.json
. Si es así, pulse el botón Ejecutar para iniciar la aplicación.
Un entorno local#
Para configurar un entorno de desarrollo con Linux, primero necesita una versión de distribución de Linux bastante nueva. Por ejemplo, la última Ubuntu LTS o más reciente, Arch, Debian Testing, SUSE Tumbleweed, o similar. Gaphor depende de versiones más recientes de GTK, y no comprobamos la compatibilidad con versiones anteriores. También necesitará la última versión estable de Python. Para obtener la última versión estable sin interferir con la versión de Python de todo el sistema, le recomendamos que instale pyenv.
Instale primero pyenv prerrequisitos y, a continuación, instale pyenv:
curl https://pyenv.run | bash
Asegúrese de seguir las instrucciones al final del script de instalación para instalar los comandos en el archivo rc de su shell. A continuación instale la última versión de Python ejecutando:
pyenv install 3.x.x
Donde 3.x.x se sustituye por la última versión estable de Python (pyenv debería permitirte completar por tabuladores las versiones disponibles).
A continuación, instale los requisitos previos de Gaphor instalando las dependencias de gobject introspection y cairo build, por ejemplo, en Ubuntu execute:
sudo apt-get install -y python3-dev python3-gi python3-gi-cairo
gir1.2-gtk-4.0 libgirepository1.0-dev libcairo2-dev libgtksourceview-5-dev
pipx install poetry
cd gaphor
# activate latest python for this project
pyenv local 3.x.x # 3.x.x is the version you installed earlier
poetry env use 3.x # ensures poetry /consistently/ uses latest major release
poetry config virtualenvs.in-project true
poetry install
poetry run gaphor
NOTA: Gaphor requiere GTK 4. Funciona mejor con GTK >=4.8 y libadwaita >=1.2.
Debugging using Visual Studio Code#
Before you start debugging you’ll need to open Gaphor is vscode (the folder
containing pyproject.toml
). You’ll need to have the Python extension installed.
Create a file .vscode/launch.json
with the following content:
{
"version": "0.2.0",
"configurations": [
{
"name": "Python: Gaphor UI",
"type": "python",
"request": "launch",
"module": "gaphor",
"justMyCode": false,
"env": {
"GDK_BACKEND": "wayland",
}
}
]
}
GDK_BACKEND
is added since VSCode by default uses XWayland (the X11 emulator).
Crear un paquete Flatpak#
El principal método de empaquetado de Gaphor para Linux es con un paquete Flatpak. Flatpak es una utilidad de software para el despliegue de software y la gestión de paquetes para Linux. Ofrece un entorno de aislamiento en el que los usuarios pueden ejecutar software de aplicación aislado del resto del sistema.
Distribuimos el Flatpak oficial usando Flathub, y la construcción de la imagen se realiza en el repositorio Gaphor Flathub.
Instalar flatpak-builder
sudo apt-get install flatpak-builder
Instalar el SDK de GNOME
flatpak install flathub org.gnome.Sdk 43
Clone el repositorio de Flathub e instale el SDK necesario:
git clone https://github.com/flathub/org.gaphor.Gaphor.git cd org.gaphor.Gaphor make setup
Construir Gaphor Flatpak
make
Instalar el Flatpak
make install
Paquetes de distribución Linux#
Se pueden encontrar ejemplos de archivos de especificaciones RPM de Gaphor y Gaphas en PLD Linux repositorio:
https://github.com/pld-linux/python-gaphas
https://github.com/pld-linux/gaphor
También hay un Arch User Repository (AUR) para Gaphor disponible para los usuarios de Arch.
No dude en ponerse en contacto con nosotros si necesita ayuda para crear un paquete Linux para Gaphor o Gaphas.
Gaphor en macOS#
La última versión de Gaphor puede descargarse de la página de descargas de Gaphor. Gaphor también puede instalarse como Homebrew cask.
Las versiones anteriores están disponibles en GitHub.
También están disponibles construcciones CI.
Entorno de desarrollo#
Para configurar un entorno de desarrollo con macOS:
Instalar Homebrew
Abra un terminal y ejecute:
brew install python3 gobject-introspection gtk4 gtksourceview5 libadwaita adwaita-icon-theme graphviz
pipx install poetry
cd gaphor
poetry config virtualenvs.in-project true
poetry install
poetry run gaphor
Si PyGObject no compila y se queja de que falta el archivo ffi.h
, establezca la siguiente variable de entorno y ejecute poetry install
de nuevo:
export PKG_CONFIG_PATH=/usr/local/opt/libffi/lib/pkgconfig
poetry install
Debugging using Visual Studio Code#
Before you start debugging you’ll need to open Gaphor is VSCode (the folder
containing pyproject.toml
). You’ll need to have the Python extension installed.
Create a file .vscode/launch.json
with the following content:
{
"version": "0.2.0",
"configurations": [
{
"name": "Python: Gaphor UI",
"type": "python",
"request": "launch",
"module": "gaphor",
"justMyCode": false,
}
]
}
Empaquetado para macOS#
Para crear un paquete de instalación exe para macOS, usamos PyInstaller que analiza Gaphor para encontrar todas las dependencias y agruparlas en una única carpeta.
Siga las instrucciones anteriores para configurar un entorno de desarrollo
Abra un terminal y ejecute lo siguiente desde el directorio del repositorio:
poetry install --with packaging
poetry run poe package
Gaphor on Windows#
Gaphor can be installed as with our installer. Check out the Gaphor download page for details.
Las versiones anteriores están disponibles en GitHub.
También están disponibles construcciones CI.
Entorno de desarrollo#
Choco#
We recommend using Chocolately as a package manager in Windows.
To install it, open PowerShell as an administrator, then execute:
Set-ExecutionPolicy Bypass -Scope Process -Force; iex ((New-Object System.Net.WebClient).DownloadString('https://community.chocolatey.org/install.ps1'))
To run local scripts in follow-on steps, also execute
Set-ExecutionPolicy RemoteSigned
This allows for local PowerShell scripts to run without signing, but still requires signing for remote scripts.
Git#
To setup a development environment in Windows first install Git by executing as an administrator:
choco install git
MSYS2#
The development environment in the next step needs MSYS2 installed to provide some Linux command line tools in Windows.
Keep PowerShell open as administrator and install MSYS2:
choco install msys2
GTK and Python with gvsbuild#
gvsbuild provides a Python script helps you build the GTK library stack for Windows using Visual Studio. By compiling GTK with Visual Studio, we can then use a standard Python development environment in Windows.
First we will install the gvsbuild dependencies:
Visual C++ build tools workload for Visual Studio 2022 Build Tools
Python
Install Visual Studio 2022#
With your admin PowerShell terminal:
choco install visualstudio2022-workload-vctools
Install the Latest Python#
In Windows, The full installer contains all the Python components and is the best option for developers using Python for any kind of project.
For more information on how to use the official installer, please see the full installer instructions. The default installation options should be fine for use with Gaphor.
Install the latest Python version using the official installer.
Open a PowerShell terminal as a normal user and check the python version:
py -3.11 --version
Install Graphviz#
Graphviz is used by Gaphor for automatic diagram formatting.
Install from Chocolately with administrator PowerShell:
choco install graphviz
Restart your PowerShell terminal as a normal user and check that the dot command is available:
dot -?
Install pipx#
From the regular user PowerShell terminal execute:
py -3.11 -m pip install --user pipx
py -3.11 -m pipx ensurepath
Install gvsbuild#
From the regular user PowerShell terminal execute:
pipx install gvsbuild
Build GTK#
In the same PowerShell terminal, execute:
gvsbuild build --enable-gi --py-wheel gobject-introspection gtk4 libadwaita gtksourceview5 pygobject pycairo adwaita-icon-theme hicolor-icon-theme
Grab a coffee, the build will take a few minutes to complete.
Setup Gaphor#
In the same PowerShell terminal, clone the repository:
cd (to the location you want to put Gaphor)
git clone https://github.com/gaphor/gaphor.git
cd gaphor
Install Poetry
pipx install poetry
poetry config virtualenvs.in-project true
Add GTK to your environmental variables:
$env:Path = $env:Path + ";C:\gtk-build\gtk\x64\release\bin"
$env:LIB = "C:\gtk-build\gtk\x64\release\lib"
$env:INCLUDE = "C:\gtk-build\gtk\x64\release\include;C:\gtk-build\gtk\x64\release\include\cairo;C:\gtk-build\gtk\x64\release\include\glib-2.0;C:\gtk-build\gtk\x64\release\include\gobject-introspection-1.0;C:\gtk-build\gtk\x64\release\lib\glib-2.0\include;"
You can also edit your account’s Environmental Variables to persist across PowerShell sessions.
Install Gaphor’s dependencies
poetry install
Reinstall PyGObject and pycairo using gvsbuild wheels
poetry run pip install --force-reinstall (Resolve-Path C:\gtk-build\build\x64\release\pygobject\dist\PyGObject*.whl)
poetry run pip install --force-reinstall (Resolve-Path C:\gtk-build\build\x64\release\pycairo\dist\pycairo*.whl)
Launch Gaphor!
poetry run gaphor
Debugging using Visual Studio Code#
Start a new PowerShell terminal, and set current directory to the project folder:
cd (to the location you put gaphor)
Ensure that path environment variable is set:
$env:Path = "C:\gtk-build\gtk\x64\release\bin;" + $env:Path
Start Visual Studio Code:
code .
To start the debugger, execute the following steps:
Open
__main__.py
file fromgaphor
folderAdd a breakpoint on line
main(sys.argv)
In the menu, select Run → Start debugging
Choose Select module from the list
Enter
gaphor
as module name
Visual Studio Code will start the application in debug mode, and will stop at main.
Packaging for Windows#
In order to create an exe installation package for Windows, we utilize PyInstaller which analyzes Gaphor to find all the dependencies and bundle them in to a single folder. We then use a custom bash script that creates a Windows installer using NSIS and a portable installer using 7-Zip. To install them, open PowerShell as an administrator, then execute:
choco install nsis 7zip
Then build your installer using:
poetry install --only main,packaging,automation
poetry build
poetry run poe package
poetry run poe win-installer
Gaphor en un contenedor#
En lugar de crear un entorno de desarrollo local, la forma más sencilla de contribuir al proyecto es usar GitHub Codespaces.
GitHub Codespaces#
Siga estos pasos para abrir Gaphor en un Codespace:
Navegar hasta https://github.com/gaphor/gaphor
Haga clic en el menú desplegable Código y seleccione la opción Abrir con Codespaces.
Seleccione + Codespace nuevo en la parte inferior del panel.
Para más información, consulte la documentación de GitHub.
Modeling Language Core#
The Core modeling language is the the basis for any other language.
The Element
class acts as the root for all gaphor domain classes.
Diagram
and Presentation
form the basis for everything you see
in a diagram.
All data models in Gaphor are generated from actual Gaphor model files. This allows us to provide you nice diagrams of Gaphor’s internal model.
The Element
base class provides event notification and integrates
with the model repository (internally known as ElementFactory
).
Bi-directional relationships are also possible, as well as derived
relations.
Change Sets#
The core model has support for change sets, sets of pending changes. Normally you end up with a change set when you resolve a merge conflict in your model.
This diagram is provided for completion sake.
Unified Modeling Language#
The UML model is the most extensive model in Gaphor. It is used as a base language for SysML, RAAML, and C4.
Gaphor follows the official UML 2.5.1 data model. Where changes have been made a comment has been added to the model. In particular where m:n relationships subset 1:n relationships.
01. Common Structure#
1. Root#
2. Templates#
Not implemented.
3. Namespaces#
4. Types and Multiplicity#
5. Constraints#
6. Dependencies#
02. Values#
1. Literals#
2. Expressions#
03. Classification#
1. Classifiers#
3. Features#
4. Properties#
5. Operations#
7. Instances#
04. Simple Classifiers#
1. Data Types#
3. Interfaces#
05. Structured Classifiers#
1. Structured Classifiers#
2. Encapsulated Classifiers#
3. Classes#
4. Associations#
5. Components#
6. Collaborations#
06. Packaging#
1. Packages#
2. Profiles#
07. Common Behaviors#
1. Behaviors#
2. Events#
08. State Machines#
1. Behavior State Machines#
09. Activities#
1. Activities#
2. Control Nodes#
3. Object Nodes#
4. Executable Nodes#
5. Activity Groups#
10. Actions#
1. Actions#
2. Invocation Actions#
7. Structural Feature Actions#
9. Accept Event Actions#
11. Interactions#
1. Interactions#
2. Lifelines#
3. Messages#
4. Occurrences#
12. Use Cases#
UseCases#
13. Deployments#
1. Deployments#
2. Artifacts#
3. Nodes#
14. Information Flows#
A. Gaphor Specific Constructs#
1. Stereotype Applications#
B. Gaphor Profile#
In order to provide extra information to the diagram elements (mainly association ends), the Gaphor model has been extended with stereotypes.
Systems Modeling Language#
Gaphor implements part of the SysML 1.6 specification.
Activities#
Allocations#
AllocatedActivityPartition#
Allocation#
Blocks#
Adjunt and Classifier Behavior Properties#
Bound References#
Connector Ends#
Properties#
Property Paths#
Property-Specific Types#
Property Strings#
Value Types#
ConstraintBlocks#
Libraries#
ModelElements#
PortsAndFlows#
Actions on Nested Ports#
Port Stereotypes#
Property Value Change Events#
Provided and Required Features#
Item Flow#
Requirements#
Risk Analysis and Assessment Modeling Language#
Gaphor implements parts of the RAAML 1.0 specification.
Core#
Core Library/Any Situation#
Core Profile/Controlling Measure#
Core Profile/Relevant To#
Core Profile/Situation#
Core Profile/Violates#
General#
Basic Event#
General Concepts Library/Abstract Cause#
General Concepts Library/Abstract Effect#
General Concepts Library/Abstract Event#
General Concepts Library/Abstract Failure Mode#
General Concepts Library/Abstract Risk#
General Concepts Library/Activation#
General Concepts Library/Cause#
General Concepts Library/Dysfunctional Event#
General Concepts Library/Effect#
General Concepts Library/Error Propagation#
General Concepts Library/Error Realization#
General Concepts Library/Harm Potential#
General Concepts Library/Hazard#
General Concepts Library/Scenario#
General Concepts Library/Undesired State#
General Concepts Profile/Detection#
General Concepts Profile/Failure State#
General Concepts Profile/Mitigation#
General Concepts Profile/Prevention#
General Concepts Profile/Recommendation#
General Concepts Profile/Undeveloped#
Methods#
FTA/FTA Library/Events/Basic Event#
FTA/FTA Library/Events/Conditional Event#
FTA/FTA Library/Events/Dormant Event#
FTA/FTA Library/Events/Events#
FTA/FTA Library/Events/Event#
FTA/FTA Library/Events/House Event#
FTA/FTA Library/Events/Intermediate Event#
FTA/FTA Library/Events/Top Event#
FTA/FTA Library/Events/Undeveloped Event#
FTA/FTA Library/Events/Zero Event#
FTA/FTA Library/FTA Element#
FTA/FTA Library/FTA Library#
FTA/FTA Library/FTA Tree#
FTA/FTA Library/Gates/AND#
FTA/FTA Library/Gates/Gate#
FTA/FTA Library/Gates/INHIBIT#
FTA/FTA Library/Gates/MAJORITY_VOTE#
FTA/FTA Library/Gates/NOT#
FTA/FTA Library/Gates/OR#
FTA/FTA Library/Gates/SEQ#
FTA/FTA Library/Gates/XOR#
FTA/FTA Profile/AND#
FTA/FTA Profile/Conditional Event#
FTA/FTA Profile/Dormant Event#
FTA/FTA Profile/Event#
FTA/FTA Profile/Gate#
FTA/FTA Profile/House Event#
FTA/FTA Profile/INHIBIT#
FTA/FTA Profile/Intermediate Event#
FTA/FTA Profile/MAJORITY_VOTE#
FTA/FTA Profile/NOT#
FTA/FTA Profile/OR#
FTA/FTA Profile/SEQ#
FTA/FTA Profile/Top Event#
FTA/FTA Profile/Transfer In#
FTA/FTA Profile/Transfer Out#
FTA/FTA Profile/Tree#
FTA/FTA Profile/XOR#
FTA/FTA Profile/Zero Event#
FTA/FTA#
The C4 Model#
The C4 model is a simple visual language to describe the static structure of a software system.
It’s based on the UML language.
Principios de diseño#
Gaphor existe desde hace bastantes años. En esos años nosotros (los desarrolladores de Gaphor) aprendimos algunas cosas sobre cómo construirlo. Gaphor intenta ser fácilmente accesible para los usuarios principiantes, así como una herramienta útil para los usuarios más experimentados.
Gaphor no es un editor al uso. Es un entorno de modelado. Esto implica que hay un lenguaje que sustenta los modelos. Los lenguajes se adhieren a reglas y Gaphor intenta seguir esas reglas.
La usabilidad es muy importante. Cuando se es nuevo en Gaphor, debe ser fácil orientarse. Un conocimiento mínimo de UML debería al menos permitirle crear un diagrama de clases.
Orientación#
Para ayudar a los usuarios, Gaphor debe proporcionar orientación siempre que pueda.
Ayuda con las relaciones#
El diagrama muestra en gris todos los elementos a los que no puede conectarse una relación. Esto ayuda a decidir dónde puede conectarse una relación. Puede mezclar diferentes elementos, pero intentamos que sea lo más sencillo posible para crear modelos coherentes.
Mantener el modelo sincronizado#
Una parte importante del modelado es diseñar un sistema en abstracciones y ser capaz de explicarlas a otros. A medida que los sistemas se complican, es importante disponer del diseño (modelo) en diagramas.
Gaphor hace todo lo posible para mantener el modelo sincronizado con los diagramas. De este modo, los elementos no usados pueden eliminarse automáticamente del modelo si ya no se muestran en ningún diagrama.
Fuera de su camino#
Al modelar, debe estar ocupado con su problema o dominio de solución, no con la herramienta. Gaphor intenta mantenerse al margen en la medida de lo posible. No trata de fastidiarle con mensajes de error, porque el modelo no es «correcto».
Evitar diálogos#
Para hacer lo correcto y no estorbar a los usuarios, Gaphor evita en lo posible el uso de diálogos.
Gaphor debe permitirle hacer lo más sensato (véase más arriba) y no sacarle de sus casillas con todo tipo de preguntas.
Notificar cambios#
Cuando Gaphor está haciendo algo que no es directamente visible, verá una notificación, por ejemplo, un elemento que se elimina indirectamente del modelo. No le interrumpirá con diálogos, sino que sólo proporcionará una pequeña notificación en la aplicación. Si el cambio no es deseado, pulse deshacer
.
Equilibrado#
Aunque Gaphor implementa gran parte del modelo UML 2, no está completo. Intentamos encontrar el equilibrio adecuado en las características para satisfacer tanto a los modeladores expertos como a los principiantes.
Continuidad#
Un modelo creado debe poder usarse en el futuro. Gaphor lo reconoce. Nos importa la compatibilidad.
Compatibilidad con versiones anteriores#
Gaphor es capaz de cargar modelos que se remontan a Gaphor 1.0. Es importante que una herramienta siempre permita cargar modelos antiguos.
Multiplataforma#
Nos hemos esforzado mucho para que Gaphor funcione en las principales plataformas: Windows, macOS y Linux. Disponer de Gaphor en todas las plataformas es esencial si se quiere compartir el modelo. Sería horrible tener que ejecutar un sistema operativo específico para abrir un modelo.
Hasta ahora, no soportamos la cuarta plataforma principal (web). Las aplicaciones nativas ofrecen una mejor experiencia de usuario (una vez instaladas). Pero esto puede cambiar.
Interacción del usuario#
Gaphor está escrito originalmente en Linux. Usa GTK como interfaz de usuario. Esto implica que Gaphor sigue las GNOME Human Interface Guidelines (HIG). Gaphor es también una aplicación multiplataforma. Tratamos de mantenernos cerca de las HIG de GNOME, pero tratamos de no introducir conceptos que no están disponibles en Windows y macOS.
No se generan componentes de interfaz de usuario. Nos dimos cuenta de que la generación de interfaz de usuario (al igual que muchas herramientas de modelado empresarial) proporciona una experiencia de usuario horrible. Queremos que los usuarios usen Gaphor con regularidad, así que nuestro objetivo es que sea una herramienta agradable a la vista y con la que sea fácil trabajar.
¿Qué más?#
Idempotencia Permitir que la misma operación se aplique varias veces. Esto no debería afectar al resultado.
Dirigido por eventos Gaphor es una aplicación de usuario. Actúa ante eventos del usuario. La aplicación usa un despachador de eventos interno (bus de eventos) para distribuir los eventos a las partes interesadas. Todo el mundo debe ser capaz de escuchar los eventos.
Framework#
Resumen#
Gaphor está construido de una manera ligera y orientada a servicios. La aplicación se divide en una serie de servicios, como un gestor de archivos, eventos y deshacer. Estos servicios se cargan en base a los puntos de entrada definidos en el archivo pyproject.toml
. Para obtener más información sobre la arquitectura, consulte la descripción sobre la Arquitectura Orientada a Servicios.
Dirigido por eventos#
Las partes de Gaphor se comunican entre sí mediante eventos. Cada vez que algo importante sucede, por ejemplo, un atributo de un elemento del modelo cambia, se envía un evento. Cuando otras partes de la aplicación están interesadas en un cambio, registran un controlador de eventos para ese tipo de evento. Los eventos se emiten a través de un intermediario central, por lo que no es necesario registrarse en cada elemento individual que pueda enviar un evento en el que estén interesados. Por ejemplo, un elemento de diagrama podría registrar una regla de evento y luego comprobar si el elemento que envió el evento es realmente el evento que el elemento está representando. Para más información, consulte la descripción completa del sistema de eventos.
Transaccional#
Gaphor es transaccional, lo que significa que mantiene un registro de las funciones que realiza como una serie de transacciones. Las transacciones funcionan enviando un evento cuando una transacción comienza y enviando otro cuando una transacción termina. Esto permite, por ejemplo, que el gestor de deshacer mantenga un registro de las transacciones anteriores para que una transacción pueda ser revertida si se pulsa el botón de deshacer.
Componentes principales#
La parte principal de Gaphor que se ejecuta primero se llama Aplicación
. Gaphor puede tener varios modelos abiertos en cualquier momento. Cada modelo se mantiene en una Sesión
. Sólo una instancia de la aplicación está activa. Cada sesión cargará sus propios servicios definidos como gaphor.services.
Los servicios más destacados son:
gestor_de_eventos#
Este es el componente central usado para el envío de eventos. Cada servicio que hace algo con eventos (tanto enviar como recibir) depende de este componente.
gestor_archivos#
La carga y guardado de un modelo se realiza a través de este servicio.
fábrica_de_elementos#
El propio modelo de datos se mantiene en la fábrica de elementos (gaphor.core.modeling.elementfactory
). Este servicio se usa para crear elementos del modelo, así como para buscar elementos o consultar un conjunto de elementos.
gestor_deshacer#
Uno de los servicios más apreciados. ¡Permite a los usuarios equivocarse de vez en cuando!
El gestor de deshacer es transaccional. Las acciones realizadas por un usuario sólo se almacenan si hay una transacción activa. Si se completa una transacción (confirmada) se almacena una acción nueva de deshacer. Las transacciones también pueden revertirse, en cuyo caso todos los cambios se reproducen directamente. Para más información consulte la descripción completa del gestor de deshacer.
Service Oriented Architecture#
Gaphor has a service oriented architecture. What does this mean? Well, Gaphor is built as a set of small islands (services). Each island provides a specific piece of functionality. For example, we use separate services to load/save models, provide the menu structure, and to handle the undo system.
We define services as entry points in the pyproject.toml
. With entry points,
applications can register functionality for specific purposes. We also group
entry points in to entry point groups. For example, we use the
console_scripts entry point group to start an application from the command
line.
Services#
Gaphor is modeled around the concept of services. Each service can be registered with the application and then it can be used by other services or other objects living within the application.
Each service should implement the Service interface. This interface defines one method:
shutdown(self)
Which is called when a service needs to be cleaned up.
We allow each service to define its own methods, as long as the service is implemented too.
Services should be defined as entry points in the pyproject.toml
file.
Typically, a service does some work in the background. Services can also expose actions that can be invoked by users. For example, the Ctrl-z key combo (undo) is implemented by the UndoManager service.
A service can also depend on another services. Service initialization resolves these dependencies. To define a service dependency, just add it to the constructor by its name defined in the entry point:
class MyService(Service):
def __init__(self, event_manager, element_factory):
self.event_manager = event_manager
self.element_factory = element_factory
event_manager.subscribe(self._element_changed)
def shutdown(self):
self.event_manager.unsubscribe(self._element_changed)
@event_handler(ElementChanged)
def _element_changed(self, event):
Services that expose actions should also inherit from the ActionProvider
interface. This interface does not require any additional methods to be
implemented. Action methods should be annotated with an @action
annotation.
Example: ElementFactory#
A nice example of a service in use is the ElementFactory. It is one of the core services.
The UndoManager depends on the events emitted by the ElementFactory. When an
important events occurs, like an element is created or destroyed, that event is
emitted. We then use an event handler for ElementFactory that stores the
add/remove signals in the undo system. Another example of events that are
emitted are with UML.Element
s. Those classes, or more specifically, the
properties, send notifications every time their state changes.
Entry Points#
Gaphor uses a main entry point group called gaphor.services
.
Services are used to perform the core functionality of the application while breaking the functions in to individual components. For example, the element factory and undo manager are both services.
Plugins can also be created to extend Gaphor beyond the core functionality as
an add-on. For example, a plugin could be created to connect model data to
other applications. Plugins are also defined as services. For example a new XMI
export plugin would be defined as follows in the pyproject.toml
:
[tool.poetry.plugins."gaphor.services"]
"xmi_export" = "gaphor.plugins.xmiexport:XMIExport"
Interfaces#
Each service (and plugin) should implement the gaphor.abc.Service
interface:
Another more specialized service that also inherits from gaphor.abc.Service
,
is the UI Component service. Services that use this interface are used to
define windows and user interface functionality. A UI component should
implement the gaphor.ui.abc.UIComponent
interface:
- class gaphor.ui.abc.UIComponent[fuente]#
A user interface component.
Typically, a service and UI component would like to present some actions
to the user, by means of menu entries. Every service and UI component
can advertise actions by implementing the gaphor.abc.ActionProvider
interface:
Example plugin#
A small example is provided by means of the Hello world plugin. Take a look at the files at GitHub. The example plugin needs to be updated to support versions 1.0.0 and later of Gaphor.
The pyproject.toml file contains a plugin:
[tool.poetry.plugins."gaphor.services"]
"helloworld" = "gaphor_helloworld_plugin:HelloWorldPlugin"
This refers to the class HelloWorldPlugin
in package/module
gaphor_plugins_helloworld.
Here is a stripped version of the hello world plugin:
from gaphor.abc import Service, ActionProvider
from gaphor.core import _, action
class HelloWorldPlugin(Service, ActionProvider): # 1.
def __init__(self, tools_menu): # 2.
self.tools_menu = tools_menu
tools_menu.add_actions(self) # 3.
def shutdown(self): # 4.
self.tools_menu.remove_actions(self)
@action( # 5.
name="helloworld",
label=_("Hello world"),
tooltip=_("Every application…"),
)
def helloworld_action(self):
main_window = self.main_window
pass # gtk code left out
As stated before, a plugin should implement the
Service
interface. It also implementsActionProvider
, saying it has some actions to be performed by the user.The menu entry will be part of the «Tools» extension menu. This extension point is created as a service. Other services can also be passed as dependencies. Services can get references to other services by defining them as arguments of the constructor.
All action defined in this service are registered.
Each service has a
shutdown()
method. This allows the service to perform some cleanup when it’s shut down.The action that can be invoked. The action is defined and will be picked up by
add_actions()
method (see 3.)
Sistema de eventos#
El sistema de eventos de Gaphor proporciona una API para manejar eventos y suscribirse a eventos.
En Gaphor gestionamos las suscripciones a los manejadores de eventos a través del servicio EventManager
. Gaphor está altamente orientado a eventos:
Los cambios en el modelo cargado se emiten como eventos
Los cambios en los diagramas se emiten como eventos
Los cambios en la interfaz de usuario se emiten como eventos
Aunque Gaphor depende en gran medida de GTK para su interfaz de usuario, Gaphor usa su propio despachador de eventos. Los eventos se pueden estructurar en jerarquías. Por ejemplo, un evento AttributeUpdated
es un subtipo de ElementUpdated
. Si estamos interesados en todos los cambios en los elementos, también podemos registrar ElementUpdated
y recibir todos los eventos AttributeUpdated
también.
- class gaphor.core.eventmanager.EventManager[fuente]#
El gestor de eventos.
- handle(*events: object) None [fuente]#
Enviar notificaciones de eventos a los manejadores registrados.
- priority_subscribe(handler: Callable[[object], None]) None [fuente]#
Registrar un manejador.
Los manejadores de prioridad se ejecutan directamente. No deben lanzar otros eventos, porque eso puede causar un problema en el orden de ejecución.
Es básicamente para asegurarse de que todos los eventos son registrados por el gestor de deshacer.
Bajo el capó los eventos son manejados por la librería Generic. Para obtener más información sobre cómo la biblioteca Generic gestiona los eventos, consulte la documentación de Generic.
Modeling Languages#
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.
The 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
functions.
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
Diagram types
A toolbox definition
Connectors, allow diagram items to connect
Copy/paste behavior when element copying is not trivial, for example with more than one element is involved
Grouping, allow elements to be nested in one another
Dropping, allow elements to be dragged from the tree view onto a diagram
Automatic cleanup rules to keep the model consistent
The first three by functionalities are exposed by the ModelingLanguage
class.
The other functionalities can be extended by adding handlers to the respective
generic functions.
Modeling languages can also provide new UI components. Those components are not loaded
directly when you import a modeling language package. Instead they should be imported via
the gaphor.modules
entrypoint.
Editor pages, shown in the collapsible pane on the right side
Special diagram interactions
- class gaphor.abc.ModelingLanguage[fuente]#
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 [fuente]#
Look up a model element type by (class) name.
- abstract property toolbox_definition: ToolboxDefinition#
Get structure for the toolbox.
Connectors#
Connectors are used to connect one element to another.
Connectors should adhere to the ConnectorProtocol
.
Normally you would inherit from BaseConnector
.
- class gaphor.diagram.connectors.BaseConnector(element: Presentation[Element], line: Presentation[Element])[fuente]#
Connection adapter for Gaphor diagram items.
Line item
line
connects with a handle to a connectable itemelement
.- Parámetros:
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: Handle, port: Port) bool [fuente]#
Determine if items can be connected.
Returns True if connection is allowed.
Copy and paste#
Copy and paste works out of the box for simple items: one diagram item with one model element (the subject
).
It leveages the load()
and 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
- gaphor.diagram.copypaste.paste_link(copy_data: CopyData, diagram: Diagram, lookup: Callable[[str], Element | None]) set[Presentation]: #
Create a copy of the Presentation element, but try to link the underlying 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:
- gaphor.diagram.copypaste.serialize(value)#
Return a serialized version of a value. If the
value
is an element, it’s referenced.
- gaphor.diagram.copypaste.deserialize(ser, lookup)#
Deserialize a value previously serialized with
serialize()
. Thelookup
function is used to resolve references to other elements.
Grouping#
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.
Dropping#
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
Presentation
element on the diagram.drop
works the other way around: it starts with a model element and creates an accompanyingPresentation
.
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.
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 PropertyPageBase
.
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.instanteditors.instant_editor(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.
Protocolo de conexión#
En Gaphor, si se establece una conexión en un diagrama entre un elemento y una relación, la conexión también se establece a nivel semántico (el modelo). Desde el punto de vista de la interfaz gráfica de usuario, un evento de liberación de un botón es lo que da el pistoletazo de salida a la decisión de si se permite la conexión.
La comprobación de si se permite una conexión también debería comprobar si es válido crear una relación hacia/desde el mismo elemento (como las asociaciones, pero no las generalizaciones).
File Format#
The root element of Gaphor models is the Gaphor
tag, all other elements are
contained in this. The Gaphor element delimits the beginning and the end of an
Gaphor model.
The idea is to keep the file format as simple and extensible as
possible: UML elements (including Diagram) are at the top level with no nesting.
A UML element can have two tags: references (ref
) and values (val
). References are used to point to other UML elements. Values have a value inside (an integer or a string).
Since many references are bi-directional, you’ll find both ends defined in the file (e.g. Package.ownedType
- Actor.package
, and Diagram.ownedPresentation
and UseCaseItem.diagram
).
<?xml version="1.0" ?>
<Gaphor version="1.0" gaphor_version="0.3">
<Package id="1">
<ownedClassifier>
<reflist>
<ref refid="2"/>
<ref refid="3"/>
<ref refid="4"/>
</reflist>
</ownedClassifier>
</Package>
<Diagram id="2">
<package>
<ref refid="1"/>
</package>
<ownedPresentation>
<reflist>
<ref refid="5"/>
<ref refid="6"/>
</reflist>
</ownedPresentation>
</Diagram>
<ActorItem id="5">
<matrix>
<val>(1.0, 0.0, 0.0, 1.0, 147.0, 132.0)</val>
</matrix>
<width>
<val>38.0</val>
</width>
<height>
<val>60.0</val>
</height>
<diagram>
<ref refid="2"/>
</diagram>
<subject>
<ref refid="3"/>
</subject>
</ActorItem>
<UseCaseItem id="6">
<matrix>
<val>(1.0, 0.0, 0.0, 1.0, 341.0, 144.0)</val>
</matrix>
<width>
<val>98.0</val>
</width>
<height>
<val>30.0</val>
</height>
<diagram>
<ref refid="2"/>
</diagram>
<subject>
<ref refid="4"/>
</subject>
</UseCaseItem>
<Actor id="3">
<name>
<val>Actor></val>
</name>
<package>
<ref refid="1"/>
</package>
</Actor>
<UseCase id="4">
<package>
<ref refid="1"/>
</package>
</UseCase>
</Gaphor>
Undo Manager#
Undo is a required feature in modern applications. Gaphor is no exception. Having an undo function in place means you can change the model and easily revert to an older state.
Overview of Transactions#
The recording and playback of changes in Gaphor is handled by the the Undo
Manager. The Undo Manager works transactionally.
A transaction must succeed or fail as a complete unit. If
the transaction fails in the middle, it is rolled back. In Gaphor this is
achieved by the transaction
module, which provides a context manager Transaction
and
a decorator called @transactional
.
When transactions take place, they emit event notifications on the key transaction milestones so that other services can make use of the events. The event notifications are for the begin of the transaction, and the commit of the transaction if it is successful or the rollback of the transaction if it fails.
Start of a Transaction#
A
Transaction
object is created.TransactionBegin
event is emitted.The
UndoManager
instantiates a newActionStack
which is the transaction object, and adds the undo action to the stack.
Nested transactions are supported to allow a transaction to be added inside of another transaction that is already in progress.
Successful Transaction#
A
TransactionCommit
event is emittedThe
UndoManager
closes and stores the transaction.
Failed Transaction#
A
TransactionRollback
event is emitted.The
UndoManager
plays back all the recorded actions, but does not store it.
References#
Transaction support#
Transaction support is located in module gaphor.transaction
:
>>> from gaphor import transaction
>>> import sys, logging
>>> transaction.log.addHandler(logging.StreamHandler(sys.stdout))
Do some basic initialization, so event emission will work. Since the transaction decorator does not know about the active user session (window), it emits it’s events via a global list of subscribers:
>>> from gaphor.core.eventmanager import EventManager
>>> event_manager = EventManager()
>>> transaction.subscribers.add(event_manager.handle)
The Transaction class is used mainly to signal the begin and end of a transaction. This is done by the TransactionBegin, TransactionCommit and TransactionRollback events:
>>> from gaphor.core import event_handler
>>> @event_handler(transaction.TransactionBegin)
... def transaction_begin_handler(event):
... print('tx begin')
>>> event_manager.subscribe(transaction_begin_handler)
Same goes for commit and rollback events:
>>> @event_handler(transaction.TransactionCommit)
... def transaction_commit_handler(event):
... print('tx commit')
>>> event_manager.subscribe(transaction_commit_handler)
>>> @event_handler(transaction.TransactionRollback)
... def transaction_rollback_handler(event):
... print('tx rollback')
>>> event_manager.subscribe(transaction_rollback_handler)
A Transaction is started by initiating a Transaction instance:
>>> tx = transaction.Transaction(event_manager)
tx begin
On success, a transaction can be committed:
>>> tx.commit()
tx commit
After a commit, a rollback is no longer allowed (the transaction is closed):
>>> tx.rollback()
... # doctest: +ELLIPSIS
Traceback (most recent call last):
...
gaphor.transaction.TransactionError: No Transaction on stack.
Transactions may be nested:
>>> tx = transaction.Transaction(event_manager)
tx begin
>>> tx2 = transaction.Transaction(event_manager)
>>> tx2.commit()
>>> tx.commit()
tx commit
Transactions should be closed in the right order (subtransactions first):
>>> tx = transaction.Transaction(event_manager)
tx begin
>>> tx2 = transaction.Transaction(event_manager)
>>> tx.commit()
... # doctest: +ELLIPSIS
Traceback (most recent call last):
...
gaphor.transaction.TransactionError: Transaction on stack is not the transaction being closed.
>>> tx2.commit()
>>> tx.commit()
tx commit
The transactional decorator can be used to mark functions as transactional:
>>> @transaction.transactional
... def a():
... print('do something')
>>> a()
tx begin
do something
tx commit
If an exception is raised from within the decorated function a rollback is performed:
>>> @transaction.transactional
... def a():
... raise IndexError('bla')
>>> a() # doctest; +ELLIPSIS
Traceback (most recent call last):
...
IndexError: bla
>>> transaction.Transaction._stack
[]
Cleanup:
>>> transaction.subscribers.discard(event_manager.handle)