5.3. Diagrams

Purpose - to keep the information of objects in diagrams and to generate a graphical view. The contents of the diagrams and also the Uml elements that are represented are modifiable from the diagrams. TODO: Notation!

The Diagrams are be located in org.argouml.uml.diagram.

The Diagrams is a View subsystem. Section 4.5, “View and Control subsystems”.

The Diagrams are depending on the Model subsystem and the GUI framework.

5.3.1. Multi editor pane

The multi editor pane is the pane with the diagram editor in it. Normally it is placed in the upper right corner of the application. One of the feature requests is to make the pane dockable so maybe it won't be there in the future.

The multi editor pane consists of tabs that hold editors as you can see in the class diagram.

At the moment there is only one editor tab in place. This is the TabDiagram that shows an UMLDiagram, the target.

The TabDiagram is spawn-able. This means that the user can double click the tab and the diagram will spawn as a separate window.

The target of the MultiEditorPane is set via the setTarget method of the pane. This method is called by the setTarget method of the ProjectBrowser. The pane's setTarget method will call each setTarget method of each tab that is an instance of TabModelTarget. Besides setting the target of the tabs, the setTarget method also calls MultiEditorPane.select(Object o). This selects the new target on a tab. This probably belongs in the setTarget method of the individual tabs and diagrams but that's how it's implemented at the moment.

5.3.1.1. How do I ...?

  • ...add a new tab to the MultiEditorPane?

    Create a new class that's a child of JPanel and put the following line in argo.ini:

    multi:	fully classified name of new tab class
    

5.3.2. How do I add a new element to a diagram?

To add a new element to a diagram, two main things have to be done.

  1. Create new Fig classes to represent the element on the diagram and add them to the graph model (org.argouml.uml.diagram.xxxx.XxxxDiagramGraphModel.java) and renderer (org.argouml.uml.diagram.xxxx.ui.XxxxDiagramRenderer.java).

  2. Create a new property panel class that will be displayed in the property tab window on the details pane. This is described in Section 5.4, “Property panels”.

Throughout we shall use the example of adding the UML Extend relationship to a use case diagram. This allows two Use Cases to be joined by a dotted arrow labeled «extend» to show that one extends the behavior of the other.

The classes involved in this particular example have all been well commented and have full Javadoc descriptions, to help when examining the code. You will need to read the description here in conjunction with looking at the code.

5.3.3. How to add a new Fig

The new item must be added to the tool-bar. Both the graph model and diagram renderer for the diagram will need modifying for any new fig object.

5.3.3.1. Adding to the tool-bar

Find the diagram object in uml/diagram/XXXX/ui/UMLYYYYDiagram.java, where XXXX is the diagram type (lower case) and YYYY the diagram type (bumpy caps). For example uml/diagram/use_case/ui/UMLUseCaseDiagram.java. This will be a subclass of UMLDiagram (in uml/diagram/ui/UMLDiagram.java).

Each tool-bar action is declared as a protected static field of class Action, initiated as a new CmdCreateNode (for nodal UML elements) or a new CmdSetMode (for behavior, or creation of line UML elements). These classes are part of the GEF library.

The common ones (select, broom, graphic annotations) are inherited from UMLDiagram, the diagram specific ones in the class itself. For example in UMLUseCaseDiagram.java we have the following for creating Use Case nodes.

protected static Action _actionUseCase =
    new CmdCreateNode(ModelFacade.USE_CASE, "UseCase");

The first argument is the class of the node to create from NSUML, the second a textual tool tip.

For creating associations we have:

protected static Action _actionAssoc =
      new CmdSetMode(ModeCreatePolyEdge.class,
	   	     "edgeClass", MAssociationImpl.class,
		     "Association");

The first argument is a GEF class that defines the type of behavior wanted (in this case creating a poly-edge). The second and third arguments are a named parameter used by ModeCreatePolyEdge ("edgeClass") and its value (MAssociationImpl.class). The final argument is a tooltip.

The tool-bar is actually created by defining a method, initToolBar() which adds the tools in turn to the tool-bar (a protected member named _toolBar).

The default constructor for the diagram is declared private, since it must not be called directly. The desired constructor takes a name-space as an argument, and sets up a graph model (UseCaseDiagramGraphModel), layer perspective and renderer (UseCaseDigramRenderer) for nodes and edges.

5.3.3.2. Changing the graph model

