I really like GEF's base architecture: The separation between Draw2D and GEF, the concepts of Tools, Requests, EditParts and EditPolicies. It helps you to find the component to change in order to implement a new feature quickly. The pictures in the GEF online help really help
Pecularities In some areas GEF appears to be kind of rusty. A whole bunch of relevant commercial products has been relying on it for years. Long term backward API compatibility has taken its toll. Some things definitely need a serious overhaul and often a better naming. I am very happy to hear that a 3.0 version is planned. Here is my wishlist for improvements:
- Make coordinates double by default. Integer coordinates often result in rendering glitches due to rounding errors and are not well suited for scaling.
- Add alpha channel (transparency) support.
- Revise scaling of fonts: Sometimes a label's bounds don't match its text's extend.
- Rename methods of the update mechanism. I am often confused about the semantics validate(), invalidate(), invalidateTree() or revalidate().
- Rectangular bounds are not well suited for round things like ellipses. Similar to that, clipping child figures only makes sense for Viewports but nothing else. The need of an invisible container figure for side affixed children is really an ugly workaround.
- Diagram layout does not take connection labels into account.
- Add support for curve connections.
- The feedback figures - the surrogates when a figure is moved or resized - seem to come from a time where hardware graphics acceleration was pure luxury. If you have nested edit parts you might have to reimplement the nested figure construction twice for nicer feedback.
- Using a bit less inheritance and more composition would be fine.
Mutable Geometric PrimitivesAs many other graphics frameworks, GEF code tries to create as little new objects as possible. Geometrical primitives such as points, dimensions and rectangles are therefore mutable and reused often. There are even things as a static Rectangle.SINGLETON for temporary calculation. This pretty much reminds me of good old C++. I am not sure whether such optimization is still necessary. It results in pretty unreadable code:
Point p = figure.getLocation();You see: As the semantics of the variable changes, it is no surprise you cannot find a more expressive name than p. In addition, you have to be very careful if you are dealing with a reference or a copy. Modifying a Translatable (once again bad name, as Dimension also implements this interface) directly can also circumvent an event mechanism. This is really error prone. I'd strongly advise to introduce immutable primitives.
// p is the location in local coordinates
// now p is in parent coordinates
Point q = p.add(p).scale(2):
// this will also modify p
Coordinate TransformationsThe way transformation between local, global and parent coordinates are handled is somehow unsuggestive. I've used various 2D and 3D scenegraph-based frameworks but I never got as confused with coordinates as in GEF. For example, if you have a ScalableLayeredPane showing some scaled content, its translateToAbsolute(Point) method will not take the scaling into account while translateToParent(Point) will.
Some Hints Starting with GEF from zero is hard. You will likely spend a serious amount of time debugging why your diagram doesn't show anything at all. Better copy some basic setup from one of the GEF examples. Here are my favorite pitfalls:
- missing minimum size on figure - figure does not show up at all in some layouts
- wrong coordinate system - figures don't appear where they should, somtimes in nirvana
- wrong layout manager, e.g. a plain XYLayout on a FreeformFigure - results in endless layout loop
- reusing a geometry element instead of making a copy - completely unpredictable editor behavior
- the default ChangeBoundsRequest does not take local coordinate systems into account