AbstractPlotRenderer.java
- /*
- * Copyright (C) 2008, 2014 Shawn O. Pearce <spearce@spearce.org> and others
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Distribution License v. 1.0 which is available at
- * https://www.eclipse.org/org/documents/edl-v10.php.
- *
- * SPDX-License-Identifier: BSD-3-Clause
- */
- 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.
- * <p>
- * 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.
- * <p>
- * 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.
- * <p>
- * 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.
- * <p>
- * Subclasses should call {@link #paintCommit(PlotCommit, int)} after they have
- * otherwise configured their instance to draw one commit into the current
- * location.
- * <p>
- * 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 <TLane>
- * type of lane being used by the application.
- * @param <TColor>
- * type of color object used by the graphics library.
- */
- public abstract class AbstractPlotRenderer<TLane extends PlotLane, TColor> {
- 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.
- */
- @SuppressWarnings("unchecked")
- protected void paintCommit(PlotCommit<TLane> commit, int h) {
- final int dotSize = computeDotSize(h);
- final TLane myLane = commit.getLane();
- final int myLaneX = laneC(myLane);
- final TColor myColor = laneColor(myLane);
- int maxCenter = myLaneX;
- for (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 dotX = myLaneX - dotSize / 2 - 1;
- final int dotY = (h - dotSize) / 2;
- final int nParent = commit.getParentCount();
- if (nParent > 0) {
- drawLine(myColor, myLaneX, h, myLaneX, (h + dotSize) / 2,
- LINE_WIDTH);
- for (PlotLane mergingLane : commit.mergingLanes) {
- final TLane pLane = (TLane) mergingLane;
- final TColor pColor = laneColor(pLane);
- final int cx = laneC(pLane);
- if (Math.abs(myLaneX - cx) > LANE_WIDTH) {
- final int ix;
- if (myLaneX < cx) {
- ix = cx - LANE_WIDTH / 2;
- } else {
- 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);
- }
- }
- if (commit.getChildCount() > 0) {
- for (PlotLane forkingOffLane : commit.forkingOffLanes) {
- final TLane childLane = (TLane) forkingOffLane;
- final TColor cColor = laneColor(childLane);
- final int cx = laneC(childLane);
- if (Math.abs(myLaneX - cx) > LANE_WIDTH) {
- final int ix;
- if (myLaneX < cx) {
- ix = cx - LANE_WIDTH / 2;
- } else {
- ix = cx + LANE_WIDTH / 2;
- }
- drawLine(cColor, myLaneX, h / 2, ix, h / 2, LINE_WIDTH);
- drawLine(cColor, ix, h / 2, cx, 0, LINE_WIDTH);
- } else {
- drawLine(cColor, myLaneX, h / 2, cx, 0, LINE_WIDTH);
- }
- maxCenter = Math.max(maxCenter, cx);
- }
- int nonForkingChildren = commit.getChildCount()
- - commit.forkingOffLanes.length;
- if (nonForkingChildren > 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, h);
- }
- /**
- * 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 static int computeDotSize(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.
- * <p>
- * Colors returned by this method will be passed to the other drawing
- * primitives, so the color returned should be application specific.
- * <p>
- * 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.
- * <p>
- * 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.
- * <p>
- * 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.
- * <p>
- * 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 baseline 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 static int laneX(PlotLane myLane) {
- final int p = myLane != null ? myLane.getPosition() : 0;
- return LEFT_PAD + LANE_WIDTH * p;
- }
- private static int laneC(PlotLane myLane) {
- return laneX(myLane) + LANE_WIDTH / 2;
- }
- }