/*
* Copyright 2000-2016 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.intellij.vcs.log.ui.frame;
import com.intellij.ui.ColorUtil;
import com.intellij.ui.components.JBLabel;
import com.intellij.ui.components.panels.Wrapper;
import com.intellij.util.ObjectUtils;
import com.intellij.util.containers.ContainerUtil;
import com.intellij.util.containers.MultiMap;
import com.intellij.util.ui.JBUI;
import com.intellij.util.ui.UIUtil;
import com.intellij.vcs.log.VcsRef;
import com.intellij.vcs.log.VcsRefType;
import com.intellij.vcs.log.ui.render.LabelIcon;
import com.intellij.vcs.log.ui.render.RectanglePainter;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import javax.swing.*;
import java.awt.*;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import static com.intellij.openapi.vcs.history.VcsHistoryUtil.getCommitDetailsFont;
import static com.intellij.vcs.log.ui.frame.CommitPanel.getCommitDetailsBackground;
public class ReferencesPanel extends JPanel {
public static final int H_GAP = 4;
protected static final int V_GAP = 0;
public static final int PADDING = 3;
private final int myRefsLimit;
@NotNull private List<VcsRef> myReferences;
@NotNull protected MultiMap<VcsRefType, VcsRef> myGroupedVisibleReferences;
public ReferencesPanel() {
this(new WrappedFlowLayout(JBUI.scale(H_GAP), JBUI.scale(V_GAP)), -1);
}
public ReferencesPanel(LayoutManager layout, int limit) {
super(layout);
myRefsLimit = limit;
myReferences = Collections.emptyList();
myGroupedVisibleReferences = MultiMap.create();
setOpaque(false);
}
public void setReferences(@NotNull List<VcsRef> references) {
myReferences = references;
List<VcsRef> visibleReferences = (myRefsLimit > 0) ? myReferences.subList(0, Math.min(myReferences.size(), myRefsLimit)) : myReferences;
myGroupedVisibleReferences = ContainerUtil.groupBy(visibleReferences, VcsRef::getType);
update();
}
public void update() {
removeAll();
int height = getIconHeight();
JBLabel firstLabel = null;
for (Map.Entry<VcsRefType, Collection<VcsRef>> typeAndRefs : myGroupedVisibleReferences.entrySet()) {
VcsRefType type = typeAndRefs.getKey();
Collection<VcsRef> refs = typeAndRefs.getValue();
int refIndex = 0;
for (VcsRef reference : refs) {
Icon icon = createIcon(type, refs, refIndex, height);
String ending = (refIndex != refs.size() - 1) ? "," : "";
String text = reference.getName() + ending;
JBLabel label = createLabel(text, icon);
if (firstLabel == null) {
firstLabel = label;
add(label);
}
else {
addWrapped(label, firstLabel);
}
refIndex++;
}
}
if (getHiddenReferencesSize() > 0) {
JBLabel label = createRestLabel(getHiddenReferencesSize());
addWrapped(label, ObjectUtils.assertNotNull(firstLabel));
}
setVisible(!myGroupedVisibleReferences.isEmpty());
revalidate();
repaint();
}
private int getHiddenReferencesSize() {
return (myRefsLimit > 0) ? myReferences.size() - Math.min(myReferences.size(), myRefsLimit) : 0;
}
protected int getIconHeight() {
return getFontMetrics(getLabelsFont()).getHeight() + JBUI.scale(PADDING);
}
@NotNull
protected JBLabel createRestLabel(int restSize) {
return createLabel("... " + restSize + " more", null);
}
@Nullable
protected Icon createIcon(@NotNull VcsRefType type,
@NotNull Collection<VcsRef> refs,
int refIndex, int height) {
if (refIndex == 0) {
Color color = type.getBackgroundColor();
return new LabelIcon(height, getBackground(),
refs.size() > 1 ? new Color[]{color, color} : new Color[]{color});
}
return null;
}
private void addWrapped(@NotNull JBLabel label, @NotNull JBLabel referent) {
Wrapper wrapper = new Wrapper(label);
wrapper.setVerticalSizeReferent(referent);
add(wrapper);
}
@NotNull
protected JBLabel createLabel(@NotNull String text, @Nullable Icon icon) {
JBLabel label = new JBLabel(text, icon, SwingConstants.LEFT);
label.setFont(getLabelsFont());
label.setIconTextGap(0);
label.setHorizontalAlignment(SwingConstants.LEFT);
return label;
}
@NotNull
protected Font getLabelsFont() {
return getCommitDetailsFont();
}
@Override
public Dimension getMaximumSize() {
return new Dimension(super.getMaximumSize().width, super.getPreferredSize().height);
}
@Override
public Color getBackground() {
return getCommitDetailsBackground();
}
@NotNull
public static Color getLabelColor(@NotNull Color color) {
if (UIUtil.isUnderDarcula()) {
color = ColorUtil.darker(color, 6);
}
else {
color = ColorUtil.brighter(color, 6);
}
return ColorUtil.desaturate(color, 3);
}
private static class ReferencePanel extends JPanel {
@NotNull private final RectanglePainter myLabelPainter;
@NotNull private final VcsRef myReference;
private ReferencePanel(@NotNull VcsRef reference) {
myReference = reference;
myLabelPainter = new RectanglePainter(false);
setOpaque(false);
}
@Override
public void paint(Graphics g) {
myLabelPainter.paint((Graphics2D)g, myReference.getName(), 0, 0,
getLabelColor(myReference.getType().getBackgroundColor()));
}
@Override
public Dimension getPreferredSize() {
Dimension dimension = myLabelPainter.calculateSize(myReference.getName(), getFontMetrics(RectanglePainter.getFont()));
return new Dimension(dimension.width, dimension.height + JBUI.scale(PADDING));
}
@Override
public Color getBackground() {
return getCommitDetailsBackground();
}
}
}