2 * Copyright (C) 2008, Shawn O. Pearce <spearce@spearce.org>
6 * Redistribution and use in source and binary forms, with or
7 * without modification, are permitted provided that the following
10 * - Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
13 * - Redistributions in binary form must reproduce the above
14 * copyright notice, this list of conditions and the following
15 * disclaimer in the documentation and/or other materials provided
16 * with the distribution.
18 * - Neither the name of the Git Development Community nor the
19 * names of its contributors may be used to endorse or promote
20 * products derived from this software without specific prior
23 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
24 * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
25 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
26 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
28 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
29 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
30 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
31 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
32 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
33 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
34 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
35 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
38 package org
.spearce
.jgit
.awtui
;
40 import java
.awt
.BasicStroke
;
41 import java
.awt
.Color
;
42 import java
.awt
.Component
;
43 import java
.awt
.Graphics
;
44 import java
.awt
.Graphics2D
;
45 import java
.awt
.Polygon
;
46 import java
.awt
.Stroke
;
47 import java
.text
.DateFormat
;
48 import java
.text
.SimpleDateFormat
;
50 import javax
.swing
.JTable
;
51 import javax
.swing
.ListSelectionModel
;
52 import javax
.swing
.table
.AbstractTableModel
;
53 import javax
.swing
.table
.DefaultTableCellRenderer
;
54 import javax
.swing
.table
.JTableHeader
;
55 import javax
.swing
.table
.TableColumn
;
56 import javax
.swing
.table
.TableColumnModel
;
57 import javax
.swing
.table
.TableModel
;
59 import org
.spearce
.jgit
.awtui
.SwingCommitList
.SwingLane
;
60 import org
.spearce
.jgit
.lib
.PersonIdent
;
61 import org
.spearce
.jgit
.revplot
.AbstractPlotRenderer
;
62 import org
.spearce
.jgit
.revplot
.PlotCommit
;
63 import org
.spearce
.jgit
.revplot
.PlotCommitList
;
66 * Draws a commit graph in a JTable.
68 * This class is currently a very primitive commit visualization tool. It shows
69 * a table of 3 columns:
71 * <li>Commit graph and short message</li>
72 * <li>Author name and email address</li>
73 * <li>Author date and time</li>
76 public class CommitGraphPane
extends JTable
{
77 private static final long serialVersionUID
= 1L;
79 private final SwingCommitList allCommits
;
81 /** Create a new empty panel. */
82 public CommitGraphPane() {
83 allCommits
= new SwingCommitList();
85 setShowHorizontalLines(false);
87 setSelectionMode(ListSelectionModel
.SINGLE_SELECTION
);
91 * Get the commit list this pane renders from.
93 * @return the list the caller must populate.
95 public PlotCommitList
getCommitList() {
100 public void setModel(final TableModel dataModel
) {
101 if (dataModel
!= null && !(dataModel
instanceof CommitTableModel
))
102 throw new ClassCastException("Must be special table model.");
103 super.setModel(dataModel
);
107 protected TableModel
createDefaultDataModel() {
108 return new CommitTableModel();
111 private void configureHeader() {
112 final JTableHeader th
= getTableHeader();
113 final TableColumnModel cols
= th
.getColumnModel();
115 final TableColumn graph
= cols
.getColumn(0);
116 final TableColumn author
= cols
.getColumn(1);
117 final TableColumn date
= cols
.getColumn(2);
119 graph
.setHeaderValue("");
120 author
.setHeaderValue("Author");
121 date
.setHeaderValue("Date");
123 graph
.setCellRenderer(new GraphCellRender());
124 author
.setCellRenderer(new NameCellRender());
125 date
.setCellRenderer(new DateCellRender());
128 class CommitTableModel
extends AbstractTableModel
{
129 private static final long serialVersionUID
= 1L;
131 PlotCommit
<SwingLane
> lastCommit
;
133 PersonIdent lastAuthor
;
135 public int getColumnCount() {
139 public int getRowCount() {
140 return allCommits
!= null ? allCommits
.size() : 0;
143 public Object
getValueAt(final int rowIndex
, final int columnIndex
) {
144 final PlotCommit
<SwingLane
> c
= allCommits
.get(rowIndex
);
145 switch (columnIndex
) {
157 PersonIdent
authorFor(final PlotCommit
<SwingLane
> c
) {
158 if (c
!= lastCommit
) {
160 lastAuthor
= c
.getAuthorIdent();
166 class NameCellRender
extends DefaultTableCellRenderer
{
167 private static final long serialVersionUID
= 1L;
169 public Component
getTableCellRendererComponent(final JTable table
,
170 final Object value
, final boolean isSelected
,
171 final boolean hasFocus
, final int row
, final int column
) {
172 final PersonIdent pi
= (PersonIdent
) value
;
174 final String valueStr
;
176 valueStr
= pi
.getName() + " <" + pi
.getEmailAddress() + ">";
179 return super.getTableCellRendererComponent(table
, valueStr
,
180 isSelected
, hasFocus
, row
, column
);
184 class DateCellRender
extends DefaultTableCellRenderer
{
185 private static final long serialVersionUID
= 1L;
187 private final DateFormat fmt
= new SimpleDateFormat(
188 "yyyy-MM-dd HH:mm:ss");
190 public Component
getTableCellRendererComponent(final JTable table
,
191 final Object value
, final boolean isSelected
,
192 final boolean hasFocus
, final int row
, final int column
) {
193 final PersonIdent pi
= (PersonIdent
) value
;
195 final String valueStr
;
197 valueStr
= fmt
.format(pi
.getWhen());
200 return super.getTableCellRendererComponent(table
, valueStr
,
201 isSelected
, hasFocus
, row
, column
);
205 class GraphCellRender
extends DefaultTableCellRenderer
{
206 private static final long serialVersionUID
= 1L;
208 private final AWTPlotRenderer renderer
= new AWTPlotRenderer(this);
210 PlotCommit
<SwingLane
> commit
;
212 public Component
getTableCellRendererComponent(final JTable table
,
213 final Object value
, final boolean isSelected
,
214 final boolean hasFocus
, final int row
, final int column
) {
215 super.getTableCellRendererComponent(table
, value
, isSelected
,
216 hasFocus
, row
, column
);
217 commit
= (PlotCommit
<SwingLane
>) value
;
222 protected void paintComponent(final Graphics inputGraphics
) {
223 if (inputGraphics
== null)
225 renderer
.paint(inputGraphics
, commit
);
229 static final Stroke
[] strokeCache
;
232 strokeCache
= new Stroke
[4];
233 for (int i
= 1; i
< strokeCache
.length
; i
++)
234 strokeCache
[i
] = new BasicStroke(i
);
237 static Stroke
stroke(final int width
) {
238 if (width
< strokeCache
.length
)
239 return strokeCache
[width
];
240 return new BasicStroke(width
);
243 final class AWTPlotRenderer
extends AbstractPlotRenderer
<SwingLane
, Color
> {
245 final GraphCellRender cell
;
249 AWTPlotRenderer(final GraphCellRender c
) {
253 void paint(final Graphics in
, final PlotCommit
<SwingLane
> commit
) {
254 g
= (Graphics2D
) in
.create();
256 final int h
= cell
.getHeight();
257 g
.setColor(cell
.getBackground());
258 g
.fillRect(0, 0, cell
.getWidth(), h
);
260 paintCommit(commit
, h
);
268 protected void drawLine(final Color color
, int x1
, int y1
, int x2
,
273 } else if (x1
== x2
) {
279 g
.setStroke(stroke(width
));
280 g
.drawLine(x1
, y1
, x2
, y2
);
284 protected void drawCommitDot(final int x
, final int y
, final int w
,
286 g
.setColor(Color
.blue
);
287 g
.setStroke(strokeCache
[1]);
288 g
.fillOval(x
, y
, w
, h
);
289 g
.setColor(Color
.black
);
290 g
.drawOval(x
, y
, w
, h
);
294 protected void drawBoundaryDot(final int x
, final int y
, final int w
,
296 g
.setColor(cell
.getBackground());
297 g
.setStroke(strokeCache
[1]);
298 g
.fillOval(x
, y
, w
, h
);
299 g
.setColor(Color
.black
);
300 g
.drawOval(x
, y
, w
, h
);
304 protected void drawText(final String msg
, final int x
, final int y
) {
305 final int texty
= g
.getFontMetrics().getHeight()
306 - g
.getFontMetrics().getDescent();
307 g
.setColor(cell
.getForeground());
308 g
.drawString(msg
, x
, texty
- (cell
.getHeight() - y
* 2));
312 protected Color
laneColor(final SwingLane myLane
) {
313 return myLane
!= null ? myLane
.color
: Color
.black
;
316 void paintTriangleDown(final int cx
, final int y
, final int h
) {
318 final int tipY
= y
+ h
;
319 final int baseX1
= cx
- 10 / 2;
320 final int baseX2
= tipX
+ 10 / 2;
322 final Polygon triangle
= new Polygon();
323 triangle
.addPoint(tipX
, tipY
);
324 triangle
.addPoint(baseX1
, baseY
);
325 triangle
.addPoint(baseX2
, baseY
);
326 g
.fillPolygon(triangle
);
327 g
.drawPolygon(triangle
);