org.eclipse.jgit.revplot.AbstractPlotRenderer Maven / Gradle / Ivy
/*
* Copyright (C) 2008, Shawn O. Pearce
* and other copyright owners as documented in the project's IP log.
*
* This program and the accompanying materials are made available
* under the terms of the Eclipse Distribution License v1.0 which
* accompanies this distribution, is reproduced below, and is
* available at http://www.eclipse.org/org/documents/edl-v10.php
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or
* without modification, are permitted provided that the following
* conditions are met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials provided
* with the distribution.
*
* - Neither the name of the Eclipse Foundation, Inc. nor the
* names of its contributors may be used to endorse or promote
* products derived from this software without specific prior
* written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package org.eclipse.jgit.revplot;
import org.eclipse.jgit.lib.Ref;
import org.eclipse.jgit.revwalk.RevFlag;
/**
* Basic commit graph renderer for graphical user interfaces.
*
* Lanes are drawn as columns left-to-right in the graph, and the commit short
* message is drawn to the right of the lane lines for this cell. It is assumed
* that the commits are being drawn as rows of some sort of table.
*
* Client applications can subclass this implementation to provide the necessary
* drawing primitives required to display a commit graph. Most of the graph
* layout is handled by this class, allowing applications to implement only a
* handful of primitive stubs.
*
* This class is suitable for us within an AWT TableCellRenderer or within a SWT
* PaintListener registered on a Table instance. It is meant to rubber stamp the
* graphics necessary for one row of a plotted commit list.
*
* Subclasses should call {@link #paintCommit(PlotCommit, int)} after they have
* otherwise configured their instance to draw one commit into the current
* location.
*
* All drawing methods assume the coordinate space for the current commit's cell
* starts at (upper left corner is) 0,0. If this is not true (like say in SWT)
* the implementation must perform the cell offset computations within the
* various draw methods.
*
* @param
* type of lane being used by the application.
* @param
* type of color object used by the graphics library.
*/
public abstract class AbstractPlotRenderer {
private static final int LANE_WIDTH = 14;
private static final int LINE_WIDTH = 2;
private static final int LEFT_PAD = 2;
/**
* Paint one commit using the underlying graphics library.
*
* @param commit
* the commit to render in this cell. Must not be null.
* @param h
* total height (in pixels) of this cell.
*/
protected void paintCommit(final PlotCommit commit, final int h) {
final int dotSize = computeDotSize(h);
final TLane myLane = commit.getLane();
final int myLaneX = laneC(myLane);
final TColor myColor = laneColor(myLane);
int maxCenter = 0;
for (final TLane passingLane : (TLane[]) commit.passingLanes) {
final int cx = laneC(passingLane);
final TColor c = laneColor(passingLane);
drawLine(c, cx, 0, cx, h, LINE_WIDTH);
maxCenter = Math.max(maxCenter, cx);
}
final int nParent = commit.getParentCount();
for (int i = 0; i < nParent; i++) {
final PlotCommit p;
final TLane pLane;
final TColor pColor;
final int cx;
p = (PlotCommit) commit.getParent(i);
pLane = p.getLane();
if (pLane == null)
continue;
pColor = laneColor(pLane);
cx = laneC(pLane);
if (Math.abs(myLaneX - cx) > LANE_WIDTH) {
if (myLaneX < cx) {
final int ix = cx - LANE_WIDTH / 2;
drawLine(pColor, myLaneX, h / 2, ix, h / 2, LINE_WIDTH);
drawLine(pColor, ix, h / 2, cx, h, LINE_WIDTH);
} else {
final int ix = cx + LANE_WIDTH / 2;
drawLine(pColor, myLaneX, h / 2, ix, h / 2, LINE_WIDTH);
drawLine(pColor, ix, h / 2, cx, h, LINE_WIDTH);
}
} else {
drawLine(pColor, myLaneX, h / 2, cx, h, LINE_WIDTH);
}
maxCenter = Math.max(maxCenter, cx);
}
final int dotX = myLaneX - dotSize / 2 - 1;
final int dotY = (h - dotSize) / 2;
if (commit.getChildCount() > 0)
drawLine(myColor, myLaneX, 0, myLaneX, dotY, LINE_WIDTH);
if (commit.has(RevFlag.UNINTERESTING))
drawBoundaryDot(dotX, dotY, dotSize, dotSize);
else
drawCommitDot(dotX, dotY, dotSize, dotSize);
int textx = Math.max(maxCenter + LANE_WIDTH / 2, dotX + dotSize) + 8;
int n = commit.refs.length;
for (int i = 0; i < n; ++i) {
textx += drawLabel(textx + dotSize, h/2, commit.refs[i]);
}
final String msg = commit.getShortMessage();
drawText(msg, textx + dotSize + n*2, h / 2);
}
/**
* Draw a decoration for the Ref ref at x,y
*
* @param x
* left
* @param y
* top
* @param ref
* A peeled ref
* @return width of label in pixels
*/
protected abstract int drawLabel(int x, int y, Ref ref);
private int computeDotSize(final int h) {
int d = (int) (Math.min(h, LANE_WIDTH) * 0.50f);
d += (d & 1);
return d;
}
/**
* Obtain the color reference used to paint this lane.
*
* Colors returned by this method will be passed to the other drawing
* primitives, so the color returned should be application specific.
*
* If a null lane is supplied the return value must still be acceptable to a
* drawing method. Usually this means the implementation should return a
* default color.
*
* @param myLane
* the current lane. May be null.
* @return graphics specific color reference. Must be a valid color.
*/
protected abstract TColor laneColor(TLane myLane);
/**
* Draw a single line within this cell.
*
* @param color
* the color to use while drawing the line.
* @param x1
* starting X coordinate, 0 based.
* @param y1
* starting Y coordinate, 0 based.
* @param x2
* ending X coordinate, 0 based.
* @param y2
* ending Y coordinate, 0 based.
* @param width
* number of pixels wide for the line. Always at least 1.
*/
protected abstract void drawLine(TColor color, int x1, int y1, int x2,
int y2, int width);
/**
* Draw a single commit dot.
*
* Usually the commit dot is a filled oval in blue, then a drawn oval in
* black, using the same coordinates for both operations.
*
* @param x
* upper left of the oval's bounding box.
* @param y
* upper left of the oval's bounding box.
* @param w
* width of the oval's bounding box.
* @param h
* height of the oval's bounding box.
*/
protected abstract void drawCommitDot(int x, int y, int w, int h);
/**
* Draw a single boundary commit (aka uninteresting commit) dot.
*
* Usually a boundary commit dot is a light gray oval with a white center.
*
* @param x
* upper left of the oval's bounding box.
* @param y
* upper left of the oval's bounding box.
* @param w
* width of the oval's bounding box.
* @param h
* height of the oval's bounding box.
*/
protected abstract void drawBoundaryDot(int x, int y, int w, int h);
/**
* Draw a single line of text.
*
* The font and colors used to render the text are left up to the
* implementation.
*
* @param msg
* the text to draw. Does not contain LFs.
* @param x
* first pixel from the left that the text can be drawn at.
* Character data must not appear before this position.
* @param y
* pixel coordinate of the centerline of the text.
* Implementations must adjust this coordinate to account for the
* way their implementation handles font rendering.
*/
protected abstract void drawText(String msg, int x, int y);
private int laneX(final PlotLane myLane) {
final int p = myLane != null ? myLane.getPosition() : 0;
return LEFT_PAD + LANE_WIDTH * p;
}
private int laneC(final PlotLane myLane) {
return laneX(myLane) + LANE_WIDTH / 2;
}
}