popups: combo box action is insensetive to when no component is focused
[fedora-idea.git] / platform / platform-api / src / com / intellij / openapi / actionSystem / ex / ComboBoxAction.java
blobb069234e1bd364140daaf99ee3ae13232db88518
1 /*
2 * Copyright 2000-2009 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.openapi.actionSystem.ex;
18 import com.intellij.ide.DataManager;
19 import com.intellij.openapi.actionSystem.AnAction;
20 import com.intellij.openapi.actionSystem.AnActionEvent;
21 import com.intellij.openapi.actionSystem.DefaultActionGroup;
22 import com.intellij.openapi.actionSystem.Presentation;
23 import com.intellij.openapi.ui.popup.JBPopupFactory;
24 import com.intellij.openapi.ui.popup.ListPopup;
25 import com.intellij.openapi.util.IconLoader;
26 import com.intellij.openapi.wm.IdeFocusManager;
27 import com.intellij.util.ui.UIUtil;
28 import org.jetbrains.annotations.NotNull;
30 import javax.swing.*;
31 import java.awt.*;
32 import java.awt.event.ActionEvent;
33 import java.awt.event.ActionListener;
34 import java.beans.PropertyChangeEvent;
35 import java.beans.PropertyChangeListener;
37 public abstract class ComboBoxAction extends AnAction implements CustomComponentAction {
38 private static final Icon ARROW_ICON = IconLoader.getIcon("/general/comboArrow.png");
40 protected ComboBoxAction() {
43 public void actionPerformed(AnActionEvent e) {}
45 public JComponent createCustomComponent(Presentation presentation) {
46 JPanel panel=new JPanel(new GridBagLayout());
47 ComboBoxButton button = new ComboBoxButton(presentation);
48 panel.add(button,
49 new GridBagConstraints(0,0,1,1,1,1,GridBagConstraints.CENTER,GridBagConstraints.BOTH,new Insets(0,3,0,3),0,0)
51 return panel;
54 @NotNull
55 protected abstract DefaultActionGroup createPopupActionGroup(JComponent button);
57 protected int getMaxRows() {
58 return 30;
61 protected int getMinHeight() {
62 return 1;
65 protected int getMinWidth() {
66 return 1;
69 protected class ComboBoxButton extends JButton {
70 private final Presentation myPresentation;
71 private boolean myForcePressed = false;
72 private PropertyChangeListener myButtonSynchronizer;
74 public ComboBoxButton(Presentation presentation) {
75 myPresentation = presentation;
76 setModel(new MyButtonModel());
77 setHorizontalAlignment(SwingConstants.LEFT);
78 setFocusable(false);
79 Insets margins = getMargin();
80 setMargin(new Insets(margins.top, 2, margins.bottom, 2));
81 addActionListener(
82 new ActionListener() {
83 public void actionPerformed(ActionEvent e) {
84 if (!myForcePressed) {
85 IdeFocusManager.getGlobalInstance().doWhenFocusSettlesDown(new Runnable() {
86 public void run() {
87 showPopup();
89 });
95 //noinspection HardCodedStringLiteral
96 putClientProperty("Quaqua.Button.style", "placard");
99 public void showPopup() {
100 myForcePressed = true;
101 repaint();
103 Runnable onDispose = new Runnable() {
104 public void run() {
105 // give button chance to handle action listener
106 SwingUtilities.invokeLater(new Runnable() {
107 public void run() {
108 myForcePressed = false;
111 repaint();
115 ListPopup popup = createPopup(onDispose);
117 popup.showUnderneathOf(this);
120 protected ListPopup createPopup(Runnable onDispose) {
121 DefaultActionGroup group = createPopupActionGroup(this);
122 final ListPopup popup = JBPopupFactory.getInstance().createActionGroupPopup(null, group, DataManager.getInstance().getDataContext(),
123 JBPopupFactory.ActionSelectionAid.SPEEDSEARCH, false,
124 onDispose,
125 getMaxRows());
126 popup.setMinimumSize(new Dimension(getMinWidth(), getMinHeight()));
127 return popup;
130 public void removeNotify() {
131 if (myButtonSynchronizer != null) {
132 myPresentation.removePropertyChangeListener(myButtonSynchronizer);
133 myButtonSynchronizer = null;
135 super.removeNotify();
138 public void addNotify() {
139 super.addNotify();
140 if (myButtonSynchronizer == null) {
141 myButtonSynchronizer = new MyButtonSynchronizer();
142 myPresentation.addPropertyChangeListener(myButtonSynchronizer);
144 initButton();
147 private void initButton() {
148 setIcon(myPresentation.getIcon());
149 setEnabled(myPresentation.isEnabled());
150 setText(myPresentation.getText());
151 updateTooltipText(myPresentation.getDescription());
152 updateButtonSize();
155 private void updateTooltipText(String description) {
156 String tooltip = AnAction.createTooltipText(description, ComboBoxAction.this);
157 setToolTipText(tooltip.length() > 0 ? tooltip : null);
160 public void updateUI() {
161 super.updateUI();
162 if(UIUtil.isMotifLookAndFeel()){
163 setBorder(BorderFactory.createEtchedBorder());
164 }else{
165 setBorder(UIUtil.getButtonBorder());
169 protected class MyButtonModel extends DefaultButtonModel {
170 public boolean isPressed() {
171 return myForcePressed || super.isPressed();
174 public boolean isArmed() {
175 return myForcePressed || super.isArmed();
179 private class MyButtonSynchronizer implements PropertyChangeListener {
180 public void propertyChange(PropertyChangeEvent evt) {
181 String propertyName = evt.getPropertyName();
182 if (Presentation.PROP_TEXT.equals(propertyName)) {
183 setText((String)evt.getNewValue());
184 updateButtonSize();
186 else if (Presentation.PROP_DESCRIPTION.equals(propertyName)) {
187 updateTooltipText((String)evt.getNewValue());
189 else if (Presentation.PROP_ICON.equals(propertyName)) {
190 setIcon((Icon)evt.getNewValue());
191 updateButtonSize();
193 else if (Presentation.PROP_ENABLED.equals(propertyName)) {
194 setEnabled(((Boolean)evt.getNewValue()).booleanValue());
199 public final void paint(Graphics g) {
200 super.paint(g);
201 Dimension size = getSize();
202 String text = getText();
203 boolean isEmpty = getIcon() == null && (text == null || text.trim().length() == 0);
204 int x = isEmpty ? (size.width - ARROW_ICON.getIconWidth())/2 : size.width - ARROW_ICON.getIconWidth() - 2;
205 ARROW_ICON.paintIcon(null, g, x, (size.height - ARROW_ICON.getIconHeight()) / 2);
208 protected void updateButtonSize() {
209 int width;
210 String text = getText();
211 if ((text == null || text.trim().length() == 0) && getIcon() == null) {
212 width = ARROW_ICON.getIconWidth() + 10;
213 } else {
214 width = getUI().getPreferredSize(this).width + ARROW_ICON.getIconWidth() + 2;
216 setPreferredSize(new Dimension(width, 21));