Creating module commands

In this section we will focus on the creation of commands. The commands behaviors, the Java code that do the job will be addressed in this section.

As for module, a command creation is a two step process : a declaration in module.xml and a Java class that extends DefaultModuleContextualCommand and redefines appropriate operations.

This section doesn’t address diagram command that appears in palettes of specialization of existing diagram. For more information on it, refer to creating a customized diagram.

Command declaration

A command is declared within the gui section of the module.xml file.

 1    <Gui>
 2        <Commands>
 3            <Command id="CreateTestCase" 
 4                label="%CreateTestCaseLabel" 
 5                image="res/icons/createTestCase.png"
 6                tooltip="%CreateTestCaseTooltip" 
 7                group=""
 8                modify-model="true"
 9                group-image="">
10                <Scope metaclass="Class" stereotype="JavaClass" />
11                <Handler class="org.modelio.junit.command.CreateTestCase" />
12            </Command>
13            ...
14        </Commands>
15        ...
16        <ContextualMenu>
17            <CommandRef refid="CreateTestCase"/>
18            ...
19        </ContextualMenu>
20    </Gui>

command

  • id: this field defines the logical name of the command. It will not be shown to the end-user and is only used internally as an identifier for the command;
  • label & tooltip: the name of the command as shown in Modelio gui and its associated tooltip. When these fields begin with % then it is a resource label that will be retrieved in the manifest property file (module*.properties);
  • image: a 16x16px image that will be displayed on the gui. It is optional if the command is in a popup menu and more than welcome if it is on toolbar or on property box. The image should be stored in resources/… (see §7.4.2);
  • group: is the group name of which the command belong. On contextual menu, the group will shown has a submenu between the module name and the command. When this field begins with % then it is a resource label that will be retrieved in the manifest property file (module.properties);
  • group-image: a 16x16px optional image that will be displayed in the contextual menu in front of the group name. The image should be stored in resources/… (see §7.4.2);
  • modify-model: if true, it means that the command won’t be available if one of the selected element is read-only (ie CMS locked, the presence of the red padlock in the explorer or locked because an edition operation is in progress). In our case, the value is false because we don’t want to create a test model on a read-only class.

scope

  • metaclass & stereotype: filter the availability of the command. The command will only be displayed if all the selected element types are a direct or indirect heir of metaclass value and have the requested stereotype. metaclass name can be found in Modelio metamodel user guide. In our case, the metaclass is “Class” because we want to create test cases for classes and it should have been stereotyped JavaClass because there is no point in adding a Junit testcase class to a non Java class.

handler

  • class: value is the name of the Java class that will be called when the command is invoked. This class should extend DefaultModuleContextualCommand class to be suitable for command activation.

contextual menu contribution

  • refid: indicates which command should appear in the contextual menu. In our case we decide to make the CreateTestCase command appear.

At this step of the process, the Create a test case command is created and configured but not ready to run.

Later, the only thing to add will be the implementation of the actionPerformed method on the CreateTestCase class to carry out the proper actions.

Command Java class

In this section, we will continue to create our “Create test case” command on the Java side.

A bit of theory: Contextual command filtering and graying

A contextual command will appear only under certain conditions defined by the parameters set for it in the XML declaration of the command (see §7.5.1).

This is a first level of command filtering, based on static data: kind of object and behavior for read-only objects. Although this checking is performed at runtime for each right-click event on a UML element, it is called static filtering because it is defined statically in module.xml.

A second level of command filtering, which is left completely to the module developer code, is also proposed by module commands. This second level of command filtering is called dynamic filtering as it is evaluated by running the module developer code. In practice, a dedicated accept() method that will be called by Modelio each time the Module command can be proposed has to be provided. The accept() method boolean returned value indicates whether or not the command has to be made available to the end-user.

This gives the module developer a means of dynamically checking conditions that could otherwise not be statically defined.

Commands that have passed both the active and dynamic filtering will be displayed, but can be inactive, grayed out.

Determining the graying of a command is also a two step process. First, static graying rules will be applied, and second, if the isActiveFor() method is defined, dynamic graying occurs.

Static graying rules are typically command declared to modify the model when the selected element is read-only.

Note that the dynamic filtering conditions (the developer’s coded filter) will not be evaluated (no call) if the command does not satisfy the static filtering criteria. The same rule applies for graying.

In short :

  • accept method is called to dynamically check if the command is visible;
  • isActiveFor method is called to dynamically check if the command is actionable or grayed out;
  • The order of check is : static filtering, dynamic filtering (accept), static graying and dynamic graying.

Writing command method

The next thing we have to do now is to complete the methods actionPerformed() and accept() with their implementation code.

The accept() method is called to validate the availability of the command in the current selection context. The current selection context is simply passed as the list of the currently selected elements.

For our example, let’s consider that the command accepts only one selected element.
The actionPerformed() command is called when the command is activated by the end-user. Its role is to perform the proper action. Thus, the code of this method is the action itself.

 1import java.util.List;
 2import org.modelio.vcore.smkernel.mapi.MObject;
 3import org.modelio.metamodel.uml.statik.Class;
 4import org.modelio.api.module.IModule;
 5import org.modelio.junit.command.TestCaseCreator;
 6import org.modelio.api.module.command.DefaultModuleCommandHandler;
 7
 8
 9public class CreateTestCase extends DefaultModuleCommandHandler {
10...
11    public boolean accept(List<MObject> selectedElements, IModule module) {
12        if (super.accept(selectedElements, module) == false) {
13            return false;
14        }
15        // Check that there is only one selected element
16        return selectedElements.size() == 1;
17    }
18
19    public void actionPerformed(List<MObject> selectedElements, IModule module) {
20        Class classToTest = (Class) selectedElements.get(0);
21        TestCaseCreator testCaseCreator = new TestCaseCreator();
22        testCaseCreator.createTestCase(classToTest, module);
23    }
24...
25}

That’s it!

Of course, you can see that the proposed actionPerformed() method only delegates the expected behavior to a TestCaseCreator object. This is explained by the fact that we need to pop up quite a rich and complicated GUI to fetch parameter values from the user before performing the intended action. Coding the complete GUI in the actionPerformed() method is not a recommended practice, which is why we choose to use an additional class to implement the “Create a Test Case” wizard feature.

Coding this graphical wizard is outside the scope of this document, as it would produce a lot of code that is more directly related to GUI development than to Module programming. However, note that this code can be standard SWT code without any particular problem.

What is important next for our example is that at some point, the Module will have to perform the real Test Case creation, and modify and update the test model.


<< Previous Index Next >>