replaced <code></code> with more concise {@code}
[idea/community.git] / platform / editor-ui-api / src / com / intellij / openapi / actionSystem / Presentation.java
1 /*
2  * Copyright 2000-2017 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 com.intellij.ide.ui.UISettings;
19 import com.intellij.openapi.util.Comparing;
20 import com.intellij.util.SmartFMap;
21 import com.intellij.util.ui.UIUtil;
22 import org.jetbrains.annotations.NonNls;
23 import org.jetbrains.annotations.NotNull;
24 import org.jetbrains.annotations.Nullable;
25
26 import javax.swing.*;
27 import java.beans.PropertyChangeListener;
28 import java.beans.PropertyChangeSupport;
29
30 /**
31  * The presentation of an action in a specific place in the user interface.
32  *
33  * @see AnAction
34  * @see ActionPlaces
35  */
36 public final class Presentation implements Cloneable {
37   private SmartFMap<String, Object> myUserMap = SmartFMap.emptyMap();
38
39   /**
40    * Defines tool tip for button at tool bar or text for element at menu
41    * value: String
42    */
43   @NonNls public static final String PROP_TEXT = "text";
44   /**
45    * value: Integer
46    */
47   @NonNls public static final String PROP_MNEMONIC_KEY = "mnemonicKey";
48   /**
49    * value: Integer
50    */
51   @NonNls public static final String PROP_MNEMONIC_INDEX = "mnemonicIndex";
52   /**
53    * value: String
54    */
55   @NonNls public static final String PROP_DESCRIPTION = "description";
56   /**
57    * value: Icon
58    */
59   @NonNls public static final String PROP_ICON = "icon";
60   /**
61    * value: Icon
62    */
63   @NonNls public static final String PROP_DISABLED_ICON = "disabledIcon";
64   /**
65    * value: Icon
66    */
67   @NonNls public static final String PROP_SELECTED_ICON = "selectedIcon";
68   /**
69    * value: Icon
70    */
71   @NonNls public static final String PROP_HOVERED_ICON = "hoveredIcon";
72   /**
73    * value: Boolean
74    */
75   @NonNls public static final String PROP_VISIBLE = "visible";
76   /**
77    * The actual value is a Boolean.
78    */
79   @NonNls public static final String PROP_ENABLED = "enabled";
80
81   public static final double DEFAULT_WEIGHT = 0;
82   public static final double HIGHER_WEIGHT = 42;
83   public static final double EVEN_HIGHER_WEIGHT = 239;
84
85   private final PropertyChangeSupport myChangeSupport = new PropertyChangeSupport(this);
86   private String myText;
87   private String myDescription;
88   private Icon myIcon;
89   private Icon myDisabledIcon;
90   private Icon myHoveredIcon;
91   private Icon mySelectedIcon;
92   private int myMnemonic;
93   private int myDisplayedMnemonicIndex = -1;
94   private boolean myVisible = true;
95   private boolean myEnabled = true;
96   private double myWeight = DEFAULT_WEIGHT;
97
98   public Presentation() {
99   }
100
101   public Presentation(String text) {
102     myText = text;
103   }
104
105   public void addPropertyChangeListener(PropertyChangeListener l) {
106     myChangeSupport.addPropertyChangeListener(l);
107   }
108
109   public void removePropertyChangeListener(PropertyChangeListener l) {
110     myChangeSupport.removePropertyChangeListener(l);
111   }
112
113   @Nullable
114   public String getText() {
115     return myText;
116   }
117
118   public void setText(@Nullable String text, boolean mayContainMnemonic) {
119     int oldMnemonic = myMnemonic;
120     int oldDisplayedMnemonicIndex = myDisplayedMnemonicIndex;
121     String oldText = myText;
122     myMnemonic = 0;
123     myDisplayedMnemonicIndex = -1;
124
125     if (text != null) {
126       if (text.indexOf(UIUtil.MNEMONIC) >= 0) {
127         text = text.replace(UIUtil.MNEMONIC, '&');
128       }
129
130       if (mayContainMnemonic) {
131         StringBuilder plainText = new StringBuilder();
132         for (int i = 0; i < text.length(); i++) {
133           char ch = text.charAt(i);
134           if (myMnemonic == 0 && (ch == '_' || ch == '&')) {
135             //noinspection AssignmentToForLoopParameter
136             i++;
137             if (i >= text.length()) break;
138             ch = text.charAt(i);
139             if (ch != '_' && ch != '&') {
140               if (UISettings.getInstance().getDisableMnemonicsInControls()) {
141                 myMnemonic = 0;
142                 myDisplayedMnemonicIndex = -1;
143               }
144               else {
145                 myMnemonic = Character.toUpperCase(ch);  // mnemonics are case insensitive
146                 myDisplayedMnemonicIndex = i - 1;
147               }
148             }
149           }
150           plainText.append(ch);
151         }
152         myText = plainText.length() == 0 ? "" : plainText.toString();
153       }
154       else {
155         myText = text.isEmpty() ? "" : text;
156       }
157     }
158     else {
159       myText = null;
160     }
161
162     myChangeSupport.firePropertyChange(PROP_TEXT, oldText, myText);
163     if (myMnemonic != oldMnemonic) {
164       myChangeSupport.firePropertyChange(PROP_MNEMONIC_KEY, new Integer(oldMnemonic), new Integer(myMnemonic));
165     }
166     if (myDisplayedMnemonicIndex != oldDisplayedMnemonicIndex) {
167       myChangeSupport.firePropertyChange(PROP_MNEMONIC_INDEX, new Integer(oldDisplayedMnemonicIndex), new Integer(myDisplayedMnemonicIndex));
168     }
169   }
170
171   public void setText(String text) {
172     setText(text, true);
173   }
174
175   public String getTextWithMnemonic() {
176     if (myText != null && myDisplayedMnemonicIndex > -1) {
177       return myText.substring(0, myDisplayedMnemonicIndex) + "_" + myText.substring(myDisplayedMnemonicIndex);
178     }
179     return myText;
180   }
181
182   public void restoreTextWithMnemonic(Presentation presentation) {
183     setText(presentation.getTextWithMnemonic());
184   }
185
186   public static String restoreTextWithMnemonic(@Nullable String text, final int mnemonic) {
187     if (text == null) {
188       return null;
189     }
190     for (int i = 0; i < text.length(); i++) {
191       if (Character.toUpperCase(text.charAt(i)) == mnemonic) {
192         return text.substring(0, i) + "_" + text.substring(i);
193       }
194     }
195     return text;
196   }
197
198   public String getDescription() {
199     return myDescription;
200   }
201
202   public void setDescription(String description) {
203     String oldDescription = myDescription;
204     myDescription = description;
205     myChangeSupport.firePropertyChange(PROP_DESCRIPTION, oldDescription, myDescription);
206   }
207
208   public Icon getIcon() {
209     return myIcon;
210   }
211
212   public void setIcon(@Nullable Icon icon) {
213     Icon oldIcon = myIcon;
214     if (oldIcon == icon) return;
215
216     myIcon = icon;
217     myChangeSupport.firePropertyChange(PROP_ICON, oldIcon, myIcon);
218   }
219
220   public Icon getDisabledIcon() {
221     return myDisabledIcon;
222   }
223
224   public void setDisabledIcon(@Nullable Icon icon) {
225     Icon oldDisabledIcon = myDisabledIcon;
226     myDisabledIcon = icon;
227     myChangeSupport.firePropertyChange(PROP_DISABLED_ICON, oldDisabledIcon, myDisabledIcon);
228   }
229
230   public Icon getHoveredIcon() {
231     return myHoveredIcon;
232   }
233
234   public void setHoveredIcon(@Nullable final Icon hoveredIcon) {
235     Icon old = myHoveredIcon;
236     myHoveredIcon = hoveredIcon;
237     myChangeSupport.firePropertyChange(PROP_HOVERED_ICON, old, myHoveredIcon);
238   }
239
240   public Icon getSelectedIcon() {
241     return mySelectedIcon;
242   }
243
244   public void setSelectedIcon(Icon selectedIcon) {
245     Icon old = mySelectedIcon;
246     mySelectedIcon = selectedIcon;
247     myChangeSupport.firePropertyChange(PROP_SELECTED_ICON, old, mySelectedIcon);
248   }
249
250   public int getMnemonic() {
251     return myMnemonic;
252   }
253
254   public int getDisplayedMnemonicIndex() {
255     return myDisplayedMnemonicIndex;
256   }
257
258   public boolean isVisible() {
259     return myVisible;
260   }
261
262   public void setVisible(boolean visible) {
263     boolean oldVisible = myVisible;
264     myVisible = visible;
265     firePropertyChange(PROP_VISIBLE, oldVisible, myVisible);
266   }
267
268   /**
269    * Returns the state of this action.
270    *
271    * @return {@code true} if action is enabled, {@code false} otherwise
272    */
273   public boolean isEnabled() {
274     return myEnabled;
275   }
276
277   /**
278    * Sets whether the action enabled or not. If an action is disabled, {@link AnAction#actionPerformed}
279    * won't be called. In case when action represents a button or a menu item, the
280    * representing button or item will be greyed out.
281    *
282    * @param enabled {@code true} if you want to enable action, {@code false} otherwise
283    */
284   public void setEnabled(boolean enabled) {
285     boolean oldEnabled = myEnabled;
286     myEnabled = enabled;
287     firePropertyChange(PROP_ENABLED, oldEnabled, myEnabled);
288   }
289
290   public final void setEnabledAndVisible(boolean enabled) {
291     setEnabled(enabled);
292     setVisible(enabled);
293   }
294
295   private void firePropertyChange(String propertyName, boolean oldValue, boolean newValue) {
296     if (oldValue != newValue) {
297       myChangeSupport.firePropertyChange(propertyName, oldValue, newValue);
298     }
299   }
300
301   @Override
302   public Presentation clone() {
303     Presentation presentation = new Presentation();
304     presentation.copyFrom(this);
305     return presentation;
306   }
307
308   public void copyFrom(Presentation presentation) {
309     setText(presentation.getTextWithMnemonic(), presentation.myDisplayedMnemonicIndex > -1);
310     setDescription(presentation.getDescription());
311     setIcon(presentation.getIcon());
312     setDisabledIcon(presentation.getDisabledIcon());
313     setHoveredIcon(presentation.getHoveredIcon());
314     setVisible(presentation.isVisible());
315     setEnabled(presentation.isEnabled());
316   }
317
318   @Nullable
319   public Object getClientProperty(@NonNls @NotNull String key) {
320     return myUserMap.get(key);
321   }
322
323   public void putClientProperty(@NonNls @NotNull String key, @Nullable Object value) {
324     Object oldValue = myUserMap.get(key);
325     if (Comparing.equal(oldValue, value)) return;
326     myUserMap = value == null ? myUserMap.minus(key) : myUserMap.plus(key, value);
327     myChangeSupport.firePropertyChange(key, oldValue, value);
328   }
329
330   public double getWeight() {
331     return myWeight;
332   }
333
334   /**
335    * Some action groups (like 'New...') may filter out actions with non-highest priority.
336    * @param weight please use {@link #HIGHER_WEIGHT} or {@link #EVEN_HIGHER_WEIGHT}
337    */
338   public void setWeight(double weight) {
339     myWeight = weight;
340   }
341
342   @Override
343   public String toString() {
344     return myText + " (" + myDescription + ")";
345   }
346
347   public boolean isEnabledAndVisible() {
348     return isEnabled() && isVisible();
349   }
350 }