The graph model is the bridge between the UML meta-model representation of the design and the graph model of GEF. They are found in the parent directory of the corresponding diagram class, and have the general name YYYYDiagramGraphModel.java, where YYYY is the diagram name in bumpy caps. For example the use case diagram graph model is in uml/diagram/use_case/UseCaseDiagramGraphModel.java

The graph model is defined as UMLMutableGraphSupport, a child of the GEF class MutableGraphSupport, and should implement MutableGraphModel (GEF).

5.3.3.3. Changing the renderer

The renderer is responsible for creating graphic figs as required on the diagram. It is found in the same directory of the corresponding diagram class, and has the general name YYYYDiagramRenderer.java, where YYYY is the diagram name in bumpy caps. For example the use case diagram graph model is in uml/diagram/use_case/ui/UseCaseDiagramRenderer.java

This provides two routines, getFigNodeFor(), which provides a fig object to represent a given NSUML node object and getFigEdgeFor(), which provides a fig object to represent a given NSUML edge object.

In our example, we must extend getFigEdgeFor() so it can handle NSUML MExtend objects (producing a FigExtend).

5.3.3.4. Creating a new Fig (explanation 1)

New objects that are to appear on a diagram will require new Fig classes to represent them. In our example we have created FigExtend. They are placed in the same directory as the diagram that uses them.

The implementation must provide constructors for both a generic fig, and one representing a specific NSUML object. It should provide a setFig() method to set a particular figure as the representation. It should provide a method canEdit() to indicate whether the Fig can be edited. It should provide an event handler modelChanged() to cope with advice that the model has changed.

5.3.3.5. Creating a new Fig (explanation 2)

Assuming you have your model element already defined in the model and your PropPanel for that model element you should make the Fig class.

  1. For nodes, that are Figs that are enclosed figures like FigClass, extend from FigNodeModelElement. For edges, that are lines like FigAssociation, extend from FigEdgeModelElement. The name of the Fig has to start with (yes indeed) Fig. The rest of the name should be equal to the model element name.

  2. Create a default constructor in the Fig. In this default constructor the drawing of the actual figure is done. Here you draw the lines and text fields. See FigClass and FigAssociation for an example of this.

  3. Create a constructor FigMyModelelement(Object owner). Set the owner in this method by calling setOwner. Make a method setOwner that overrides it's super. Let the method call it's super. Set all attributes of the Fig with data from it's owner in this setOwner method. See setOwner of FigAssociation for an example.

  4. Create an overridden method protected void modelChanged(). This method must be called (and is if you implement the fig correctly) if the owner changes. In this method you update the fig if the model is changed. See FigAssociation and FigClass for an example.

  5. If you have text that can be edited, override the method textEdited(FigText text). In this method the edited text is parsed. If the parsing is simple and not Notation specific, just do it in textEdited. But for most cases: delegate to ParserDisplay. See the method parseAttribute in ParserDisplay for an example. Stick to the Notation you are using to have the right parsing scheme. There is work to be done here but please don't make it an even bigger mess :)

  6. Make an Action that can be called from the GUI. If you are lucky, you just can use CmdCreateNode. See for examples UMLClassDiagram of using CmdCreateNode.

  7. Adapt the method canAddEdge(Object o) on subclasses of GraphModel if you are building an edge so it will return true if the edge may be added to the subclass. Subclasses are for example ClassDiagramGraphModel and UseCaseDiagramGraphModel. If you are building a node, adapt canAddNode(Object o).

  8. Adapt the method getFigEdgeFor on implementors of GraphEdgeRenderer if you are implementing an edge so it will return the correct FigEdge for your object. If you are implementing a node, adapt the method getFigNodeFor on implementors of GraphNodeRenderer. In ArgoUML classes like ClassDiagramRenderer implement these interfaces.

  9. Add an image file for the buttons to the resource directory org/argouml/Images. This image file must be of GIF format and have a drawing of the button image to be used in itself. This image is also used on the PropPanel. The name of the Image file should be model element.gif

  10. Add buttons to the action you created on those places in the GUI that have a need for it. This should be at least the button bar in each diagram where you can draw your model element. Probably the parent of your model element (e.g. class in case of operation) will want a button too, so add it to the PropPanel of the parent. In case of the diagrams, add it in UMLdiagram.java, so in UMLClassDiagram if it belongs there. In case of the PropPanels, most of them don't use actions, they implement them directly as methods in the PropPanel themselves. Please don't do that but use an action so we have one place of definition.