1 package com.intellij.vcs.log.ui.render;
3 import com.intellij.openapi.util.registry.Registry;
4 import com.intellij.openapi.vcs.changes.issueLinks.IssueLinkRenderer;
5 import com.intellij.ui.SimpleColoredRenderer;
6 import com.intellij.ui.SimpleTextAttributes;
7 import com.intellij.util.ObjectUtils;
8 import com.intellij.util.ui.JBUI;
9 import com.intellij.util.ui.UIUtil;
10 import com.intellij.vcs.log.VcsRef;
11 import com.intellij.vcs.log.data.VcsLogData;
12 import com.intellij.vcs.log.graph.EdgePrintElement;
13 import com.intellij.vcs.log.graph.PrintElement;
14 import com.intellij.vcs.log.paint.GraphCellPainter;
15 import com.intellij.vcs.log.paint.PaintParameters;
16 import com.intellij.vcs.log.ui.frame.VcsLogGraphTable;
17 import com.intellij.vcs.log.ui.tables.GraphTableModel;
18 import org.jetbrains.annotations.NotNull;
19 import org.jetbrains.annotations.Nullable;
23 import java.awt.image.BufferedImage;
24 import java.util.Collection;
26 public class GraphCommitCellRenderer extends TypeSafeTableCellRenderer<GraphCommitCell> {
27 private static final int MAX_GRAPH_WIDTH = 6;
28 private static final int VERTICAL_PADDING = JBUI.scale(7);
30 @NotNull private final VcsLogData myLogData;
31 @NotNull private final VcsLogGraphTable myGraphTable;
33 @NotNull private final MyComponent myComponent;
34 @NotNull private final MyComponent myTemplateComponent;
35 @Nullable private final ReferencePainter myTooltipPainter;
37 public GraphCommitCellRenderer(@NotNull VcsLogData logData,
38 @NotNull GraphCellPainter painter,
39 @NotNull VcsLogGraphTable table) {
43 myTooltipPainter = isRedesignedLabels() ? new LabelPainter(myLogData) : null;
44 myComponent = new MyComponent(logData, painter, table);
45 myTemplateComponent = new MyComponent(logData, painter, table);
49 protected Component getTableCellRendererComponentImpl(@NotNull JTable table,
50 @NotNull GraphCommitCell value,
55 myComponent.customize(value, isSelected, hasFocus, row, column);
59 public static boolean isRedesignedLabels() {
60 return Registry.is("vcs.log.labels.redesign");
64 public JComponent getTooltip(@NotNull Object value, @NotNull Point point, int row) {
65 if (myTooltipPainter == null) return null;
67 GraphCommitCell cell = getValue(value);
68 Collection<VcsRef> refs = cell.getRefsToThisCommit();
69 if (!refs.isEmpty()) {
70 myTooltipPainter.customizePainter(myComponent, refs, myComponent.getBackground(), myComponent.getForeground(),
71 true/*counterintuitive, but true*/, getColumnWidth());
72 if (getReferencesWidth(row) >= getColumnWidth() - point.getX()) {
73 return new TooltipReferencesPanel(myLogData, myTooltipPainter, refs);
79 public int getPreferredHeight() {
80 return myComponent.getPreferredHeight();
83 private int getReferencesWidth(int row) {
84 GraphCommitCell cell = getValue(myGraphTable.getModel().getValueAt(row, GraphTableModel.COMMIT_COLUMN));
85 Collection<VcsRef> refs = cell.getRefsToThisCommit();
86 if (!refs.isEmpty()) {
87 myTemplateComponent.customize(cell, myGraphTable.isRowSelected(row), myGraphTable.hasFocus(),
88 row, GraphTableModel.COMMIT_COLUMN);
89 return myTemplateComponent.getReferencePainter().getSize().width;
95 public int getTooltipXCoordinate(int row) {
96 int referencesWidth = getReferencesWidth(row);
97 if (referencesWidth != 0) {
98 return getColumnWidth() - referencesWidth / 2;
100 return getColumnWidth() / 2;
103 private int getColumnWidth() {
104 return myGraphTable.getColumnModel().getColumn(GraphTableModel.COMMIT_COLUMN).getWidth();
107 private static class MyComponent extends SimpleColoredRenderer {
108 @NotNull private final VcsLogData myLogData;
109 @NotNull private final VcsLogGraphTable myGraphTable;
110 @NotNull private final GraphCellPainter myPainter;
111 @NotNull private final IssueLinkRenderer myIssueLinkRenderer;
112 @NotNull private final ReferencePainter myReferencePainter;
114 @NotNull protected PaintInfo myGraphImage = new PaintInfo(UIUtil.createImage(1, 1, BufferedImage.TYPE_INT_ARGB), 0);
115 @NotNull private Font myFont;
116 private int myHeight;
118 public MyComponent(@NotNull VcsLogData data, @NotNull GraphCellPainter painter, @NotNull VcsLogGraphTable table) {
121 myGraphTable = table;
123 myReferencePainter = isRedesignedLabels() ? new LabelPainter(myLogData) : new RectangleReferencePainter(myLogData);
125 myIssueLinkRenderer = new IssueLinkRenderer(myLogData.getProject(), this);
126 myFont = RectanglePainter.getFont();
127 myHeight = calculateHeight();
132 public Dimension getPreferredSize() {
133 Dimension preferredSize = super.getPreferredSize();
134 int referencesSize = myReferencePainter.isLeftAligned() ? 0 : myReferencePainter.getSize().width;
135 return new Dimension(preferredSize.width + referencesSize, getPreferredHeight());
139 public void paintComponent(Graphics g) {
140 super.paintComponent(g);
142 int graphImageWidth = myGraphImage.getWidth();
144 if (!myReferencePainter.isLeftAligned()) {
145 int start = Math.max(graphImageWidth, getWidth() - myReferencePainter.getSize().width);
146 myReferencePainter.paint((Graphics2D)g, start, 0, getHeight());
149 myReferencePainter.paint((Graphics2D)g, graphImageWidth, 0, getHeight());
152 UIUtil.drawImage(g, myGraphImage.getImage(), 0, 0, null);
155 public void customize(@NotNull GraphCommitCell cell, boolean isSelected, boolean hasFocus, int row, int column) {
157 setPaintFocusBorder(false);
158 acquireState(myGraphTable, isSelected, hasFocus, row, column);
159 getCellState().updateRenderer(this);
162 myGraphImage = getGraphImage(cell.getPrintElements());
164 SimpleTextAttributes style = myGraphTable.applyHighlighters(this, row, column, hasFocus, isSelected);
166 Collection<VcsRef> refs = cell.getRefsToThisCommit();
167 Color baseForeground = ObjectUtils.assertNotNull(myGraphTable.getBaseStyle(row, column, hasFocus, isSelected).getForeground());
169 append(""); // appendTextPadding wont work without this
170 if (myReferencePainter.isLeftAligned()) {
171 myReferencePainter.customizePainter(this, refs, getBackground(), baseForeground, isSelected,
172 0 /*left aligned painter does not use available width*/);
174 appendTextPadding(myGraphImage.getWidth() + myReferencePainter.getSize().width);
175 myIssueLinkRenderer.appendTextWithLinks(cell.getText(), style);
178 appendTextPadding(myGraphImage.getWidth());
179 myIssueLinkRenderer.appendTextWithLinks(cell.getText(), style);
180 myReferencePainter.customizePainter(this, refs, getBackground(), baseForeground, isSelected,
181 getAvailableWidth(column));
185 private int getAvailableWidth(int column) {
186 int columnWidth = myGraphTable.getColumnModel().getColumn(column).getWidth();
187 return Math.min(columnWidth - super.getPreferredSize().width, columnWidth / 3);
190 private int calculateHeight() {
191 return Math.max(myReferencePainter.getSize().height, getFontMetrics(myFont).getHeight() + VERTICAL_PADDING);
194 public int getPreferredHeight() {
195 Font font = RectanglePainter.getFont();
196 if (myFont != font) {
198 myHeight = calculateHeight();
204 private PaintInfo getGraphImage(@NotNull Collection<? extends PrintElement> printElements) {
206 for (PrintElement printElement : printElements) {
207 maxIndex = Math.max(maxIndex, printElement.getPositionInCurrentRow());
208 if (printElement instanceof EdgePrintElement) {
209 maxIndex = Math.max(maxIndex,
210 (printElement.getPositionInCurrentRow() + ((EdgePrintElement)printElement).getPositionInOtherRow()) / 2.0);
215 maxIndex = Math.max(maxIndex, Math.min(MAX_GRAPH_WIDTH, myGraphTable.getVisibleGraph().getRecommendedWidth()));
216 BufferedImage image = UIUtil.createImage((int)(PaintParameters.getNodeWidth(myGraphTable.getRowHeight()) * (maxIndex + 2)),
217 myGraphTable.getRowHeight(),
218 BufferedImage.TYPE_INT_ARGB);
219 Graphics2D g2 = image.createGraphics();
220 myPainter.draw(g2, printElements);
222 int width = (int)(maxIndex * PaintParameters.getNodeWidth(myGraphTable.getRowHeight()));
223 return new PaintInfo(image, width);
227 public ReferencePainter getReferencePainter() {
228 return myReferencePainter;
232 private static class PaintInfo {
233 private final int myWidth;
234 @NotNull private final Image myImage;
236 PaintInfo(@NotNull Image image, int width) {
247 * Returns the "interesting" width of the painted image, i.e. the width which the text in the table should be offset by. <br/>
248 * It can be smaller than the width of {@link #getImage() the image}, because we allow the text to cover part of the graph
249 * (some diagonal edges, etc.)