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.

_images/gaphor-core.png

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.

pantalla de bienvenida

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.

modelo nuevo

La disposición de la interfaz Gaphor se divide en cuatro secciones:

  1. Modelo de navegador

  2. Caja de herramientas de elementos de diagrama

  3. Diagramas

  4. 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:

  1. Elementos

  2. 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:

  1. Conectado a un elemento y la manilla se vuelve roja

  2. 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 sidebar-show-right-symbolic 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 document-properties-symbolic. 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 (new class) 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).

imagen

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 (generalización nueva).

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.

imagen

Opcionalmente, puede ejecutar el diseño automático (abrir menú → 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 (diagrama nuevo) en la barra de cabecera.

imagen

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.

Two shots of espresso being pulled from an espressomachine

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.

Top level packages of the SysMLtemplate

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.

Three pillar packages nested under each abstraction levelpackage

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:

  1. Double-click on the actor to pop up the rename dialog, and replace User with Barista.

  2. Update the name of the oval Use Case from Use Case #1 to Brew espresso.

  3. 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.

Use case diagram showing an actor named Barista and a use case called Brew 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.

Block Definition Diagram showing hierarchy of blocks in the Coffee Shop 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.

Block definition diagram showing context of the coffee shop with external entities

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.

Concept requirements for water tank, heat-up time, and HMI button

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.

_images/9fdf0b3c-7170-11ec-999a-f47b099bf663.svg

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.

State machine diagram showing logical states including on and off

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.

Block definition diagram showing the coffee 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.

Internal block diagram showing the clear box view of the espresso machine

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

Logical requirements for the controller command and the water pressure derived from concept requirements

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:

Button to access style code

Here is a simple example of how to change the background color of a class:

class {
  background-color: beige;
}
background beige

Or change the color of a component, only when it’s nested in a node:

node component {
  background-color: skyblue;
}
nested component

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;
}
dark-style

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.

node component

Any component item which is a descendant of a node.

node > component

A component item which is a child of a node.

generaliation[subject]

A generalization item with a subject present.

class[name=Foo]

A class with name «Foo».

diagram[name^=draft]

A diagram with a name starting with «draft».

diagram[name$=draft]

A diagram with a name ends with «draft».

diagram[name*=draft]

A diagram with a name containing the text «draft».

diagram[name~=draft item]

A diagram with a name of «draft» or «item».

diagram[name|=draft]

A diagram with a name is «draft» or starts with «draft-«.

*:focus

The focused item. Other pseudo classes are:

  • :active selected items

  • :hover for the item under the mouse

  • :drop if an item is dragged and can be dropped on this item

  • :disabled if an element is grayed out during handle movement

node:empty

A node containing no child nodes in the diagram.

:root

An item is at the top level of the diagram.

This is only applicable for the diagram

:has()

The item contains any of the provided selectors.

E.g. node:has(component): a node containing a component item.

:is()

Match any of the provided selectors.

E.g. :is(node, subsystem) > component: a node or subsystem.

:not()

Negate the selector.

E.g. :not([subject]): Any item that has no «subject».

  • 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#

background-color

Examples:

background-color: azure;

background-color: rgb(255, 255, 255);

background-color: hsl(130, 95%, 10%);

color

Color used for lines.

text-color

Color for text.

opacity

Color opacity factor (0.0 - 1.0), applied to all colors.

  • 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#

font-family

A single font name (e.g. sans, serif, courier).

font-size

An absolute size (e.g. 14) or a size value (e.g. small).

font-style

Either normal or italic.

font-weight

Either normal or bold.

text-align

Either left, center, right.

text-decoration

Either none or underline.

vertical-align

Vertical alignment for text.

Either top, middle or bottom.

vertical-spacing

Set vertical spacing for icon-like items (actors, start state).

Example: vertical-spacing: 4.

  • 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 values x-small, small, medium, large and x-large are supported.

Drawing and spacing#

border-radius

Radius for rectangles: border-radius: 4.

dash-style

Style for dashed lines: dash-style: 7 5.

justify-content

Content alignment for boxes.

Either start, end, center or stretch.

