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
;
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
);
49 new GridBagConstraints(0,0,1,1,1,1,GridBagConstraints
.CENTER
,GridBagConstraints
.BOTH
,new Insets(0,3,0,3),0,0)
55 protected abstract DefaultActionGroup
createPopupActionGroup(JComponent button
);
57 protected int getMaxRows() {
61 protected int getMinHeight() {
65 protected int getMinWidth() {
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
);
79 Insets margins
= getMargin();
80 setMargin(new Insets(margins
.top
, 2, margins
.bottom
, 2));
82 new ActionListener() {
83 public void actionPerformed(ActionEvent e
) {
84 if (!myForcePressed
) {
85 IdeFocusManager
.getGlobalInstance().doWhenFocusSettlesDown(new Runnable() {
95 //noinspection HardCodedStringLiteral
96 putClientProperty("Quaqua.Button.style", "placard");
99 public void showPopup() {
100 myForcePressed
= true;
103 Runnable onDispose
= new Runnable() {
105 // give button chance to handle action listener
106 SwingUtilities
.invokeLater(new Runnable() {
108 myForcePressed
= false;
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,
126 popup
.setMinimumSize(new Dimension(getMinWidth(), getMinHeight()));
130 public void removeNotify() {
131 if (myButtonSynchronizer
!= null) {
132 myPresentation
.removePropertyChangeListener(myButtonSynchronizer
);
133 myButtonSynchronizer
= null;
135 super.removeNotify();
138 public void addNotify() {
140 if (myButtonSynchronizer
== null) {
141 myButtonSynchronizer
= new MyButtonSynchronizer();
142 myPresentation
.addPropertyChangeListener(myButtonSynchronizer
);
147 private void initButton() {
148 setIcon(myPresentation
.getIcon());
149 setEnabled(myPresentation
.isEnabled());
150 setText(myPresentation
.getText());
151 updateTooltipText(myPresentation
.getDescription());
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() {
162 if(UIUtil
.isMotifLookAndFeel()){
163 setBorder(BorderFactory
.createEtchedBorder());
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());
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());
193 else if (Presentation
.PROP_ENABLED
.equals(propertyName
)) {
194 setEnabled(((Boolean
)evt
.getNewValue()).booleanValue());
199 public final void paint(Graphics 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() {
210 String text
= getText();
211 if ((text
== null || text
.trim().length() == 0) && getIcon() == null) {
212 width
= ARROW_ICON
.getIconWidth() + 10;
214 width
= getUI().getPreferredSize(this).width
+ ARROW_ICON
.getIconWidth() + 2;
216 setPreferredSize(new Dimension(width
, 21));