[vcs]: implement IconListPopupRenderer, implement branch starred action

* add and detect a separated icon rendering component;
* toggle branchActionGroup by clicking on icon;
* updatePresentation if needed;
* mark BranchActionGroup as DumbAware;
This commit is contained in:
Nadya Zabrodina
2017-01-11 16:45:33 +03:00
parent 1a406f1b79
commit eaf4500835
4 changed files with 103 additions and 7 deletions
@@ -16,9 +16,45 @@
package com.intellij.dvcs.ui;
import com.intellij.openapi.actionSystem.ActionGroup;
import com.intellij.openapi.project.DumbAware;
import com.intellij.ui.LayeredIcon;
import com.intellij.util.ui.EmptyIcon;
import static icons.DvcsImplIcons.*;
public abstract class BranchActionGroup extends ActionGroup implements DumbAware {
private boolean myIsFavourite;
private final LayeredIcon myIcon;
private final LayeredIcon myHoveredIcon;
public abstract class BranchActionGroup extends ActionGroup {
public BranchActionGroup() {
super("", true);
myIcon = new LayeredIcon(Favorite, EmptyIcon.ICON_16);
myHoveredIcon = new LayeredIcon(FavoriteOnHover, NotFavoriteOnHover);
getTemplatePresentation().setIcon(myIcon);
getTemplatePresentation().setHoveredIcon(myHoveredIcon);
updateIcons();
}
private void updateIcons() {
myIcon.setLayerEnabled(0, myIsFavourite);
myHoveredIcon.setLayerEnabled(0, myIsFavourite);
myIcon.setLayerEnabled(1, !myIsFavourite);
myHoveredIcon.setLayerEnabled(1, !myIsFavourite);
}
public boolean isFavourite() {
return myIsFavourite;
}
public void setFavourite(boolean favourite) {
myIsFavourite = favourite;
updateIcons();
}
public void toggle() {
setFavourite(!myIsFavourite);
}
}
@@ -32,6 +32,7 @@ import com.intellij.ui.components.panels.OpaquePanel;
import com.intellij.ui.popup.KeepingPopupOpenAction;
import com.intellij.ui.popup.PopupFactoryImpl;
import com.intellij.ui.popup.WizardPopup;
import com.intellij.ui.popup.list.IconListPopupRenderer;
import com.intellij.ui.popup.list.ListPopupImpl;
import com.intellij.ui.popup.list.ListPopupModel;
import com.intellij.ui.popup.list.PopupListElementRenderer;
@@ -44,6 +45,7 @@ import org.jetbrains.annotations.Nullable;
import javax.swing.*;
import java.awt.*;
import java.awt.event.InputEvent;
import java.awt.event.MouseEvent;
import java.util.List;
import static com.intellij.util.ui.UIUtil.DEFAULT_HGAP;
@@ -53,6 +55,7 @@ public class BranchActionGroupPopup extends FlatSpeedSearchPopup {
private static final String DIMENSION_SERVICE_KEY = "Vcs.Branch.Popup";
private static final DataKey<ListPopupModel> POPUP_MODEL = DataKey.create("VcsPopupModel");
private int myIgnoreNextItem = 0;
private MyPopupListElementRenderer myListElementRenderer;
public BranchActionGroupPopup(@NotNull String title, @NotNull Project project,
@NotNull Condition<AnAction> preselectActionCondition, @NotNull ActionGroup actions) {
@@ -60,12 +63,14 @@ public class BranchActionGroupPopup extends FlatSpeedSearchPopup {
preselectActionCondition, true);
setDimensionServiceKey(DIMENSION_SERVICE_KEY);
DataManager.registerDataProvider(getList(), dataId -> POPUP_MODEL.is(dataId) ? getListModel() : null);
installOnHoverIconsSupport(getListElementRenderer());
}
//for child popups only
private BranchActionGroupPopup(@Nullable WizardPopup aParent, @NotNull ListPopupStep aStep, @Nullable Object parentValue) {
super(aParent, aStep, DataContext.EMPTY_CONTEXT, parentValue);
DataManager.registerDataProvider(getList(), dataId -> POPUP_MODEL.is(dataId) ? getListModel() : null);
installOnHoverIconsSupport(getListElementRenderer());
}
@NotNull
@@ -98,6 +103,34 @@ public class BranchActionGroupPopup extends FlatSpeedSearchPopup {
}
}
@Override
public void handleSelect(boolean handleFinalChoices, InputEvent e) {
BranchActionGroup branchActionGroup = getSelectedBranchGroup();
if (branchActionGroup != null && e instanceof MouseEvent && myListElementRenderer.isIconAt(((MouseEvent)e).getPoint())) {
branchActionGroup.toggle();
}
else {
super.handleSelect(handleFinalChoices, e);
}
}
@Override
protected void handleToggleAction() {
BranchActionGroup branchActionGroup = getSelectedBranchGroup();
if (branchActionGroup != null) {
branchActionGroup.toggle();
getList().repaint();
}
else {
super.handleToggleAction();
}
}
@Nullable
private BranchActionGroup getSelectedBranchGroup() {
return getSpecificAction(getList().getSelectedValue(), BranchActionGroup.class);
}
@Override
protected void onSpeedSearchPatternChanged() {
super.onSpeedSearchPatternChanged();
@@ -142,18 +175,26 @@ public class BranchActionGroupPopup extends FlatSpeedSearchPopup {
if (clazz.isInstance(action)) {
return clazz.cast(action);
}
else if (action instanceof MySpeedSearchActionGroup) {
ActionGroup group = ((MySpeedSearchActionGroup)action).getActionGroup();
return clazz.isInstance(group) ? clazz.cast(group) : null;
}
}
return null;
}
@Override
protected ListCellRenderer getListElementRenderer() {
return new MyPopupListElementRenderer(this);
protected MyPopupListElementRenderer getListElementRenderer() {
if (myListElementRenderer == null) {
myListElementRenderer = new MyPopupListElementRenderer(this);
}
return myListElementRenderer;
}
private static class MyPopupListElementRenderer extends PopupListElementRenderer<Object> {
private class MyPopupListElementRenderer extends PopupListElementRenderer<Object> implements IconListPopupRenderer {
private ErrorLabel myInfoLabel;
private IconComponent myIconLabel;
public MyPopupListElementRenderer(ListPopupImpl aPopup) {
super(aPopup);
@@ -164,6 +205,18 @@ public class BranchActionGroupPopup extends FlatSpeedSearchPopup {
return new MyTextSeparator();
}
@Override
public boolean isIconAt(@NotNull Point point) {
JList list = getList();
int index = getList().locationToIndex(point);
Rectangle bounds = getList().getCellBounds(index, index);
Component renderer = getListCellRendererComponent(list, list.getSelectedValue(), index, true, true);
renderer.setBounds(bounds);
renderer.doLayout();
point.translate(-bounds.x, -bounds.y);
return SwingUtilities.getDeepestComponentAt(renderer, point.x, point.y) instanceof IconComponent;
}
@Override
protected void customizeComponent(JList list, Object value, boolean isSelected) {
MoreAction more = getSpecificAction(value, MoreAction.class);
@@ -171,7 +224,9 @@ public class BranchActionGroupPopup extends FlatSpeedSearchPopup {
myTextLabel.setForeground(JBColor.gray);
}
super.customizeComponent(list, value, isSelected);
myTextLabel.setIcon(null);
myTextLabel.setDisabledIcon(null);
myIconLabel.setIcon(myDescriptor.getIconFor(value));
PopupElementWithAdditionalInfo additionalInfoAction = getSpecificAction(value, PopupElementWithAdditionalInfo.class);
String infoText = additionalInfoAction != null ? additionalInfoAction.getInfoText() : null;
if (infoText != null) {
@@ -202,11 +257,16 @@ public class BranchActionGroupPopup extends FlatSpeedSearchPopup {
myInfoLabel.setBorder(JBUI.Borders.empty(1, DEFAULT_HGAP, 1, 1));
JPanel compoundPanel = new OpaquePanel(new BorderLayout(), JBColor.WHITE);
myIconLabel = new IconComponent();
compoundPanel.add(myIconLabel, BorderLayout.WEST);
compoundPanel.add(myTextLabel, BorderLayout.CENTER);
compoundPanel.add(myInfoLabel, BorderLayout.EAST);
return layoutComponent(compoundPanel);
}
private class IconComponent extends JLabel {
}
}
private static class MyTextSeparator extends SeparatorWithText {
@@ -423,7 +423,7 @@ public class PopupFactoryImpl extends JBPopupFactory {
Rectangle bounds = getList().getCellBounds(index, index);
Object selectedValue = getList().getSelectedValue();
if (selectedValue instanceof ActionItem) {
((ActionItem)selectedValue).setIconHovered(myRenderer.iconContains(point));
((ActionItem)selectedValue).setIconHovered(myRenderer.isIconAt(point));
}
if (bounds != null) {
getList().repaint(bounds);
@@ -21,5 +21,5 @@ import java.awt.*;
public interface IconListPopupRenderer {
boolean iconContains(@NotNull Point point);
boolean isIconAt(@NotNull Point point);
}