| /* |
| * Copyright 2000-2014 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; |
| |
| import com.intellij.openapi.Disposable; |
| import com.intellij.openapi.project.DumbAware; |
| import com.intellij.openapi.project.PossiblyDumbAware; |
| import com.intellij.openapi.project.Project; |
| import com.intellij.openapi.util.Disposer; |
| import com.intellij.util.IncorrectOperationException; |
| import com.intellij.util.SmartList; |
| import org.intellij.lang.annotations.JdkConstants; |
| import org.jetbrains.annotations.NonNls; |
| import org.jetbrains.annotations.NotNull; |
| import org.jetbrains.annotations.Nullable; |
| |
| import javax.swing.*; |
| import java.util.List; |
| |
| /** |
| * Represents an entity that has a state, a presentation and can be performed. |
| * |
| * For an action to be useful, you need to implement {@link AnAction#actionPerformed} |
| * and optionally to override {@link com.intellij.openapi.actionSystem.AnAction#update}. By overriding the |
| * {@link com.intellij.openapi.actionSystem.AnAction#update} method you can dynamically change action's presentation |
| * depending on the place (for more information on places see {@link ActionPlaces}. |
| * |
| * The same action can have various presentations. |
| * |
| * <pre> |
| * public class MyAction extends AnAction { |
| * public MyAction() { |
| * // ... |
| * } |
| * |
| * public void update(AnActionEvent e) { |
| * Presentation presentation = e.getPresentation(); |
| * if (e.getPlace().equals(ActionPlaces.MAIN_MENU)) { |
| * presentation.setText("My Menu item name"); |
| * } else if (e.getPlace().equals(ActionPlaces.MAIN_TOOLBAR)) { |
| * presentation.setText("My Toolbar item name"); |
| * } |
| * } |
| * |
| * public void actionPerformed(AnActionEvent e) { ... } |
| * } |
| * </pre> |
| * |
| * @see AnActionEvent |
| * @see Presentation |
| * @see ActionPlaces |
| */ |
| public abstract class AnAction implements PossiblyDumbAware { |
| public static final AnAction[] EMPTY_ARRAY = new AnAction[0]; |
| @NonNls public static final String ourClientProperty = "AnAction.shortcutSet"; |
| |
| private Presentation myTemplatePresentation; |
| private ShortcutSet myShortcutSet; |
| private boolean myEnabledInModalContext; |
| |
| |
| private static final ShortcutSet ourEmptyShortcutSet = new CustomShortcutSet(); |
| private boolean myIsDefaultIcon = true; |
| private boolean myWorksInInjected; |
| |
| |
| /** |
| * Creates a new action with its text, description and icon set to <code>null</code>. |
| */ |
| public AnAction(){ |
| this(null, null, null); |
| } |
| |
| /** |
| * Creates a new action with <code>icon</code> provided. Its text, description set to <code>null</code>. |
| * |
| * @param icon Default icon to appear in toolbars and menus (Note some platform don't have icons in menu). |
| */ |
| public AnAction(Icon icon){ |
| this(null, null, icon); |
| } |
| |
| /** |
| * Creates a new action with the specified text. Description and icon are |
| * set to <code>null</code>. |
| * |
| * @param text Serves as a tooltip when the presentation is a button and the name of the |
| * menu item when the presentation is a menu item. |
| */ |
| public AnAction(@Nullable String text){ |
| this(text, null, null); |
| } |
| |
| /** |
| * Constructs a new action with the specified text, description and icon. |
| * |
| * @param text Serves as a tooltip when the presentation is a button and the name of the |
| * menu item when the presentation is a menu item |
| * |
| * @param description Describes current action, this description will appear on |
| * the status bar when presentation has focus |
| * |
| * @param icon Action's icon |
| */ |
| public AnAction(@Nullable String text, @Nullable String description, @Nullable Icon icon){ |
| myShortcutSet = ourEmptyShortcutSet; |
| myEnabledInModalContext = false; |
| Presentation presentation = getTemplatePresentation(); |
| presentation.setText(text); |
| presentation.setDescription(description); |
| presentation.setIcon(icon); |
| } |
| |
| /** |
| * Returns the shortcut set associated with this action. |
| * |
| * @return shortcut set associated with this action |
| */ |
| public final ShortcutSet getShortcutSet(){ |
| return myShortcutSet; |
| } |
| |
| /** |
| * Registers a set of shortcuts that will be processed when the specified component |
| * is the ancestor of focused component. Note that the action doesn't have |
| * to be registered in action manager in order for that shortcut to work. |
| * |
| * @param shortcutSet the shortcuts for the action. |
| * @param component the component for which the shortcuts will be active. |
| */ |
| public final void registerCustomShortcutSet(@NotNull ShortcutSet shortcutSet, @Nullable JComponent component){ |
| myShortcutSet = shortcutSet; |
| if (component != null){ |
| @SuppressWarnings("unchecked") |
| List<AnAction> actionList = (List<AnAction>)component.getClientProperty(ourClientProperty); |
| if (actionList == null){ |
| actionList = new SmartList<AnAction>(); |
| component.putClientProperty(ourClientProperty, actionList); |
| } |
| if (!actionList.contains(this)){ |
| actionList.add(this); |
| } |
| } |
| } |
| |
| public final void registerCustomShortcutSet(int keyCode, @JdkConstants.InputEventMask int modifiers, @Nullable JComponent component) { |
| registerCustomShortcutSet(new CustomShortcutSet(KeyStroke.getKeyStroke(keyCode, modifiers)), component); |
| } |
| |
| public final void registerCustomShortcutSet(@NotNull ShortcutSet shortcutSet, @NotNull final JComponent component, @NotNull Disposable parentDisposable) { |
| registerCustomShortcutSet(shortcutSet, component); |
| Disposer.register(parentDisposable, new Disposable() { |
| @Override |
| public void dispose() { |
| unregisterCustomShortcutSet(component); |
| } |
| }); |
| } |
| |
| public final void unregisterCustomShortcutSet(JComponent component){ |
| if (component != null){ |
| @SuppressWarnings("unchecked") |
| List<AnAction> actionList = (List<AnAction>)component.getClientProperty(ourClientProperty); |
| if (actionList != null){ |
| actionList.remove(this); |
| } |
| } |
| } |
| |
| /** |
| * Copies template presentation and shortcuts set from <code>sourceAction</code>. |
| * |
| * @param sourceAction cannot be <code>null</code> |
| */ |
| public final void copyFrom(@NotNull AnAction sourceAction){ |
| Presentation sourcePresentation = sourceAction.getTemplatePresentation(); |
| Presentation presentation = getTemplatePresentation(); |
| presentation.setIcon(sourcePresentation.getIcon()); |
| presentation.setText(sourcePresentation.getTextWithMnemonic()); |
| presentation.setDescription(sourcePresentation.getDescription()); |
| copyShortcutFrom(sourceAction); |
| } |
| |
| public final void copyShortcutFrom(@NotNull AnAction sourceAction) { |
| myShortcutSet = sourceAction.myShortcutSet; |
| } |
| |
| |
| public final boolean isEnabledInModalContext() { |
| return myEnabledInModalContext; |
| } |
| |
| protected final void setEnabledInModalContext(boolean enabledInModalContext) { |
| myEnabledInModalContext = enabledInModalContext; |
| } |
| |
| /** |
| * Override with true returned if your action has to display its text along with the icon when placed in the toolbar |
| */ |
| public boolean displayTextInToolbar() { |
| return false; |
| } |
| |
| /** |
| * Updates the state of the action. Default implementation does nothing. |
| * Override this method to provide the ability to dynamically change action's |
| * state and(or) presentation depending on the context (For example |
| * when your action state depends on the selection you can check for |
| * selection and change the state accordingly). |
| * This method can be called frequently, for instance, if an action is added to a toolbar, |
| * it will be updated twice a second. This means that this method is supposed to work really fast, |
| * no real work should be done at this phase. For example, checking selection in a tree or a list, |
| * is considered valid, but working with a file system is not. If you cannot understand the state of |
| * the action fast you should do it in the {@link #actionPerformed(AnActionEvent)} method and notify |
| * the user that action cannot be executed if it's the case. |
| * |
| * @param e Carries information on the invocation place and data available |
| */ |
| public void update(@NotNull AnActionEvent e) { |
| } |
| |
| /** |
| * Same as {@link #update(AnActionEvent)} but is calls immediately before actionPerformed() as final check guard. |
| * Default implementation delegates to {@link #update(AnActionEvent)}. |
| * |
| * @param e Carries information on the invocation place and data available |
| */ |
| public void beforeActionPerformedUpdate(@NotNull AnActionEvent e) { |
| boolean worksInInjected = isInInjectedContext(); |
| e.setInjectedContext(worksInInjected); |
| update(e); |
| if (!e.getPresentation().isEnabled() && worksInInjected) { |
| e.setInjectedContext(false); |
| update(e); |
| } |
| } |
| |
| /** |
| * Returns a template presentation that will be used |
| * as a template for created presentations. |
| * |
| * @return template presentation |
| */ |
| @NotNull |
| public final Presentation getTemplatePresentation() { |
| Presentation presentation = myTemplatePresentation; |
| if (presentation == null){ |
| myTemplatePresentation = presentation = new Presentation(); |
| } |
| return presentation; |
| } |
| |
| /** |
| * Implement this method to provide your action handler. |
| * |
| * @param e Carries information on the invocation place |
| */ |
| public abstract void actionPerformed(@NotNull AnActionEvent e); |
| |
| protected void setShortcutSet(ShortcutSet shortcutSet) { |
| myShortcutSet = shortcutSet; |
| } |
| |
| /** |
| * @deprecated Use KeymapUtil.createTooltipText() |
| */ |
| public static String createTooltipText(String s, @NotNull AnAction action) { |
| throw new IncorrectOperationException("Please use KeymapUtil.createTooltipText()"); |
| } |
| |
| /** |
| * Sets the flag indicating whether the action has an internal or a user-customized icon. |
| * @param isDefaultIconSet true if the icon is internal, false if the icon is customized by the user. |
| */ |
| public void setDefaultIcon(boolean isDefaultIconSet) { |
| myIsDefaultIcon = isDefaultIconSet; |
| } |
| |
| /** |
| * Returns true if the action has an internal, not user-customized icon. |
| * @return true if the icon is internal, false if the icon is customized by the user. |
| */ |
| public boolean isDefaultIcon() { |
| return myIsDefaultIcon; |
| } |
| |
| /** |
| * Enables automatic detection of injected fragments in editor. Values in DataContext, passed to the action, like EDITOR, PSI_FILE |
| * will refer to an injected fragment, if caret is currently positioned on it. |
| */ |
| public void setInjectedContext(boolean worksInInjected) { |
| myWorksInInjected = worksInInjected; |
| } |
| |
| public boolean isInInjectedContext() { |
| return myWorksInInjected; |
| } |
| |
| public boolean isTransparentUpdate() { |
| return this instanceof TransparentUpdate; |
| } |
| |
| @Override |
| public boolean isDumbAware() { |
| return this instanceof DumbAware; |
| } |
| |
| public interface TransparentUpdate { |
| } |
| |
| @Nullable |
| public static Project getEventProject(AnActionEvent e) { |
| return e == null ? null : e.getData(CommonDataKeys.PROJECT); |
| } |
| |
| @Override |
| public String toString() { |
| return getTemplatePresentation().toString(); |
| } |
| } |