| Version 3.4.4 |
| Working with the Eclipse Graphical Editing Framework (GEF) |
The Graphical Editing Framework (GEF) is a set
of Eclipse plugins for creating editors that support visual editing of arbitrary models.
This framework is very popular and QF-Test has supported recording and playback of GEF
items for a long time ago (since about version 2.2). It is also a good example for the
power of the ItemResolver concept (see section 39.2),
because the gef Jython module contains an implementation of just that
interface. In older QF-Test versions you had to import the gef module
explicitly with the help of a script node, but now this is done automatically.
The gef module can deal with GEF editors at a generic level, even
supporting several editors at once. However, there are limits to what can be
determined automatically. Depending on the underlying model classes, there might still
remain some work for you: Implementing custom resolvers to provide useful names and
values for your items.
| Recording GEF items |
The following paragraphs refer to the GEF Shapes example. It allows you to draw
rectangles, ellipses, and connections between those figures on the
FigureCanvas. The type of figure to be drawn is chosen from a palette
which is also part of the GEF editor. Suppose you have drawn a rectangle on the
canvas and then record a mouse click on that figure. Without the GEF resolver you will
record a 'Mouse event' node for the canvas component. The click position is
relative to the canvas and there is no clue at all that it was the rectangle figure
you clicked at. In contrast, with the GEF resolver installed the recording gets
targeted at an item of the canvas:
canvas@/ShapesDiagram\\\@1e1968d/Rectangle 16329001
You can see from the path-like index that you clicked on a 'Rectangle' which itself is
part of a 'ShapesDiagram'. This item index is not really beautiful. Even worse, it is
completely useless. But why? Both numbers contained in the index are hash code values
which will change when you restart your application and reopen the saved drawing.
Consequently, when trying to replay that mouse click, you will run into an
IndexNotFoundException.
If you are lucky, your GEF application comes with proper item names giving an index like
/ShapesDiagram/My blue rectangle
If not, there are three options:
/0/1 tells nothing about an item.
toString() method of the item's model. It
would make live easy for you, but only if the developers are cooperative.
ItemNameResolver2. This is the tough course - and
unfortunately the most likely scenario. It is covered in the next section.
| Implementing a GEF ItemNameResolver2 |
You have seen in the last section that the items in the GEF Shapes example do not
have useful names by default. As stated in section 39.1, an
ItemNameResolver2 is the hook to change or provide names for items.
To get started - be it the Shapes example or your own GEF application - insert a new Jython 'SUT script' in the 'Extras' node with the following code:
|
|
|
|||
|
| Example 39.12: Get started with a GEF ItemNameResolver2 | |||
To ease the installation of the resolver we use the resolvers module
described in subsection 39.1.10. The resolver gets registered for the
FigureCanvas class where the items reside. As mentioned above, what
QF-Test does by default is providing item.getModel().toString() as item
name. This default value is supplied as the last argument to our function
getItemName(). Now run the script, press the record button and then simply
move the mouse over your figures on the canvas - supposing you have created some of
them previously. Note that this first resolver implementation does nothing but print
out out some information into the terminal, something like
name: Rectangle 16329001
item: org.eclipse.gef.examples.shapes.parts.ShapeEditPart
model: org.eclipse.gef.examples.shapes.model.RectangularShape
The question is now: Does the model of the GEF EditPart provide any
property that might be used as name for the item? The answer in the case of the GEF
Shapes example is "No", and hopefully you are in a better situation with your
application. To find out insert a line
print dir(model)
in the getItemName() function and run the script again. Now you will also
see the methods of the model when moving the mouse over the items in record mode. With
a bit of luck you will find methods like getName() or
getLabel() and can create a resolver like this:
|
|
|
|||
|
| Example 39.13: A simple ItemNameResolver2 | |||
Let's go back to the GEF Shapes example where we don't have such useful methods. Only geometry information is available for the shapes and that is not really helpful. At least we can distinguish between rectangles and ellipses. To make the item names unique we simply add a child index as shown in the following resolver:
|
|
|
|||
|
| Example 39.14: An ItemNameResolver2 for GEF Shapes | |||
With this resolver in place, the item index for a rectangle becomes
/Diagram/Rectangle 1
where the trailing number is the child index of the item. The above implementation
also provides names for the connections by calling getItemName()
recursively for the source and the target item of the connection. Checking the types
with ResolverRegistry.isInstance (see subsection 39.1.11) will save you the need to import the GEF classes,
something that is not trivial.
Once your resolver is working fine you should move the script into your 'Setup' sequence right behind the 'Wait for client to connect' node. This way the resolver will be registered automatically when the SUT starts.
| Implementing a GEF ItemValueResolver2 |
We have mentioned that a GEF editor normally consists of two parts. Having so far
focused on the canvas where you draw the figures, we now take a closer look at the
palette where you select the kind of figure to draw ('Rectangle', 'Ellipse' or
'Connection'). Its entries look like tool buttons but actually the palette is a
FigureCanvas too. You will be glad to know that this one works out of the
box, that is without implementing an ItemNameResolver2. When you click
for example on the 'Rectangle' button, QF-Test recognizes a
/Palette Root/Palette Container (Shapes)/Palette Entry (Rectangle)
item. What will happen if you record a check for the 'Object value' for this button? You may expect to get the button text 'Rectangle' but in fact the value of this item is
Palette Entry (Rectangle)
The reason is that by default name and value of an item are the same. To alter this
behavior and provide customized values you need to implement an
ItemValueResolver2. This interface is very similar to the
ItemNameResolver2 above. For the palette we can code the
following one:
|
|
|
|||
|
| Example 39.15: An ItemValueResolver2 for the GEF Shapes palette | |||
The method getLabel() returns the text as displayed in the palette.
| Last update: 01/27/2012 Copyright © 1999-2012 Quality First Software GmbH |