xref: /JGit/org.eclipse.jgit.ui/src/org/eclipse/jgit/awtui/CommitGraphPane.java (revision 5c5f7c6b146b24f2bd4afae1902df85ad6e57ea3)
1 /*
2  * Copyright (C) 2008, Shawn O. Pearce <spearce@spearce.org> and others
3  *
4  * This program and the accompanying materials are made available under the
5  * terms of the Eclipse Distribution License v. 1.0 which is available at
6  * https://www.eclipse.org/org/documents/edl-v10.php.
7  *
8  * SPDX-License-Identifier: BSD-3-Clause
9  */
10 
11 package org.eclipse.jgit.awtui;
12 
13 import java.awt.BasicStroke;
14 import java.awt.Component;
15 import java.awt.Graphics;
16 import java.awt.Stroke;
17 import java.text.DateFormat;
18 import java.text.SimpleDateFormat;
19 
20 import javax.swing.JTable;
21 import javax.swing.ListSelectionModel;
22 import javax.swing.table.AbstractTableModel;
23 import javax.swing.table.DefaultTableCellRenderer;
24 import javax.swing.table.JTableHeader;
25 import javax.swing.table.TableCellRenderer;
26 import javax.swing.table.TableColumn;
27 import javax.swing.table.TableColumnModel;
28 import javax.swing.table.TableModel;
29 
30 import org.eclipse.jgit.awtui.SwingCommitList.SwingLane;
31 import org.eclipse.jgit.lib.PersonIdent;
32 import org.eclipse.jgit.revplot.PlotCommit;
33 import org.eclipse.jgit.revplot.PlotCommitList;
34 import org.eclipse.jgit.util.References;
35 
36 /**
37  * Draws a commit graph in a JTable.
38  * <p>
39  * This class is currently a very primitive commit visualization tool. It shows
40  * a table of 3 columns:
41  * <ol>
42  * <li>Commit graph and short message</li>
43  * <li>Author name and email address</li>
44  * <li>Author date and time</li>
45  * </ol>
46  */
47 public class CommitGraphPane extends JTable {
48 	private static final long serialVersionUID = 1L;
49 
50 	private final SwingCommitList allCommits;
51 
52 	/**
53 	 * Create a new empty panel.
54 	 */
CommitGraphPane()55 	public CommitGraphPane() {
56 		allCommits = new SwingCommitList();
57 		configureHeader();
58 		setShowHorizontalLines(false);
59 		setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
60 		configureRowHeight();
61 	}
62 
configureRowHeight()63 	private void configureRowHeight() {
64 		int h = 0;
65 		for (int i = 0; i<getColumnCount(); ++i) {
66 			TableCellRenderer renderer = getDefaultRenderer(getColumnClass(i));
67 			Component c = renderer.getTableCellRendererComponent(this,
68 					"ÅOj", false, false, 0, i); //$NON-NLS-1$
69 			h = Math.max(h, c.getPreferredSize().height);
70 		}
71 		setRowHeight(h + getRowMargin());
72 	}
73 
74 	/**
75 	 * Get the commit list this pane renders from.
76 	 *
77 	 * @return the list the caller must populate.
78 	 */
getCommitList()79 	public PlotCommitList getCommitList() {
80 		return allCommits;
81 	}
82 
83 	/** {@inheritDoc} */
84 	@Override
setModel(TableModel dataModel)85 	public void setModel(TableModel dataModel) {
86 		if (dataModel != null && !(dataModel instanceof CommitTableModel))
87 			throw new ClassCastException(UIText.get().mustBeSpecialTableModel);
88 		super.setModel(dataModel);
89 	}
90 
91 	/** {@inheritDoc} */
92 	@Override
createDefaultDataModel()93 	protected TableModel createDefaultDataModel() {
94 		return new CommitTableModel();
95 	}
96 
configureHeader()97 	private void configureHeader() {
98 		final JTableHeader th = getTableHeader();
99 		final TableColumnModel cols = th.getColumnModel();
100 
101 		final TableColumn graph = cols.getColumn(0);
102 		final TableColumn author = cols.getColumn(1);
103 		final TableColumn date = cols.getColumn(2);
104 
105 		graph.setHeaderValue(""); //$NON-NLS-1$
106 		author.setHeaderValue(UIText.get().author);
107 		date.setHeaderValue(UIText.get().date);
108 
109 		graph.setCellRenderer(new GraphCellRender());
110 		author.setCellRenderer(new NameCellRender());
111 		date.setCellRenderer(new DateCellRender());
112 	}
113 
114 	class CommitTableModel extends AbstractTableModel {
115 		private static final long serialVersionUID = 1L;
116 
117 		PlotCommit<SwingLane> lastCommit;
118 
119 		PersonIdent lastAuthor;
120 
121 		@Override
getColumnCount()122 		public int getColumnCount() {
123 			return 3;
124 		}
125 
126 		@Override
getRowCount()127 		public int getRowCount() {
128 			return allCommits != null ? allCommits.size() : 0;
129 		}
130 
131 		@Override
getValueAt(int rowIndex, int columnIndex)132 		public Object getValueAt(int rowIndex, int columnIndex) {
133 			final PlotCommit<SwingLane> c = allCommits.get(rowIndex);
134 			switch (columnIndex) {
135 			case 0:
136 				return c;
137 			case 1:
138 				return authorFor(c);
139 			case 2:
140 				return authorFor(c);
141 			default:
142 				return null;
143 			}
144 		}
145 
authorFor(PlotCommit<SwingLane> c)146 		PersonIdent authorFor(PlotCommit<SwingLane> c) {
147 			if (!References.isSameObject(c, lastCommit)) {
148 				lastCommit = c;
149 				lastAuthor = c.getAuthorIdent();
150 			}
151 			return lastAuthor;
152 		}
153 	}
154 
155 	static class NameCellRender extends DefaultTableCellRenderer {
156 		private static final long serialVersionUID = 1L;
157 
158 		@Override
getTableCellRendererComponent(final JTable table, final Object value, final boolean isSelected, final boolean hasFocus, final int row, final int column)159 		public Component getTableCellRendererComponent(final JTable table,
160 				final Object value, final boolean isSelected,
161 				final boolean hasFocus, final int row, final int column) {
162 			final PersonIdent pi = (PersonIdent) value;
163 
164 			final String valueStr;
165 			if (pi != null)
166 				valueStr = pi.getName() + " <" + pi.getEmailAddress() + ">"; //$NON-NLS-1$ //$NON-NLS-2$
167 			else
168 				valueStr = ""; //$NON-NLS-1$
169 			return super.getTableCellRendererComponent(table, valueStr,
170 					isSelected, hasFocus, row, column);
171 		}
172 	}
173 
174 	static class DateCellRender extends DefaultTableCellRenderer {
175 		private static final long serialVersionUID = 1L;
176 
177 		private final DateFormat fmt = new SimpleDateFormat(
178 				"yyyy-MM-dd HH:mm:ss"); //$NON-NLS-1$
179 
180 		@Override
getTableCellRendererComponent(final JTable table, final Object value, final boolean isSelected, final boolean hasFocus, final int row, final int column)181 		public Component getTableCellRendererComponent(final JTable table,
182 				final Object value, final boolean isSelected,
183 				final boolean hasFocus, final int row, final int column) {
184 			final PersonIdent pi = (PersonIdent) value;
185 
186 			final String valueStr;
187 			if (pi != null)
188 				valueStr = fmt.format(pi.getWhen());
189 			else
190 				valueStr = ""; //$NON-NLS-1$
191 			return super.getTableCellRendererComponent(table, valueStr,
192 					isSelected, hasFocus, row, column);
193 		}
194 	}
195 
196 	static class GraphCellRender extends DefaultTableCellRenderer {
197 		private static final long serialVersionUID = 1L;
198 
199 		private final AWTPlotRenderer renderer = new AWTPlotRenderer(this);
200 
201 		PlotCommit<SwingLane> commit;
202 
203 		@Override
204 		@SuppressWarnings("unchecked")
getTableCellRendererComponent(final JTable table, final Object value, final boolean isSelected, final boolean hasFocus, final int row, final int column)205 		public Component getTableCellRendererComponent(final JTable table,
206 				final Object value, final boolean isSelected,
207 				final boolean hasFocus, final int row, final int column) {
208 			super.getTableCellRendererComponent(table, value, isSelected,
209 					hasFocus, row, column);
210 			commit = (PlotCommit<SwingLane>) value;
211 			return this;
212 		}
213 
214 		@Override
paintComponent(Graphics inputGraphics)215 		protected void paintComponent(Graphics inputGraphics) {
216 			if (inputGraphics == null)
217 				return;
218 			renderer.paint(inputGraphics, commit);
219 		}
220 	}
221 
222 	static final Stroke[] strokeCache;
223 
224 	static {
225 		strokeCache = new Stroke[4];
226 		for (int i = 1; i < strokeCache.length; i++)
227 			strokeCache[i] = new BasicStroke(i);
228 	}
229 
stroke(int width)230 	static Stroke stroke(int width) {
231 		if (width < strokeCache.length)
232 			return strokeCache[width];
233 		return new BasicStroke(width);
234 	}
235 
236 }
237