package gitj.ui.components;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.util.List;
import javax.imageio.ImageIO;
import javax.swing.JPanel;
import git.Chunk;
import git.CodeLine;
import git.Diff;
import gitj.utils.GitIconUtils;
@SuppressWarnings("serial")
public class DiffPanel extends JPanel {
public static final Color COLOR_ADDED = new Color(212, 234, 205);
public static final Color COLOR_REMOVED = new Color(240, 214, 214);
public static final Color COLOR_PANEL = new Color(237, 237, 237);
public static final Color COLOR_PANEL_BORDER = new Color(204, 204, 204);
private Diff diff;
private boolean hasChecked;
private BufferedImage image;
private int prefWidth;
private int prefHeight;
public DiffPanel(Diff diff) {
this.diff = diff;
}
@Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
((Graphics2D) g).setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
boolean isImage = diff.isImage();
if (isImage && image == null && !hasChecked) {
try {
image = ImageIO.read(new ByteArrayInputStream(diff.getData(false)));
if (image == null) {
isImage = false;
}
hasChecked = true;
} catch (Exception e) {
e.printStackTrace();
isImage = false;
}
}
FontMetrics metrics = g.getFontMetrics(g.getFont());
int textHeight = metrics.getHeight();
if (prefWidth == 0 || prefHeight == 0) {
prefHeight = 25;
if (diff.getChunks().size() == 0) {
prefHeight += 10;
}
for (Chunk chunk : diff.getChunks()) {
prefHeight += 6 + textHeight;
for (CodeLine line : chunk.getLines()) {
int sw = metrics.stringWidth(line.getFixedLine()) + 80;
if (sw > prefWidth) {
prefWidth = sw;
}
prefHeight += textHeight + 2;
}
}
if (metrics.stringWidth(diff.getLocalPath()) + 80 > prefWidth) {
prefWidth = metrics.stringWidth(diff.getLocalPath()) + 80;
}
if (isImage) {
if (image.getWidth() + 80 > prefWidth) {
prefWidth = image.getWidth() + 80;
}
prefHeight += image.getHeight();
} else {
prefWidth += 20;
}
}
// Top diff file table
g.setColor(COLOR_PANEL);
g.fillRect(0, 0, prefWidth, 25);
g.setColor(COLOR_PANEL_BORDER);
g.drawRect(0, 0, prefWidth, 25);
g.setColor(Color.gray);
g.drawString(diff.getLocalPath(), 20, 4 + textHeight);
g.drawImage(GitIconUtils.getIconFromDiffType(diff.getType()), 2, 5, null);
// Left line number table
g.setColor(COLOR_PANEL);
g.fillRect(0, 25, 60, getHeight() - 35);
g.setColor(COLOR_PANEL_BORDER);
g.drawRect(0, 25, 60, getHeight() - 35);
int y = 25;
List<Chunk> chunks = diff.getChunks();
for (Chunk chunk : chunks) {
g.setColor(Color.black);
g.drawString(chunk.getName(), 63, y + textHeight);
g.setColor(COLOR_PANEL_BORDER);
g.drawRect(60, y, prefWidth - 60, 5 + textHeight);
y += 6 + textHeight;
int startLine = chunk.getStartLine();
int startRemovedLine = chunk.getStartRemovedLine();
int startY = y;
for (CodeLine line : chunk.getLines()) {
g.setColor(Color.gray);
if (line.getType() == CodeLine.Type.ADDED) {
g.drawString(startLine++ + "", 60 - metrics.stringWidth(startLine + "") - 5, y + textHeight);
} else if (line.getType() == CodeLine.Type.REMOVED) {
g.drawString(startRemovedLine++ + "", 5, y + textHeight);
} else {
g.drawString(startLine++ + "", 60 - metrics.stringWidth(startLine + "") - 5, y + textHeight);
g.drawString(startRemovedLine++ + "", 5, y + textHeight);
}
if (line.getType() == CodeLine.Type.ADDED) {
g.setColor(COLOR_ADDED);
} else if (line.getType() == CodeLine.Type.REMOVED) {
g.setColor(COLOR_REMOVED);
} else {
g.setColor(Color.white);
}
g.fillRect(61, y, prefWidth - 61, textHeight + 2);
y += textHeight + 2;
}
y = startY;
for (CodeLine line : chunk.getLines()) {
if (line.getType() == CodeLine.Type.ADDED) {
g.setColor(COLOR_ADDED.darker());
g.drawString("+", 67 - (metrics.stringWidth("+") / 2), y + textHeight - 1);
} else if (line.getType() == CodeLine.Type.REMOVED) {
g.setColor(COLOR_REMOVED.darker());
g.drawString("-", 67 - (metrics.stringWidth("-") / 2), y + textHeight - 1);
}
g.setColor(Color.black);
g.drawString(line.getFixedLine(), 80, y + textHeight);
y += textHeight + 2;
}
}
if (isImage) {
g.drawImage(image, prefWidth / 2, y + 5, null);
}
g.setColor(COLOR_PANEL_BORDER);
g.drawRect(0, 0, prefWidth - 1, getHeight() - 10);
g.setColor(Color.white);
g.fillRect(0, getHeight() - 9, prefWidth, 9);
if (getWidth() != prefWidth || getHeight() != prefHeight) {
super.setPreferredSize(getDimension());
}
}
public Dimension getDimension() {
return new Dimension(prefWidth, prefHeight + 10);
}
public int getPrefWidth() {
return prefWidth;
}
public int getPrefHeight() {
return prefHeight;
}
}