diva.canvas: code review, February 3rd, 1999
John Reekie, 20 Jul 2001
diva.canvas: code review, February 3rd, 1999
Preliminary notes
Code review of the mature parts of the Diva canvas.
This is the second of a series of reviews on the canvas code.
-
Moderator: neuendor
-
Scribe: yuhong
-
Author: johnr
-
Reader: neuendor
-
Reviewers:
Review started: 1:15pm
Review ended: 2:30pm
Review materials
This is a code review so the review materials are the source files as
listed below. The list is structured into groups, with each group
containing some pages from the design reference, followed by the list
of classes. Note that the pages from the design reference are not
under review, but are provided for context. The complete design
reference is here; a printable
(single file) version is here.
The source code is in the same zip
file as the previous review.
Figure sets and containers
and Transform contexts
- FigureSet.java
- FigureContainer.java
- ZList.java
- TransformContext.java
Figure classes
- AbstractFigure.java
- AbstractFigureContainer.java
- CompositeFigure.java
- FigureDecorator.java
Identified defects
- OverlayLayer: Document that no Z depth in OverlayLayer.
Done.
- OverlayLayer: The constructor with 0 argument should call the one
with 2 arguments.
It's only two lines of code, there's no need.
- OverlayLayer: FIXME in repaint() needs to be taken care of.
Fixed. Now if it doesn't have a BasicStroke it reverts to the
slow but general verison of this method.
- OverlayLayer: repaint(): Getting the damage region repaint is
wrong, won't get the right region.
Same fix as above.
- OverlayLayer: setVisible() should repaint.
Fixed. Also fixed in FigureLayer.
- AbstractFigure.getLayer(): should check if _parent is actually an
instance of Figure before casting and throw a run-time exception if
not.
It will throw a ClassCastException. I don't think there's any need
to check that the type of _parent is correct, as if it is not, then
whoever called setParent() had a bug, and that method is clearly
documented as "not for general use."
- AbstractFigure.repaint(): should document the role of this method
in derived classes.
I added
This default implementation
creates a damage region that is the same size as this figure's
bounding box, and forwards that to the parent. Subclasses only
need to override this method if they need to damage a region that
is different from the bounding box.
- AbstractFigure.setParent(): why is this method public if not
intended for public use?
So that classes that implement FigureContainer in other packages can
call it. I changed the last line of the comment to this: This
method is intended only for use by classes that implement
FigureContainer.
- FigureContainer.pick(): consider returning an Iterator or Set.
That's actually fairly difficult and expensive if it's done the way it
should be done (iterate all figures under the mouse even if in
different subtrees), so is not a fundamental operation. There is an
attempt at something that does this in CanvasUtilities but it won't
work. This is definitely something that is needed, but should be done
as a separate method somewhere else that uses
FigureContainer.figuresFromFront() to recursively find intersecting
figures, and then the client can filter them with hit().
- AbstractFigureContainer.decorate(): should issue better exception
message.
Fixed.
- AbstractFigureContainer.swapChild(): should the method name
starts with _ since it is protected?
No, the Diva convention is not to use underscores for
method names. There are actually a few methods that break this
convention, which appear to be used as a "this is kind of
weird so be careful with this one" flag. No change.
- AbstractFigureContainer.pick(): method out of order
(also in other clases, especially in FigureLayer.java)
Fixed in AbstractFigureContainer and FigureLayer.
- AbstractFigureContainer.swapChild(): The 2nd Figure must not be a
child, but not checked.
Not needed. I changed the comment to clarify:
Replace the first figure with the second. This is a hook
method for the decorate() and undecorate() methods, and should
not be called by other methods. Implementors can assume that
the first figure is a child of this container, and that the
second is not.
- AbstractFigureContainer.swapChild(): better name for this method?
I went with "replaceChild," unless anyone can think of a better
one that will have to do.
- AbstractFigureContainer.undecorate(): should issue better
exception message.
Fixed.
- CompositeFigure._children: There is no simple mechanism provided
by super class, so the comment needs work?
Deleted comment.
- CompositeFigure. The call to super() in the constructor is not necessary.
Deleted.
- CompositeFigure.add(): why cast to AbstractFigure?
Removed.
- CompositeFigure.contains(): why the comment says the
implementation is wrong, but still implemented in the wrong way?
Well, it's not wrong, it's just slower. I updated the
comment to say so. I'm a bit leery of changing it to
use if (child.getParent() != this) because that only
is correct if the pointers are set up correctly... I dunno,
somehow it seems to me that having the method do what it
says it does and providing a documented faster way is
better than hiding stuff.
- CompositeFigure.some methods taken an index can be removed.
See response to the same issue in the last review.
- CompositeFigure.getBounds(): not clear why a FIXME is there.
I replaced the FIXME with this comment
// This could be made faster by optimizing for orthogonal
// transforms. Since it's cached though, don't worry about it.
- CompositeFigure.getBounds()(?): should use validate(),
invalidate() methods.
There's only one variable being cached, and it isn't visible outside
this class. Adding validate() and invalidate() to do this
is overkill.
- CompositeFigure.paint(): the else{...} part should use
canvasUtility.transform().
Actually, I think I raised this issue. The code as it is
is correct.
- CompositeFigure.paint(): FIXME: need to be fixed (code should go back in.)
Fixed.
- CompositeFigure.pick(): not clear why a FIXME is there.
Removed.
- CompositeFigure.repaint(): better name for checkCacheValid()?
This issue is in DamageRegion, not CompositeFigure.
Maybe we could have a better name...
[FIXME]
- CompositeFigure.repaint(): why need to call checkCacheValid().
[FIXME]
- FigureDecorator.getFigureCount(): comment: when return 0? when 1?
Fixed comment.
- FigureDecorator.getContainer(): in the else{...} part, should not
assume the parent is a FigureContainer.
If the parent is not a FigureContainer, you have much
more serious problems than getting a run-time exception
here...
- FigureDecorator.getShape(): should call child.getShape().
Fixed.
- FigureDecorator.newInstance(): improve class comments.
[FIXME]
- FigureDecorator.newInstance(): better method name?
[FIXME]
- TransformContext._cacheValid: which data is cached?
[FIXME]
- TransformContext.checkCacheValid(): what happens if
TransformContext is not an ancestor?
[FIXME]
- TransformContext.checkCacheValid(): what is this supposed to do?
[FIXME]
- TransformContext.getInverseTransform(): how to do noninvertible
transforms?
[FIXME]
- TransformContext.getInverseTransform(): better document for _cacheValid flag and _inverseTransform.
[FIXME]
- TransformContext.constructor should check if the component is null.
[FIXME]
- TransformContext._version is an int, should it be a long? what happens if it rolls over?
[FIXME]
- TransformContext.. what happens if push() and pop() are not
called in the right order?
[FIXME]
- TransformContext.setTransform(): should make a copy of the
AffineTransform.
[FIXME]
Related issues
StructureFigure and subclasses could be explained better somewhere.
Concluding notes