package gitj.ui; import java.awt.BorderLayout; import java.awt.Color; import java.awt.Component; import java.awt.Dimension; import java.awt.Font; import java.awt.Rectangle; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import javax.swing.ImageIcon; import javax.swing.JLabel; import javax.swing.JMenuItem; import javax.swing.JPanel; import javax.swing.JPopupMenu; import javax.swing.JScrollPane; import javax.swing.JTable; import javax.swing.JToolBar; import javax.swing.table.DefaultTableCellRenderer; import javax.swing.table.DefaultTableModel; import git.Branch; import git.Commit; import git.Repository; import git.Tag; import gitj.Main; import gitj.ui.components.BranchComboBox; import gitj.ui.components.ICommitClickListener; import gitj.ui.dialogs.DialogArchive; import gitj.ui.dialogs.DialogReset; import gitj.utils.DialogUtils; import gitj.utils.IOUtils; import gitj.utils.IconGenerator; import gitj.utils.MenuItemUtils; @SuppressWarnings("serial") public class CommitListPanel extends JScrollPane { public static final Color TABLE_SELECTED = new Color(51, 153, 255); public static final Color TABLE_GRAY = new Color(240, 240, 240); public static final String COLUMN_GRAPH = "Graph"; public static final String COLUMN_DESCRIPTION = "Description"; public static final String COLUMN_DATE = "Date"; public static final String COLUMN_AUTHOR = "Author"; public static final String COLUMN_COMMIT = "Commit"; private List<ICommitClickListener> listeners = new ArrayList<ICommitClickListener>(); private Repository repository; private List<Commit> commits; private JTable table; private CommitTableModel model; private BranchComboBox branchBox; private JToolBar toolBar; private JPanel panel; public CommitListPanel(Repository repo) throws Exception { this.repository = repo; this.commits = repo.getCommits(); this.model = new CommitTableModel(); this.table = new JTable(model); super.getVerticalScrollBar().setUnitIncrement(10); toolBar = new JToolBar(); toolBar.setFloatable(false); branchBox = new BranchComboBox(this, repo); branchBox.reload(); toolBar.add(branchBox); table.setDefaultRenderer(Object.class, new CommitRenderer()); table.setRowHeight(20); table.setShowGrid(false); table.setFillsViewportHeight(true); table.setIntercellSpacing(new Dimension(0, 0)); panel = new JPanel(); panel.setLayout(new BorderLayout(0, 0)); panel.add(table, BorderLayout.SOUTH); panel.add(toolBar, BorderLayout.NORTH); super.setViewportView(panel); table.addMouseListener(new MouseAdapter() { @Override public void mouseClicked(MouseEvent evt) { int row = table.getSelectedRow(); if (row != -1) { TableEntry entry = (TableEntry) table.getValueAt(row, 0); //System.out.println(entry.getCommit().getRepository().getGraph().get(entry.getCommit()).getData().get(entry.getGraphIndex())); if (entry.getGraphIndex() == 0) { for (ICommitClickListener l : listeners) { l.onClick(entry.getCommit()); } } } } }); JPopupMenu menu = new JPopupMenu(); JMenuItem imRevert = new JMenuItem("Revert commit"); imRevert.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent arg0) { int row = table.getSelectedRow(); if (row != -1) { Commit c = (Commit) table.getValueAt(row, 0); if (DialogUtils.confirm("Are you sure that you want to create a new commit,\nreversing all the changes in " + c.getHash(), "Revert commit")) { try { c.revert(); reload(); } catch (Exception e) { e.printStackTrace(); Main.displayError(e); } } } } }); menu.add(imRevert); JMenuItem imReset = new JMenuItem("Reset current branch to this commit"); imReset.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent arg0) { int row = table.getSelectedRow(); if (row != -1) { Commit c = (Commit) table.getValueAt(row, 0); new DialogReset(c).setVisible(true); } } }); menu.add(imReset); JMenuItem imArchive = new JMenuItem("Archive"); imArchive.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent arg0) { int row = table.getSelectedRow(); if (row != -1) { Commit c = (Commit) table.getValueAt(row, 0); new DialogArchive(c, repository).setVisible(true); } } }); menu.add(imArchive); JMenuItem imCopy = new JMenuItem("Copy SHA1 to clipboard"); imCopy.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent arg0) { int row = table.getSelectedRow(); if (row != -1) { Commit c = (Commit) table.getValueAt(row, 0); IOUtils.setClipboard(c.getHash()); } } }); menu.add(imCopy); MenuItemUtils.addPopup(table, menu); reload(); } public Commit getSelectedCommit() { int row = table.getSelectedRow(); if (row != -1) { return ((CommitListPanel.TableEntry) table.getValueAt(row, 0)).getCommit(); } return null; } public void setSelectedCommit(Commit commit) { for (int i = 0; i < model.getRowCount(); i++) { Commit c = (Commit) table.getValueAt(i, 0); if (c == commit) { table.setRowSelectionInterval(i, i); table.scrollRectToVisible(new Rectangle(table.getCellRect(i, 0, true))); break; } } } /** * Reloads the commit list. If repository has unstaged changes, will add "null" to the top which is the row "Uncommited changes" * @throws Exception */ public void reload() throws Exception { Branch selectedBranch = branchBox.getSelectedBranch(); List<Commit> commits = repository.getCommits(true, selectedBranch == null, selectedBranch); this.commits = commits; clear(); if (repository.hasUnstagedFiles()) { model.addRow(new Object[] { null }); } for (Commit c : commits) { List<String> data = c.getGraphData(); for (int i = 0; i < data.size(); i++) { model.addRow(new Object[] { new TableEntry(c, i) }); } } } public void clear() { while (table.getRowCount() > 0) { model.removeRow(0); } } /** * Adds commit click listener * @param l */ public void addListener(ICommitClickListener l) { listeners.add(l); } /** * Removes commit click listener * @param l */ public void removeListener(ICommitClickListener l) { listeners.remove(l); } public class TableEntry { private Commit commit; private int graphIndex; public TableEntry(Commit commit, int graphIndex) { this.commit = commit; this.graphIndex = graphIndex; } public Commit getCommit() { return this.commit; } public int getGraphIndex() { return this.graphIndex; } } public class CommitRenderer extends DefaultTableCellRenderer { private final Map<Commit, ImageIcon> cache = new HashMap<Commit, ImageIcon>(); @Override public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) { JLabel label = (JLabel) super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column); Object obj = table.getValueAt(row, 0); if (obj instanceof TableEntry) { TableEntry entry = (TableEntry) obj; Commit c = entry.getCommit(); ImageIcon icon = null; if (c.getTags() != null) { List<Tag> tags = new ArrayList<Tag>(); for (Tag tag : c.getTags()) { if (tag.getHash().equals(c.getHash())) { tags.add(tag); } } if (cache.containsKey(c)) { icon = cache.get(c); } else { icon = IconGenerator.getTagIcons(tags); cache.put(c, icon); } } label.setIcon(null); if (table.getColumnName(column).equals(COLUMN_GRAPH)) { label.setIcon(c.getRepository().getGraph().getIcon(row * table.getRowHeight())); label.setText(""); } else if (entry.getGraphIndex() != 0) { return label; } if (table.getColumnName(column).equals(COLUMN_DESCRIPTION)) { label.setIcon(icon); label.setText(c.getComment()); } else if (table.getColumnName(column).equals(COLUMN_DATE)) { label.setText(c.getWhen()); } else if (table.getColumnName(column).equals(COLUMN_AUTHOR)) { label.setText(c.getDisplayAuthor()); } else if (table.getColumnName(column).equals(COLUMN_COMMIT)) { label.setText(c.getDisplayHash()); } } else if (obj == null) { if (table.getColumnName(column).equals(COLUMN_DESCRIPTION)) { label.setText("Uncommitted changes"); label.setFont(new Font(label.getFont().getName(), Font.BOLD, label.getFont().getSize())); } else { label.setText(""); } } if (isSelected) { label.setBackground(TABLE_SELECTED); } else if (row % 2 == 1) { label.setBackground(TABLE_GRAY); } else { label.setBackground(Color.white); } return label; } } public static class CommitTableModel extends DefaultTableModel { public CommitTableModel() { super.addColumn(COLUMN_GRAPH); super.addColumn(COLUMN_DESCRIPTION); super.addColumn(COLUMN_DATE); super.addColumn(COLUMN_AUTHOR); super.addColumn(COLUMN_COMMIT); } @Override public boolean isCellEditable(int i, int i1) { return false; } } }