CommitGraphPane.java

  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. package org.eclipse.jgit.awtui;

  11. import java.awt.BasicStroke;
  12. import java.awt.Component;
  13. import java.awt.Graphics;
  14. import java.awt.Stroke;
  15. import java.text.DateFormat;
  16. import java.text.SimpleDateFormat;

  17. import javax.swing.JTable;
  18. import javax.swing.ListSelectionModel;
  19. import javax.swing.table.AbstractTableModel;
  20. import javax.swing.table.DefaultTableCellRenderer;
  21. import javax.swing.table.JTableHeader;
  22. import javax.swing.table.TableCellRenderer;
  23. import javax.swing.table.TableColumn;
  24. import javax.swing.table.TableColumnModel;
  25. import javax.swing.table.TableModel;

  26. import org.eclipse.jgit.awtui.SwingCommitList.SwingLane;
  27. import org.eclipse.jgit.lib.PersonIdent;
  28. import org.eclipse.jgit.revplot.PlotCommit;
  29. import org.eclipse.jgit.revplot.PlotCommitList;
  30. import org.eclipse.jgit.util.References;

  31. /**
  32.  * Draws a commit graph in a JTable.
  33.  * <p>
  34.  * This class is currently a very primitive commit visualization tool. It shows
  35.  * a table of 3 columns:
  36.  * <ol>
  37.  * <li>Commit graph and short message</li>
  38.  * <li>Author name and email address</li>
  39.  * <li>Author date and time</li>
  40.  * </ol>
  41.  */
  42. public class CommitGraphPane extends JTable {
  43.     private static final long serialVersionUID = 1L;

  44.     private final SwingCommitList allCommits;

  45.     /**
  46.      * Create a new empty panel.
  47.      */
  48.     public CommitGraphPane() {
  49.         allCommits = new SwingCommitList();
  50.         configureHeader();
  51.         setShowHorizontalLines(false);
  52.         setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
  53.         configureRowHeight();
  54.     }

  55.     private void configureRowHeight() {
  56.         int h = 0;
  57.         for (int i = 0; i<getColumnCount(); ++i) {
  58.             TableCellRenderer renderer = getDefaultRenderer(getColumnClass(i));
  59.             Component c = renderer.getTableCellRendererComponent(this,
  60.                     "ÅOj", false, false, 0, i); //$NON-NLS-1$
  61.             h = Math.max(h, c.getPreferredSize().height);
  62.         }
  63.         setRowHeight(h + getRowMargin());
  64.     }

  65.     /**
  66.      * Get the commit list this pane renders from.
  67.      *
  68.      * @return the list the caller must populate.
  69.      */
  70.     public PlotCommitList getCommitList() {
  71.         return allCommits;
  72.     }

  73.     /** {@inheritDoc} */
  74.     @Override
  75.     public void setModel(TableModel dataModel) {
  76.         if (dataModel != null && !(dataModel instanceof CommitTableModel))
  77.             throw new ClassCastException(UIText.get().mustBeSpecialTableModel);
  78.         super.setModel(dataModel);
  79.     }

  80.     /** {@inheritDoc} */
  81.     @Override
  82.     protected TableModel createDefaultDataModel() {
  83.         return new CommitTableModel();
  84.     }

  85.     private void configureHeader() {
  86.         final JTableHeader th = getTableHeader();
  87.         final TableColumnModel cols = th.getColumnModel();

  88.         final TableColumn graph = cols.getColumn(0);
  89.         final TableColumn author = cols.getColumn(1);
  90.         final TableColumn date = cols.getColumn(2);

  91.         graph.setHeaderValue(""); //$NON-NLS-1$
  92.         author.setHeaderValue(UIText.get().author);
  93.         date.setHeaderValue(UIText.get().date);

  94.         graph.setCellRenderer(new GraphCellRender());
  95.         author.setCellRenderer(new NameCellRender());
  96.         date.setCellRenderer(new DateCellRender());
  97.     }

  98.     class CommitTableModel extends AbstractTableModel {
  99.         private static final long serialVersionUID = 1L;

  100.         PlotCommit<SwingLane> lastCommit;

  101.         PersonIdent lastAuthor;

  102.         @Override
  103.         public int getColumnCount() {
  104.             return 3;
  105.         }

  106.         @Override
  107.         public int getRowCount() {
  108.             return allCommits != null ? allCommits.size() : 0;
  109.         }

  110.         @Override
  111.         public Object getValueAt(int rowIndex, int columnIndex) {
  112.             final PlotCommit<SwingLane> c = allCommits.get(rowIndex);
  113.             switch (columnIndex) {
  114.             case 0:
  115.                 return c;
  116.             case 1:
  117.                 return authorFor(c);
  118.             case 2:
  119.                 return authorFor(c);
  120.             default:
  121.                 return null;
  122.             }
  123.         }

  124.         PersonIdent authorFor(PlotCommit<SwingLane> c) {
  125.             if (!References.isSameObject(c, lastCommit)) {
  126.                 lastCommit = c;
  127.                 lastAuthor = c.getAuthorIdent();
  128.             }
  129.             return lastAuthor;
  130.         }
  131.     }

  132.     static class NameCellRender extends DefaultTableCellRenderer {
  133.         private static final long serialVersionUID = 1L;

  134.         @Override
  135.         public Component getTableCellRendererComponent(final JTable table,
  136.                 final Object value, final boolean isSelected,
  137.                 final boolean hasFocus, final int row, final int column) {
  138.             final PersonIdent pi = (PersonIdent) value;

  139.             final String valueStr;
  140.             if (pi != null)
  141.                 valueStr = pi.getName() + " <" + pi.getEmailAddress() + ">"; //$NON-NLS-1$ //$NON-NLS-2$
  142.             else
  143.                 valueStr = ""; //$NON-NLS-1$
  144.             return super.getTableCellRendererComponent(table, valueStr,
  145.                     isSelected, hasFocus, row, column);
  146.         }
  147.     }

  148.     static class DateCellRender extends DefaultTableCellRenderer {
  149.         private static final long serialVersionUID = 1L;

  150.         private final DateFormat fmt = new SimpleDateFormat(
  151.                 "yyyy-MM-dd HH:mm:ss"); //$NON-NLS-1$

  152.         @Override
  153.         public Component getTableCellRendererComponent(final JTable table,
  154.                 final Object value, final boolean isSelected,
  155.                 final boolean hasFocus, final int row, final int column) {
  156.             final PersonIdent pi = (PersonIdent) value;

  157.             final String valueStr;
  158.             if (pi != null)
  159.                 valueStr = fmt.format(pi.getWhen());
  160.             else
  161.                 valueStr = ""; //$NON-NLS-1$
  162.             return super.getTableCellRendererComponent(table, valueStr,
  163.                     isSelected, hasFocus, row, column);
  164.         }
  165.     }

  166.     static class GraphCellRender extends DefaultTableCellRenderer {
  167.         private static final long serialVersionUID = 1L;

  168.         private final AWTPlotRenderer renderer = new AWTPlotRenderer(this);

  169.         PlotCommit<SwingLane> commit;

  170.         @Override
  171.         @SuppressWarnings("unchecked")
  172.         public Component getTableCellRendererComponent(final JTable table,
  173.                 final Object value, final boolean isSelected,
  174.                 final boolean hasFocus, final int row, final int column) {
  175.             super.getTableCellRendererComponent(table, value, isSelected,
  176.                     hasFocus, row, column);
  177.             commit = (PlotCommit<SwingLane>) value;
  178.             return this;
  179.         }

  180.         @Override
  181.         protected void paintComponent(Graphics inputGraphics) {
  182.             if (inputGraphics == null)
  183.                 return;
  184.             renderer.paint(inputGraphics, commit);
  185.         }
  186.     }

  187.     static final Stroke[] strokeCache;

  188.     static {
  189.         strokeCache = new Stroke[4];
  190.         for (int i = 1; i < strokeCache.length; i++)
  191.             strokeCache[i] = new BasicStroke(i);
  192.     }

  193.     static Stroke stroke(int width) {
  194.         if (width < strokeCache.length)
  195.             return strokeCache[width];
  196.         return new BasicStroke(width);
  197.     }

  198. }