2 * Copyright 2000-2016 JetBrains s.r.o.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
16 package com.intellij.vcs.log.ui.render;
18 * Copyright 2000-2015 JetBrains s.r.o.
20 * Licensed under the Apache License, Version 2.0 (the "License");
21 * you may not use this file except in compliance with the License.
22 * You may obtain a copy of the License at
24 * http://www.apache.org/licenses/LICENSE-2.0
26 * Unless required by applicable law or agreed to in writing, software
27 * distributed under the License is distributed on an "AS IS" BASIS,
28 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
29 * See the License for the specific language governing permissions and
30 * limitations under the License.
33 import com.intellij.openapi.ui.GraphicsConfig;
34 import com.intellij.openapi.util.Pair;
35 import com.intellij.openapi.util.text.StringUtil;
36 import com.intellij.ui.SimpleColoredComponent;
37 import com.intellij.util.ObjectUtils;
38 import com.intellij.util.containers.ContainerUtil;
39 import com.intellij.util.containers.MultiMap;
40 import com.intellij.util.ui.GraphicsUtil;
41 import com.intellij.util.ui.JBUI;
42 import com.intellij.util.ui.UIUtil;
43 import com.intellij.vcs.log.RefGroup;
44 import com.intellij.vcs.log.VcsLogRefManager;
45 import com.intellij.vcs.log.VcsRef;
46 import com.intellij.vcs.log.VcsRefType;
47 import com.intellij.vcs.log.data.VcsLogData;
48 import org.jetbrains.annotations.NotNull;
52 import java.util.Collection;
53 import java.util.List;
56 public class LabelPainter implements ReferencePainter {
57 public static final int TOP_TEXT_PADDING = JBUI.scale(2);
58 public static final int BOTTOM_TEXT_PADDING = JBUI.scale(1);
59 public static final int GRADIENT_WIDTH = JBUI.scale(50);
60 public static final int RIGHT_PADDING = JBUI.scale(5);
61 public static final int MIDDLE_PADDING = JBUI.scale(5);
62 private static final int MAX_LENGTH = 22;
63 private static final String THREE_DOTS = "...";
64 private static final String TWO_DOTS = "..";
65 private static final String SEPARATOR = "/";
67 @NotNull private final VcsLogData myLogData;
69 @NotNull private List<Pair<String, LabelIcon>> myLabels = ContainerUtil.newArrayList();
70 private int myHeight = JBUI.scale(22);
71 private int myWidth = 0;
73 private Color myBackground = UIUtil.getTableBackground();
75 private Color myForeground = UIUtil.getTableForeground();
77 public LabelPainter(@NotNull VcsLogData data) {
81 public void customizePainter(@NotNull JComponent component,
82 @NotNull Collection<VcsRef> references,
83 @NotNull Color background,
84 @NotNull Color foreground) {
85 myBackground = background;
86 myForeground = foreground;
88 FontMetrics metrics = component.getFontMetrics(getReferenceFont());
89 myHeight = metrics.getHeight() + TOP_TEXT_PADDING + BOTTOM_TEXT_PADDING;
91 VcsLogRefManager manager = ReferencePainter.getRefManager(myLogData, references);
92 List<RefGroup> refGroups = manager == null ? ContainerUtil.emptyList() : manager.groupForTable(references);
93 Pair<List<Pair<String, LabelIcon>>, Integer> presentation = calculatePresentation(refGroups, metrics, myHeight, myBackground);
95 myLabels = presentation.first;
96 myWidth = presentation.second;
100 public static Pair<List<Pair<String, LabelIcon>>, Integer> calculatePresentation(@NotNull List<RefGroup> refGroups,
101 @NotNull FontMetrics fontMetrics,
103 @NotNull Color background) {
104 int width = GRADIENT_WIDTH + RIGHT_PADDING;
106 List<Pair<String, LabelIcon>> labels = ContainerUtil.newArrayList();
107 if (refGroups.isEmpty()) return Pair.create(labels, width);
109 for (RefGroup group : refGroups) {
110 if (group.isExpanded()) {
111 for (VcsRef ref : group.getRefs()) {
112 LabelIcon labelIcon = new LabelIcon(height, background, ref.getType().getBackgroundColor());
113 String text = shortenRefName(ref.getName());
115 labels.add(Pair.create(text, labelIcon));
116 width += labelIcon.getIconWidth() + fontMetrics.stringWidth(text) + MIDDLE_PADDING;
120 LabelIcon labelIcon = new LabelIcon(height, background, getGroupColors(group));
121 String text = shortenRefName(group.getName());
123 labels.add(Pair.create(text, labelIcon));
124 width += labelIcon.getIconWidth() + fontMetrics.stringWidth(text) + MIDDLE_PADDING;
128 return Pair.create(labels, width);
132 private static String shortenRefName(@NotNull String refName) {
133 int textLength = refName.length();
134 if (textLength > MAX_LENGTH) {
135 int separatorIndex = refName.indexOf(SEPARATOR);
136 if (separatorIndex > TWO_DOTS.length()) {
137 refName = TWO_DOTS + refName.substring(separatorIndex);
139 return StringUtil.shortenTextWithEllipsis(refName, MAX_LENGTH, 0, THREE_DOTS);
145 public static Color[] getGroupColors(@NotNull RefGroup group) {
146 MultiMap<VcsRefType, VcsRef> referencesByType = ContainerUtil.groupBy(group.getRefs(), VcsRef::getType);
148 if (referencesByType.size() == 1) {
149 Map.Entry<VcsRefType, Collection<VcsRef>> firstItem =
150 ObjectUtils.assertNotNull(ContainerUtil.getFirstItem(referencesByType.entrySet()));
151 boolean multiple = firstItem.getValue().size() > 1;
152 Color color = firstItem.getKey().getBackgroundColor();
153 colors = multiple ? new Color[]{color, color} : new Color[]{color};
156 List<Color> colorsList = ContainerUtil.newArrayList();
157 for (VcsRefType type : referencesByType.keySet()) {
158 if (referencesByType.get(type).size() > 1) {
159 colorsList.add(type.getBackgroundColor());
161 colorsList.add(type.getBackgroundColor());
163 colors = colorsList.toArray(new Color[colorsList.size()]);
168 public void paint(@NotNull Graphics2D g2, int x, int y, int height) {
169 if (myLabels.isEmpty()) return;
171 GraphicsConfig config = GraphicsUtil.setupAAPainting(g2);
172 g2.setFont(getReferenceFont());
173 g2.setStroke(new BasicStroke(1.5f));
175 x = paintFadeOut(g2, x, y, myWidth, height, myBackground);
177 FontMetrics fontMetrics = g2.getFontMetrics();
178 for (Pair<String, LabelIcon> label : myLabels) {
179 LabelIcon icon = label.second;
180 String text = label.first;
182 icon.paintIcon(null, g2, x, y + (height - icon.getIconHeight()) / 2);
183 x += icon.getIconWidth();
185 g2.setColor(myForeground);
186 g2.drawString(text, x, y + SimpleColoredComponent.getTextBaseLine(fontMetrics, height));
187 x += fontMetrics.stringWidth(text) + MIDDLE_PADDING;
193 public static int paintFadeOut(@NotNull Graphics2D g2, int x, int y, int width, int height, @NotNull Color background) {
194 //noinspection UseJBColor
195 g2.setPaint(new GradientPaint(x, y,
196 new Color(background.getRed(), background.getGreen(), background.getBlue(), 0),
197 x + GRADIENT_WIDTH, y,
199 g2.fill(new Rectangle(x, y, GRADIENT_WIDTH, height));
202 g2.setColor(background);
203 g2.fillRect(x, y, width - GRADIENT_WIDTH, height);
207 public Dimension getSize() {
208 if (myLabels.isEmpty()) return new Dimension();
209 return new Dimension(myWidth, myHeight);
213 public boolean isLeftAligned() {