line-style

Either normal or sloppy [factor].

line-width

Set the width for lines: line-width: 2.

min-height

Set minimal height for an item: min-height: 50.

min-width

Set minimal width for an item: min-width: 100.

padding

CSS style padding (top, right, bottom, left).

Example: padding: 3 4.

  • 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 a diagram. 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. class, usecase.

UML

Classes

all Association’s

association

UML

Components

Device/Node

node

UML

Actions

Decision/Merge Node

decisionnode

UML

Actions

Fork/Join Node

forknode

UML

Actions

Swimlane

partition

UML

Interactions

Reflexive message

message

UML

States

Initial Pseudostate

pseudostate

UML

States

History Pseudostate

pseudostate

UML

Profiles

Metaclass

class

C4 Model

C4 Model

Person

c4person

C4 Model

C4 Model

Software System

c4container[type="Software System"]

C4 Model

C4 Model

Component

c4container[type="Component"]

C4 Model

C4 Model

Container

c4container[type="Container"]

C4 Model

C4 Model

Container: Database

c4database

SysML

Blocks

ValueType

datatype

SysML

Blocks

Primitive

datatype

SysML

Requirements

Derive Requirement

derivedreq

RAAML

FTA

any AND/OR/… Gate

and, or, etc.

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 (open menu → 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 */
}
draft style

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;
}
unconnected relationship

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;
}
control flow

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;
}
highlighted todo note

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
_images/88ff97d7-5c0c-11ea-8042-9771210c7122.svg

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
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")
_images/395fc24675a2bb0a993e3608452b4ad5d3cc710e27de0cd18c44ee48a96583cf.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")
_images/5cdba0fea5ae8e999d38061e133b583d2384c7a86aedc958516e92c8e1ebc7f3.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")
_images/fb3d9102449ecc8244f20f35e3fde06808fd39dabc164a07471623f372a3f153.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")
_images/d94b7c27ffb40ead4395c78a5923f8897c477d6adcf29cd000df5e8598020d08.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:

_images/79803af8-4c9d-11ec-9b16-0456e5e540ed.svg

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.

Stereotype usage example

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.

