/* * Copyright 2000-2009 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.openapi.actionSystem.ex; import com.intellij.ide.DataManager; import com.intellij.openapi.actionSystem.DataContext; import com.intellij.openapi.actionSystem.DefaultActionGroup; import com.intellij.openapi.actionSystem.Presentation; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.application.ModalityState; import com.intellij.openapi.keymap.KeymapUtil; import com.intellij.openapi.ui.popup.JBPopup; import com.intellij.openapi.ui.popup.JBPopupFactory; import com.intellij.openapi.ui.popup.ListPopup; import com.intellij.openapi.util.SystemInfo; import com.intellij.openapi.wm.IdeFocusManager; import com.intellij.ui.UserActivityProviderComponent; import com.intellij.util.ui.JBUI; import com.intellij.util.ui.UIUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import javax.swing.*; import java.awt.*; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; public class ComboBoxButton extends JButton implements UserActivityProviderComponent { private static final String uiClassID = "ComboBoxButtonUI"; private ComboBoxAction myComboBoxAction; private final Presentation myPresentation; private boolean myForcePressed = false; private PropertyChangeListener myButtonSynchronizer; private JBPopup myPopup; private boolean myForceTransparent = false; public ComboBoxButton(ComboBoxAction comboBoxAction, Presentation presentation) { myComboBoxAction = comboBoxAction; myPresentation = presentation; setEnabled(myPresentation.isEnabled()); setModel(new MyButtonModel()); setHorizontalAlignment(LEFT); setFocusable(false); Insets margins = getMargin(); setMargin(JBUI.insets(margins.top, 2, margins.bottom, 2)); setFont(SystemInfo.isMac && myComboBoxAction.isSmallVariant() ? UIUtil.getLabelFont(UIUtil.FontSize.SMALL) : UIUtil.getLabelFont()); addActionListener(e -> { if (!myForcePressed) { IdeFocusManager.getGlobalInstance().doWhenFocusSettlesDown(this::showPopup); } }); } @Override public String getUIClassID() { return uiClassID; } public void setForceTransparent(boolean transparent) { myForceTransparent = transparent; } public boolean isForceTransparent() { return myForceTransparent; } @NotNull private Runnable setForcePressed() { myForcePressed = true; repaint(); return () -> { // give the button a chance to handle action listener ApplicationManager.getApplication().invokeLater(() -> { myForcePressed = false; myPopup = null; }, ModalityState.any()); repaint(); fireStateChanged(); }; } public JBPopup getPopup() { return myPopup; } @Nullable @Override public String getToolTipText() { return myForcePressed ? null : super.getToolTipText(); } public void showPopup() { createPopup(setForcePressed()).showUnderneathOf(this); } protected JBPopup createPopup(Runnable onDispose) { DefaultActionGroup group = myComboBoxAction.createPopupActionGroup(this); DataContext context = getDataContext(); ListPopup popup = JBPopupFactory.getInstance() .createActionGroupPopup(myComboBoxAction.getPopupTitle(), group, context, false, myComboBoxAction.shouldShowDisabledActions(), false, onDispose, myComboBoxAction.getMaxRows(), myComboBoxAction.getPreselectCondition()); popup.setMinimumSize(new Dimension(myComboBoxAction.getMinWidth(), myComboBoxAction.getMinHeight())); return popup; } public ComboBoxAction getComboBoxAction() { return myComboBoxAction; } protected DataContext getDataContext() { return DataManager.getInstance().getDataContext(this); } @Override public void removeNotify() { if (myButtonSynchronizer != null) { myPresentation.removePropertyChangeListener(myButtonSynchronizer); myButtonSynchronizer = null; } super.removeNotify(); } @Override public void addNotify() { super.addNotify(); if (myButtonSynchronizer == null) { myButtonSynchronizer = new MyButtonSynchronizer(); myPresentation.addPropertyChangeListener(myButtonSynchronizer); } initButton(); } private void initButton() { setIcon(myPresentation.getIcon()); setText(myPresentation.getText()); updateTooltipText(myPresentation.getDescription()); updateButtonSize(); } private void updateTooltipText(String description) { String tooltip = KeymapUtil.createTooltipText(description, myComboBoxAction); setToolTipText(!tooltip.isEmpty() ? tooltip : null); } @Override public void updateUI() { setUI(UIManager.getUI(this)); } protected class MyButtonModel extends DefaultButtonModel { @Override public boolean isPressed() { return myForcePressed || super.isPressed(); } @Override public boolean isArmed() { return myForcePressed || super.isArmed(); } } private class MyButtonSynchronizer implements PropertyChangeListener { @Override public void propertyChange(PropertyChangeEvent evt) { String propertyName = evt.getPropertyName(); if (Presentation.PROP_TEXT.equals(propertyName)) { setText((String)evt.getNewValue()); updateButtonSize(); } else if (Presentation.PROP_DESCRIPTION.equals(propertyName)) { updateTooltipText((String)evt.getNewValue()); } else if (Presentation.PROP_ICON.equals(propertyName)) { setIcon((Icon)evt.getNewValue()); updateButtonSize(); } else if (Presentation.PROP_ENABLED.equals(propertyName)) { setEnabled(((Boolean)evt.getNewValue()).booleanValue()); } } } @Override public boolean isOpaque() { return !myComboBoxAction.isSmallVariant(); } protected void updateButtonSize() { invalidate(); repaint(); setSize(getPreferredSize()); } }