inline "other settings" submenu if it contains only one action (PY-4508)
[idea/community.git] / platform / platform-api / src / com / intellij / openapi / actionSystem / ActionGroup.java
1 /*
2  * Copyright 2000-2009 JetBrains s.r.o.
3  *
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
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
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.
15  */
16 package com.intellij.openapi.actionSystem;
17
18 import org.jetbrains.annotations.NonNls;
19 import org.jetbrains.annotations.NotNull;
20 import org.jetbrains.annotations.Nullable;
21
22 import javax.swing.*;
23 import java.beans.PropertyChangeListener;
24 import java.beans.PropertyChangeSupport;
25 import java.lang.reflect.Method;
26 import java.util.HashSet;
27 import java.util.Set;
28
29 /**
30  * Represents a group of actions.
31  */
32 public abstract class ActionGroup extends AnAction {
33   private boolean myPopup;
34   private final PropertyChangeSupport myChangeSupport = new PropertyChangeSupport(this);
35   public static final ActionGroup EMPTY_GROUP = new ActionGroup() {
36     @NotNull
37     @Override
38     public AnAction[] getChildren(@Nullable AnActionEvent e) {
39       return EMPTY_ARRAY;
40     }
41   };
42
43   private Set<AnAction> mySecondaryActions;
44
45   /**
46    * The actual value is a Boolean.
47    */
48   @NonNls public static final String PROP_POPUP = "popup";
49
50   private Boolean myDumbAware;
51
52   /**
53    * Creates a new <code>ActionGroup</code> with shortName set to <code>null</code> and
54    * popup set to false.
55    */
56   public ActionGroup(){
57     this(null, false);
58   }
59
60   /**
61    * Creates a new <code>ActionGroup</code> with the specified shortName
62    * and popup.
63    *
64    * @param shortName Text that represents a short name for this action group
65    *
66    * @param popup <code>true</code> if this group is a popup, <code>false</code>
67    *  otherwise
68    */
69   public ActionGroup(String shortName, boolean popup){
70     super(shortName);
71     setPopup(popup);
72   }
73
74   public ActionGroup(String text, String description, Icon icon) {
75     super(text, description, icon);
76   }
77
78   /**
79    * This method can be called in popup menus if {@link #canBePerformed(DataContext)} is true
80    */
81   public void actionPerformed(AnActionEvent e){
82   }
83
84   @Override
85   public void update(AnActionEvent e) {
86     super.update(e);
87   }
88
89   /**
90    * @return true if {@link #actionPerformed(AnActionEvent)} should be called
91    */
92   public boolean canBePerformed(DataContext context) {
93     return false;
94   }
95
96   /**
97    * Returns the type of the group.
98    *
99    * @return <code>true</code> if the group is a popup, <code>false</code> otherwise
100    */
101   public boolean isPopup(){
102     return myPopup;
103   }
104
105   /**
106    * Sets the type of the group.
107    *
108    * @param popup If <code>true</code> the group will be shown as a popup in menus
109    */
110   public final void setPopup(boolean popup){
111     boolean oldPopup = myPopup;
112     myPopup = popup;
113     firePropertyChange(PROP_POPUP, oldPopup?Boolean.TRUE:Boolean.FALSE, myPopup?Boolean.TRUE:Boolean.FALSE);
114   }
115
116   public final void addPropertyChangeListener(PropertyChangeListener l){
117     myChangeSupport.addPropertyChangeListener(l);
118   }
119
120   public final void removePropertyChangeListener(PropertyChangeListener l){
121     myChangeSupport.removePropertyChangeListener(l);
122   }
123
124   protected final void firePropertyChange(String propertyName, Object oldValue, Object newValue){
125     myChangeSupport.firePropertyChange(propertyName, oldValue, newValue);
126   }
127
128   /**
129    * Returns the children of the group.
130    *
131    * @return An array represting children of this group. All returned children must be not <code>null</code>.
132    */
133   @NotNull
134   public abstract AnAction[] getChildren(@Nullable AnActionEvent e);
135
136   final void setAsPrimary(AnAction action, boolean isPrimary) {
137     if (isPrimary) {
138       if (mySecondaryActions != null) {
139         mySecondaryActions.remove(action);
140       }
141     } else {
142       if (mySecondaryActions == null) {
143         mySecondaryActions = new HashSet<AnAction>();
144       }
145
146       mySecondaryActions.add(action);
147     }
148   }
149
150   public final boolean isPrimary(AnAction action) {
151     return mySecondaryActions == null || !mySecondaryActions.contains(action);
152   }
153
154   protected final void replace(AnAction originalAction, AnAction newAction) {
155     if (mySecondaryActions != null) {
156       if (mySecondaryActions.contains(originalAction)) {
157         mySecondaryActions.remove(originalAction);
158         mySecondaryActions.add(newAction);
159       }
160     }
161   }
162
163   @Override
164   public boolean isDumbAware() {
165     if (myDumbAware != null) {
166       return myDumbAware;
167     }
168
169     boolean dumbAware = super.isDumbAware();
170     if (dumbAware) {
171       myDumbAware = Boolean.valueOf(dumbAware);
172     } else {
173       if (myDumbAware == null) {
174         try {
175           Method updateMethod = getClass().getMethod("update", AnActionEvent.class);
176           Class<?> declaringClass = updateMethod.getDeclaringClass();
177           myDumbAware = AnAction.class.equals(declaringClass) || ActionGroup.class.equals(declaringClass);
178         }
179         catch (NoSuchMethodException e) {
180           myDumbAware = Boolean.FALSE;
181         }
182       }
183     }
184
185     return myDumbAware;
186   }
187 }