diálogo 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 conflict window

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:

  1. Application (global) services (gaphor.appservices)

  2. Session specific services (gaphor.services)

  3. Modeling languages (gaphor.modelinglanguages)

  4. (Sub)command line parsers (gaphor.argparsers)

  5. 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 (open 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:

  1. GNOME Builder, ideal para contribuciones «drive by».

  2. Un entorno local.

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

Instale Poetry usando pipx:

pipx install poetry

Clonar el repositorio.

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.

  1. Instalar Flatpak

  2. Instalar flatpak-builder

    sudo apt-get install flatpak-builder
    
  3. Instalar el SDK de GNOME

    flatpak install flathub org.gnome.Sdk 43
    
  4. 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
    
  5. Construir Gaphor Flatpak

    make
    
  6. 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:

  1. Instalar Homebrew

  2. Abra un terminal y ejecute:

brew install python3 gobject-introspection gtk4 gtksourceview5 libadwaita adwaita-icon-theme graphviz

Instale Poetry usando pipx:

pipx install poetry

Clonar el repositorio.

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.

  1. Siga las instrucciones anteriores para configurar un entorno de desarrollo

  2. 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:

  1. Visual C++ build tools workload for Visual Studio 2022 Build Tools

  2. 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.

  1. Install the latest Python version using the official installer.

  2. 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.

  1. Install from Chocolately with administrator PowerShell:

    choco install graphviz
    
  2. 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:

  1. Open __main__.py file from gaphor folder

  2. Add a breakpoint on line main(sys.argv)

  3. In the menu, select Run → Start debugging

  4. Choose Select module from the list

  5. 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:

  1. Navegar hasta https://github.com/gaphor/gaphor

  2. Haga clic en el menú desplegable Código y seleccione la opción Abrir con Codespaces.

  3. 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.

_images/3867dda5-7a95-11ea-a112-7f953848cf85.svg

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.

_images/6f72b252-5ee4-11ed-9155-0456e5e540ed.svg

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.

_images/DCE%3ACBCB3DDA-379D-11D9-9FA4-00C00C03A405.svg

01. Common Structure#

1. Root#

_images/DCE%3AE71AAA3E-45CE-11D7-B5CA-613352B2821F.svg

2. Templates#

Not implemented.

3. Namespaces#

_images/DCE%3AD2653A36-464C-11D7-AA08-1B85D5275D8A.svg

4. Types and Multiplicity#

_images/DCE%3ADD80D3EC-4A86-11D7-B086-133D836EF880.svg

5. Constraints#

_images/DCE%3A34764E0C-4A89-11D7-B08E-133D836EF880.svg

6. Dependencies#

_images/DCE%3A4E445586-50A4-11D7-807A-302CB4EF44FD.svg

02. Values#

1. Literals#

_images/3bf6ebec-e20d-11ea-b7ab-f5b4c130f24e.svg

2. Expressions#

_images/DCE%3A33061A3A-4A88-11D7-B08B-133D836EF880.svg

03. Classification#

1. Classifiers#

_images/DCE%3A90F60210-4B33-11D7-B391-02BBFE4396CE.svg

3. Features#

_images/DCE%3A539997D4-4B37-11D7-B391-02BBFE4396CE.svg

4. Properties#

_images/DCE%3A5198F474-4B3D-11D7-B391-02BBFE4396CE.svg

5. Operations#

_images/DCE%3A94ED9700-4B3A-11D7-B391-02BBFE4396CE.svg

7. Instances#

_images/DCE%3A039A7C82-4B32-11D7-B391-02BBFE4396CE.svg

04. Simple Classifiers#

1. Data Types#

_images/DCE%3A9661A9EE-509B-11D7-811E-AF5893A6470D.svg

3. Interfaces#

_images/DCE%3A2D47DA48-50A5-11D7-807A-302CB4EF44FD.svg

05. Structured Classifiers#

1. Structured Classifiers#

_images/DCE%3A3B936BE0-5FD2-11D9-89DE-0050040A5923.svg

2. Encapsulated Classifiers#

_images/DCE%3A647E10B2-8352-11DD-8EDA-000D936B094A.svg

3. Classes#

_images/b136e974-b123-11de-abbf-000d93868322.svg

4. Associations#

_images/70258172-e964-11ea-96dc-bf74f1f80424.svg

5. Components#

_images/DCE%3A4A9E3AF4-A419-11D8-B4C8-00061BC22919.svg

6. Collaborations#

_images/e48f0fae-4065-11e0-b382-0019d2b28af0.svg

06. Packaging#

1. Packages#

_images/DCE%3A2817DA5A-50A1-11D7-9F0D-F80F4B06507D.svg

2. Profiles#

_images/DCE%3AF4CAA7BA-97B9-11D8-9E36-00C00C03A405.svg

07. Common Behaviors#

1. Behaviors#

_images/DCE%3A30B2FAF8-6679-11D7-A84E-6C8643AD0CA4.svg

2. Events#

_images/d14d351a-40f1-11e0-9acb-0019d2b28af0.svg

08. State Machines#

1. Behavior State Machines#

_images/DCE%3AAEC6FCA4-4586-11DA-A04F-00123FE76EBE.svg

09. Activities#

1. Activities#

_images/DCE%3A3A957AF4-8325-11D8-8D1E-00C00C03A405.svg

2. Control Nodes#

_images/DCE%3A54022A8C-8325-11D8-8D1E-00C00C03A405.svg

3. Object Nodes#

_images/DCE%3A052880F2-8323-11D8-8D1E-00C00C03A405.svg

4. Executable Nodes#

_images/c6e0fa86-ea00-11ea-96dc-bf74f1f80424.svg

5. Activity Groups#

_images/DCE%3ADA3B1A4E-8405-11D8-82A2-7B88E55A3BEC.svg

10. Actions#

1. Actions#

_images/DCE%3A47C3C202-8325-11D8-8D1E-00C00C03A405.svg

2. Invocation Actions#

_images/5c9a2260-38fd-11e0-98cd-0021e9e5a3cd.svg

7. Structural Feature Actions#

_images/eca56402-3801-11e0-87bf-0021e9e5a3cd.svg

9. Accept Event Actions#

_images/bb8daa5a-3801-11e0-87bf-0021e9e5a3cd.svg

11. Interactions#

1. Interactions#

_images/DCE%3A8E6B58CC-3B13-11D9-83CE-A0BAF22E8A12.svg

2. Lifelines#

_images/DCE%3AEA8890EA-3B14-11D9-83CE-A0BAF22E8A12.svg

3. Messages#

_images/DCE%3A14C6D1BC-3B17-11D9-83CE-A0BAF22E8A12.svg

4. Occurrences#

_images/6cd26680-55b6-11ea-8c7d-fd01dce16f0a.svg

12. Use Cases#

UseCases#

_images/DCE%3A71EC6E5E-6690-11D7-A84E-6C8643AD0CA4.svg

13. Deployments#

1. Deployments#

_images/f4ad7aaa-b13d-11de-9fae-000d93868322.svg

2. Artifacts#

_images/DCE%3A1FD159C8-A41B-11D8-BCB9-00061BC22919.svg

3. Nodes#

_images/DCE%3A954E534C-A41C-11D8-BCB9-00061BC22919.svg

14. Information Flows#

_images/5485a3f0-ebea-11eb-8d68-2d4b211d5079.svg

A. Gaphor Specific Constructs#

1. Stereotype Applications#

_images/DCE%3A8B3C1FAA-B7DE-11D8-8AD1-9AC43285B64C.svg

B. Gaphor Profile#

In order to provide extra information to the diagram elements (mainly association ends), the Gaphor model has been extended with stereotypes.

_images/9ab5c2dc-3fe1-11de-8375-00224128e79d.svg

Systems Modeling Language#

Gaphor implements part of the SysML 1.6 specification.

_images/1bad943e-20e9-11ea-9209-e76c3117c943.svg

Activities#

_images/ac4b90fc-2140-11ea-ab0b-c72c0738acd2.svg

Allocations#

AllocatedActivityPartition#

_images/fb031740-2142-11ea-ab0b-c72c0738acd2.svg

Allocation#

_images/662db256-2142-11ea-ab0b-c72c0738acd2.svg

Blocks#

_images/47ca5c16-20e7-11ea-9209-e76c3117c943.svg

Adjunt and Classifier Behavior Properties#

_images/bfa2ba84-210b-11ea-ab0b-c72c0738acd2.svg

Bound References#

_images/e1591070-210a-11ea-ab0b-c72c0738acd2.svg

Connector Ends#

_images/3747bba4-210a-11ea-ab0b-c72c0738acd2.svg

Properties#

_images/541dcb16-2104-11ea-ab0b-c72c0738acd2.svg

Property Paths#

_images/4a1ef44a-2105-11ea-ab0b-c72c0738acd2.svg

Property-Specific Types#

_images/ac3ce272-210a-11ea-ab0b-c72c0738acd2.svg

Property Strings#

_images/f63737e4-2356-11ea-ab0b-c72c0738acd2.svg

Value Types#

_images/6d89dc70-2104-11ea-ab0b-c72c0738acd2.svg

ConstraintBlocks#

_images/2b70bf3e-2140-11ea-ab0b-c72c0738acd2.svg

Libraries#

_images/6ede6852-2145-11ea-ab0b-c72c0738acd2.svg

ModelElements#

_images/447ed65c-213e-11ea-ab0b-c72c0738acd2.svg

PortsAndFlows#

Actions on Nested Ports#

_images/dd8165c6-2112-11ea-ab0b-c72c0738acd2.svg

Port Stereotypes#

_images/d86faf8c-210f-11ea-ab0b-c72c0738acd2.svg

Property Value Change Events#

_images/aef5d558-2116-11ea-ab0b-c72c0738acd2.svg

Provided and Required Features#

_images/84aaf232-2117-11ea-ab0b-c72c0738acd2.svg

Item Flow#

_images/7a0704c6-5921-11ec-befa-0456e5e540ed.svg

Requirements#

_images/b354e9ca-20e1-11ea-9209-e76c3117c943.svg

Risk Analysis and Assessment Modeling Language#

Gaphor implements parts of the RAAML 1.0 specification.

_images/5921d168-235f-11ea-ab0b-c72c0738acd2.svg

Core#

Core Library/Any Situation#

_images/6111d8be-2364-11ea-ab0b-c72c0738acd2.svg

Core Profile/Controlling Measure#

_images/1636e506-5f7b-11eb-bf7c-d51178c71081.svg

Core Profile/Relevant To#

_images/8ee428ca-5f7a-11eb-bf7c-d51178c71081.svg

Core Profile/Situation#

_images/1f4246c8-5f7a-11eb-bf7c-d51178c71081.svg

Core Profile/Violates#

_images/de98b04c-5f7b-11eb-bf7c-d51178c71081.svg_images/76c26950-2b50-11ea-99a7-7d79dbbd423e.svg

General#

Basic Event#

_images/2ca042cc-2a7c-11ea-99a7-7d79dbbd423e.svg

General Concepts Library/Abstract Cause#

_images/9e1d24fa-2370-11ea-99a7-7d79dbbd423e.svg

General Concepts Library/Abstract Effect#

_images/2b69d716-2396-11ea-99a7-7d79dbbd423e.svg

General Concepts Library/Abstract Event#

_images/4e3fb614-2366-11ea-ab0b-c72c0738acd2.svg

General Concepts Library/Abstract Failure Mode#

_images/43a4a34e-2394-11ea-99a7-7d79dbbd423e.svg

General Concepts Library/Abstract Risk#

_images/62b87052-242b-11ea-99a7-7d79dbbd423e.svg

General Concepts Library/Activation#

_images/3789cb08-2398-11ea-99a7-7d79dbbd423e.svg

General Concepts Library/Cause#

_images/7a90a4f8-2370-11ea-99a7-7d79dbbd423e.svg

General Concepts Library/Dysfunctional Event#

_images/c2532de2-2370-11ea-99a7-7d79dbbd423e.svg

General Concepts Library/Effect#

_images/2fec63e8-2397-11ea-99a7-7d79dbbd423e.svg

General Concepts Library/Error Propagation#

_images/bcfa898e-2399-11ea-99a7-7d79dbbd423e.svg

General Concepts Library/Error Realization#

_images/4ca3e422-239a-11ea-99a7-7d79dbbd423e.svg

General Concepts Library/Harm Potential#

_images/b662935e-239a-11ea-99a7-7d79dbbd423e.svg

General Concepts Library/Hazard#

_images/ff0937c0-239a-11ea-99a7-7d79dbbd423e.svg

General Concepts Library/Scenario#

_images/9b1b2828-242a-11ea-99a7-7d79dbbd423e.svg

General Concepts Library/Undesired State#

_images/8b368f84-5614-11eb-a85e-18cf5efc6bb9.svg

General Concepts Profile/Detection#

_images/028a5afe-242d-11ea-99a7-7d79dbbd423e.svg

General Concepts Profile/Failure State#

_images/4b357e5e-242e-11ea-99a7-7d79dbbd423e.svg

General Concepts Profile/Mitigation#

_images/e885a252-242d-11ea-99a7-7d79dbbd423e.svg

General Concepts Profile/Prevention#

_images/74d658ba-242d-11ea-99a7-7d79dbbd423e.svg

General Concepts Profile/Recommendation#

_images/1d77da84-242e-11ea-99a7-7d79dbbd423e.svg

General Concepts Profile/Undeveloped#

_images/c92a9cd0-5480-11eb-a85e-18cf5efc6bb9.svg_images/d173abb6-2b50-11ea-99a7-7d79dbbd423e.svg

Methods#

FTA/FTA Library/Events/Basic Event#

_images/2ca042cc-2a7c-11ea-99a7-7d79dbbd423e.svg

FTA/FTA Library/Events/Conditional Event#

_images/a2210f70-2a7e-11ea-99a7-7d79dbbd423e.svg

FTA/FTA Library/Events/Dormant Event#

_images/fa2fc8c4-2a7d-11ea-99a7-7d79dbbd423e.svg

FTA/FTA Library/Events/Events#

_images/6c969142-69a5-11eb-9cb6-b14bb5bac2d1.svg

FTA/FTA Library/Events/Event#

_images/c5551376-2a72-11ea-99a7-7d79dbbd423e.svg

FTA/FTA Library/Events/House Event#

_images/24547c48-2a7f-11ea-99a7-7d79dbbd423e.svg

FTA/FTA Library/Events/Intermediate Event#

_images/6d7b2540-2a82-11ea-99a7-7d79dbbd423e.svg

FTA/FTA Library/Events/Top Event#

_images/a0b44e0a-2a82-11ea-99a7-7d79dbbd423e.svg

FTA/FTA Library/Events/Undeveloped Event#

_images/4a9d0538-2b0a-11ea-99a7-7d79dbbd423e.svg

FTA/FTA Library/Events/Zero Event#

_images/e09392d2-2a7e-11ea-99a7-7d79dbbd423e.svg

FTA/FTA Library/FTA Element#

_images/bcb9dfd8-2a6f-11ea-99a7-7d79dbbd423e.svg

FTA/FTA Library/FTA Library#

_images/b4220604-2a72-11ea-99a7-7d79dbbd423e.svg

FTA/FTA Library/FTA Tree#

_images/380fea2e-2a70-11ea-99a7-7d79dbbd423e.svg

FTA/FTA Library/Gates/AND#

_images/83c3bd96-2a80-11ea-99a7-7d79dbbd423e.svg

FTA/FTA Library/Gates/Gate#

_images/f6a2fc9a-2a7c-11ea-99a7-7d79dbbd423e.svg

FTA/FTA Library/Gates/INHIBIT#

_images/cccd82be-2a81-11ea-99a7-7d79dbbd423e.svg

FTA/FTA Library/Gates/MAJORITY_VOTE#

_images/07f18afc-2a82-11ea-99a7-7d79dbbd423e.svg

FTA/FTA Library/Gates/NOT#

_images/3b0f9366-2a82-11ea-99a7-7d79dbbd423e.svg

FTA/FTA Library/Gates/OR#

_images/0df0c900-2a81-11ea-99a7-7d79dbbd423e.svg

FTA/FTA Library/Gates/SEQ#

_images/3b992fbe-2a81-11ea-99a7-7d79dbbd423e.svg

FTA/FTA Library/Gates/XOR#

_images/8dde5e98-2a81-11ea-99a7-7d79dbbd423e.svg

FTA/FTA Profile/AND#

_images/83c3bd96-2a80-11ea-99a7-7d79dbbd423e.svg

FTA/FTA Profile/Conditional Event#

_images/a2210f70-2a7e-11ea-99a7-7d79dbbd423e.svg

FTA/FTA Profile/Dormant Event#

_images/fa2fc8c4-2a7d-11ea-99a7-7d79dbbd423e.svg

FTA/FTA Profile/Event#

_images/c5551376-2a72-11ea-99a7-7d79dbbd423e.svg

FTA/FTA Profile/Gate#

_images/f6a2fc9a-2a7c-11ea-99a7-7d79dbbd423e.svg

FTA/FTA Profile/House Event#

_images/24547c48-2a7f-11ea-99a7-7d79dbbd423e.svg

FTA/FTA Profile/INHIBIT#

_images/cccd82be-2a81-11ea-99a7-7d79dbbd423e.svg

FTA/FTA Profile/Intermediate Event#

_images/6d7b2540-2a82-11ea-99a7-7d79dbbd423e.svg

FTA/FTA Profile/MAJORITY_VOTE#

_images/07f18afc-2a82-11ea-99a7-7d79dbbd423e.svg

FTA/FTA Profile/NOT#

_images/3b0f9366-2a82-11ea-99a7-7d79dbbd423e.svg

FTA/FTA Profile/OR#

_images/0df0c900-2a81-11ea-99a7-7d79dbbd423e.svg

FTA/FTA Profile/SEQ#

_images/3b992fbe-2a81-11ea-99a7-7d79dbbd423e.svg

FTA/FTA Profile/Top Event#

_images/a0b44e0a-2a82-11ea-99a7-7d79dbbd423e.svg

FTA/FTA Profile/Transfer In#

_images/e1154abc-2a82-11ea-99a7-7d79dbbd423e.svg

FTA/FTA Profile/Transfer Out#

_images/0eacc392-2a83-11ea-99a7-7d79dbbd423e.svg

FTA/FTA Profile/Tree#

_images/96ed3524-2a70-11ea-99a7-7d79dbbd423e.svg

FTA/FTA Profile/XOR#

_images/8dde5e98-2a81-11ea-99a7-7d79dbbd423e.svg

FTA/FTA Profile/Zero Event#

_images/e09392d2-2a7e-11ea-99a7-7d79dbbd423e.svg

FTA/FTA#

_images/94a4c198-2b50-11ea-99a7-7d79dbbd423e.svg_images/b515fb22-2b50-11ea-99a7-7d79dbbd423e.svg

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.

_images/2e656718-6cae-11eb-aee1-750f3fed8beb.svg

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.Elements. 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:

class gaphor.abc.Service[fuente]#

Base interface for all services in Gaphor.

abstract shutdown() None[fuente]#

Apagar los servicios, liberar recursos.

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.

abstract close()[fuente]#

Close the UI component.

The component can decide to hide or destroy the UI components.

abstract open()[fuente]#

Create and display the UI components (windows).

shutdown()[fuente]#

Shut down this component.

It’s not supposed to be opened again.

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:

class gaphor.abc.ActionProvider[fuente]#

An action provider is a special service that provides actions via @action decorators on its methods (see gaphor/action.py).

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
  1. As stated before, a plugin should implement the Service interface. It also implements ActionProvider, saying it has some actions to be performed by the user.

  2. 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.

  3. All action defined in this service are registered.

  4. Each service has a shutdown() method. This allows the service to perform some cleanup when it’s shut down.

  5. 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.

shutdown() None[fuente]#

Apagar los servicios, liberar recursos.

subscribe(handler: Callable[[object], None]) None[fuente]#

Registrar un manejador.

Los manejadores se accionan (ejecutan) cuando se emiten eventos específicos a través del método handle().

unsubscribe(handler: Callable[[object], None]) None[fuente]#

Anula el registro de un manipulador previamente registrado.

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.

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 name: str#

Human-readable name of the modeling language.

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 item element.

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.

connect(handle: Handle, port: Port) bool[fuente]#

Connect to an element. Note that at this point the line may be connected to some other, or the same element. The connection at model level also still exists.

Returns True if a connection is established.

disconnect(handle: Handle) None[fuente]#

Disconnect model level connections.

get_connected(handle: Handle) Optional[Presentation[Element]][fuente]#

Get item connected to a handle.

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

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(). The lookup 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.

gaphor.diagram.group.ungroup(parent: Element, element: Element) bool#

Remove the grouping from an element. The function needs to check if the provided parent node is the right one.

gaphor.diagram.group.can_group(parent_type: Type[Element], element_or_type: Type[Element] | Element) bool#

This function tries to determine if grouping is possible, without actually performing a group operation. This is not 100% accurate.

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 accompanying Presentation.

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.

gaphor.diagram.deletable.deletable(element: Element) bool#

Determine if a model element can safely 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.

class gaphor.diagram.propertypages.PropertyPageBase[fuente]#

A property page which can display itself in a notebook.

abstract construct()[fuente]#

Create the page (Gtk.Widget) that belongs to the Property page.

Returns the page’s toplevel widget (Gtk.Widget).

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.

_images/a26e1ce5-0092-11eb-8f71-7fd0147881a5.svg

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#

  1. A Transaction object is created.

  2. TransactionBegin event is emitted.

  3. The UndoManager instantiates a new ActionStack 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#

  1. A TransactionCommit event is emitted

  2. The UndoManager closes and stores the transaction.

Failed Transaction#

  1. A TransactionRollback event is emitted.

  2. 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)