Merge pull request #235 from JohnHake/IJSDK-690

IJSDK-690
This commit is contained in:
John Hake 2019-12-16 22:17:54 -08:00 committed by GitHub
commit 660a76f1e6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 401 additions and 291 deletions

View File

@ -80,8 +80,8 @@
* [Exposing Theme Metadata](reference_guide/ui_themes/themes_metadata.md)
* [Actions](basics/action_system.md)
* [Actions Tutorial](tutorials/action_system.md)
* [1. Registering an Action](tutorials/action_system/working_with_custom_actions.md)
* [2. Grouping Actions](tutorials/action_system/grouping_action.md)
* [Creating Actions](tutorials/action_system/working_with_custom_actions.md)
* [Grouping Actions](tutorials/action_system/grouping_action.md)
* Settings
* [Persisting State of Components](basics/persisting_state_of_components.md)
* [Persisting Sensitive Data](basics/persisting_sensitive_data.md)

View File

@ -2,42 +2,159 @@
title: Action System
---
## Executing and updating actions
The system of actions allows plugins to add their own items to IDEA menus and toolbars. An action is a class, derived from the [`AnAction`](upsource:///platform/editor-ui-api/src/com/intellij/openapi/actionSystem/AnAction.java) class, whose `actionPerformed` method is called when the menu item or toolbar button is selected.
## Introduction
The actions system is an extension point that allows plugins to add their items to IntelliJ Platform-based IDE menus and toolbars.
For example, one of the action classes is responsible for the **File \| Open File...** menu item and for the **Open File** toolbar button.
Actions are organized into groups, which, in turn, can contain other groups. A group of actions can form a toolbar or a menu.
Subgroups of the group can form submenus of the menu.
Actions in the IntelliJ Platform require a [code implementation](#action-implementation) and must be [registered](#registering-actions) with the IntelliJ Platform.
The action implementation determines the contexts in which an action is available, and its functionality when it is selected in the UI.
Registration determines where an action appears in the IDE UI.
Once implemented and registered, an action receives callbacks from the IntelliJ Platform in response to user gestures.
Every action and action group has an unique identifier. Identifiers of many of the standard IDEA actions are defined in the [`IdeActions`](upsource:///platform/platform-api/src/com/intellij/openapi/actionSystem/IdeActions.java) class.
The [Creating Actions](/tutorials/action_system/working_with_custom_actions.md) tutorial describes the process of adding a custom action to a plugin.
The [Grouping Actions](/tutorials/action_system/grouping_action.md) tutorial demonstrates three types of groups that can contain actions.
The rest of this page is an overview of actions as an extension point.
Every action can be included in multiple groups, and thus appear in multiple places within the IDEA user interface. Different places where actions can appear are defined by constants in the [`ActionPlaces`](upsource:///platform/platform-api/src/com/intellij/openapi/actionSystem/ActionPlaces.java) interface. For every place where the action appears, a new [`Presentation`](upsource:///platform/platform-api/src/com/intellij/ide/presentation/Presentation.java) is created. Thus, the same action can have different text or icons when it appears in different places of the user interface. Different presentations for the action are created by copying the presentation returned by the `AnAction.getTemplatePresentation()` method.
* bullet list
{:toc}
To update the state of the action, the method `AnAction.update()` is periodically called by IDEA. The [`AnActionEvent`](upsource:///platform/editor-ui-api/src/com/intellij/openapi/actionSystem/AnActionEvent.java) object passed to this method carries the information about the current context for the action, and in particular, the specific presentation which needs to be updated.
## Action Implementation
An action is a class derived from the abstract class [`AnAction`](upsource:///platform/editor-ui-api/src/com/intellij/openapi/actionSystem/AnAction.java).
The IntelliJ Platform calls methods of an action when a user interacts with a menu item or toolbar button.
To retrieve the information about the current state of the IDE, including the active project, the selected file, the selection in the editor and so on, the method `AnActionEvent.getData()` can be used. Different data keys that can be passed to that method are defined in the [`CommonDataKeys`](upsource:///platform/editor-ui-api/src/com/intellij/openapi/actionSystem/CommonDataKeys.java)class.
> **Warning** Classes based on `AnAction` do not have class fields of any kind. This is because an instance of `AnAction` class
exists for the entire lifetime of the application. If `AnAction` class uses a field to store data that has a shorter
lifetime, and doesn't clear this data promptly, the data will be leaked. For example, any `AnAction` data that exists
only within the context of a `Project` will cause the `Project` to be kept in memory after the user has closed it.
The `AnActionEvent` instance is also passed to the `actionPerformed` method.
### Principal Implementation Overrides
Every IntelliJ Platform action should override `AnAction.update()` and must override `AnAction.actionPerformed()`.
* An action's method `AnAction.update()` is called by the IntelliJ Platform framework to update the state of an action.
The state (enabled, visible) of an action determines whether the action is available in the UI of an IDE.
An object of type [`AnActionEvent`](upsource:///platform/editor-ui-api/src/com/intellij/openapi/actionSystem/AnActionEvent.java) is passed to this method, and it contains the information about the current context for the action.
Actions are made available by changing state in the [Presentation](upsource:///platform/platform-api/src/com/intellij/ide/presentation/Presentation.java) object associated with the event context.
As explained in [Overriding the `AnAction.update()` Method](#overriding-the-anactionupdate-method), it is vital `update()` methods _execute quickly_ and return execution to the IntelliJ Platform.
* An action's method `AnAction.actionPerformed()` is called by the IntelliJ Platform if it is available and selected by the user.
This method does the heavy lifting for the action - it contains the code to be executed when the action is invoked.
The `actionPerformed()` method also receives `AnActionEvent` as a parameter, which can be used to access projects, files, selection, etc.
See [Overriding the `AnAction.actionPerformed()` Method](#overriding-the-anactionactionperformed-method) for more information.
There are other methods to override in the `AnAction` class, such as for changing the default `Presentation` object for the action.
There is also a use case for overriding action constructors when registering them with dynamic action groups, which is demonstrated in the [Grouping Actions](/tutorials/action_system/grouping_action.md#adding-child-actions-to-the-dynamic-group) tutorial.
However, the `update()` and `actionPerformed()` methods are essential to basic operation.
For a step-by-step walkthrough of defining actions, please check out the [action system tutorial](/tutorials/action_system.md).
### Overriding the AnAction.update Method
The method `AnAction.update()` is periodically called by the IntelliJ Platform in response to user gestures.
The `update()` method gives an action to evaluate the current context and enable or disable its functionality.
> **Warning** The `AnAction.update()` method can be called frequently, and on a UI thread.
This method needs to _execute very quickly_; no real work should be performed in this method.
For example, checking selection in a tree or a list is considered valid, but working with the file system is not.
> **Tip** If the new state of an action cannot be determined quickly, then evaluation should be performed in the `AnAction.actionPerformed()` method, and notify the user that the action cannot be executed if the context isn't suitable.
#### Determining the Action Context
The `AnActionEvent` object passed to `update()` carries information about the current context for the action.
Context information is available from the methods of `AnActionEvent`, providing information such as the Presentation, and whether the action is triggered from a Toolbar.
Additional context information is available using the method `AnActionEvent.getData()`.
Keys defined in [`CommonDataKeys`](upsource:///platform/editor-ui-api/src/com/intellij/openapi/actionSystem/CommonDataKeys.java) are passed to the `getData()` method to retrieve objects such as `Project`, `Editor`, `PsiFile`, and other information.
Accessing this information is relatively light-weight and is suited for `AnAction.update()`.
#### Enabling and Setting Visibility for an Action
Based on information about the action context, the `AnAction.update()` method can enable, disable, or hide an action.
An action's enable/disable state and visibility are set using methods of the `Presentation` object, which is accessed using `AnActionEvent.getPresentation()`.
The default `Presentation` object is a set of descriptive information about a menu or toolbar action.
Every context for an action - it might appear in multiple menu or toolbar locations - has a unique presentation.
Attributes such as an action's text, description, and icons, as well as visibility and enable/disable state, are stored in the presentation.
The attributes in a presentation get initialized from the [action registration](#registering-actions).
However, some can be changed at runtime using the methods of the `Presentation` object associated with an action.
The enabled/disabled state of an action is set using `Presentation.setEnabled()`.
The visibility state of an action is set using `Presentation.setVisible()`
If an action is enabled, the `AnAction.actionPerformed()` can be called if an action is selected in the IDE by a user.
A menu action will be shown in the UI location specified in the registration.
A toolbar action will display its enabled (or selected) icon, depending on the user interaction.
When an action is disabled `AnAction.actionPerformed()` will not be called.
Toolbar actions will display their respective icons for the disabled state.
The visibility of a disabled action in a menu depends on whether the host menu (e.g. "ToolsMenu") containing the action has the `compact` attribute set.
See [Grouping Actions](#grouping-actions) for more information about the `compact` attribute, and the visibility of menu actions.
> **Note** If an action is added to a toolbar, its `update()` can be called if there was any user activity or focus transfer.
If the action's availability changes in the absence of these events, then call [`ActivityTracker.getInstance().inc()`](upsource:///platform/platform-api/src/com/intellij/ide/ActivityTracker.java) to notify the action subsystem to update all toolbar actions.
An example of enabling a menu action based on whether a project is open is demonstrated in [`PopupDialogAction.update()`](https://github.com/JetBrains/intellij-sdk-docs/blob/master/code_samples/action_basics/src/main/java/org/intellij/sdk/action/PopupDialogAction.java) method.
### Overriding the AnAction.actionPerformed Method
When the user selects an enabled action, be it from a menu or toolbar, the action's `AnAction.actionPerformed()` method is called.
This method contains the code to be executed to perform the action, and it is here that the real work gets done.
Using the `AnActionEvent` methods and `CommonDataKeys`, objects such as the `Project`, `Editor`, `PsiFile`, and other information is available.
For example, the `actionPerformed()` method can modify, remove, or add PSI elements to a file open in the editor.
The code that executes in the `AnAction.actionPerformed()` method should execute efficiently, but it does not have to meet the same stringent requirements as the `update()` method.
<!-- TODO: does this all happen inside a transaction? Does that ensure the undo step? -->
An example of inspecting PSI elements is demonstrated in the SDK code sample `action_basics` [`PopupDialogAction.actionPerformed()`](https://github.com/JetBrains/intellij-sdk-docs/blob/master/code_samples/action_basics/src/main/java/org/intellij/sdk/action/PopupDialogAction.java) method.
### Action IDs
Every action and action group has a unique identifier.
Basing the identifier for a custom action on the FQN of the implementation is the best practice, assuming the package incorporates the `<id>` of the plugin.
An action must have a unique identifier for each place it is used in the IDE UI, even though the FQN of the implementation is the same.
Definitions of identifiers for the standard IntelliJ Platform actions are in [`IdeActions`](upsource:///platform/platform-api/src/com/intellij/openapi/actionSystem/IdeActions.java).
### Grouping Actions
Groups organize actions into logical UI structures, which in turn can contain other groups.
A group of actions can form a toolbar or a menu.
Subgroups of a group can form submenus of a menu.
Actions can be included in multiple groups, and thus appear in multiple places within the IDE UI.
An action must have a unique identifier for each place it appears in the IDE UI.
The places where actions can appear are defined by constants in [`ActionPlaces`](upsource:///platform/platform-api/src/com/intellij/openapi/actionSystem/ActionPlaces.java).
Group IDs for the IntelliJ Platform are defined in [PlatformActions](upsource:///platform/platform-resources/src/idea/PlatformActions.xml).
<!-- TODO: Reconcile ActionPlaces vs. PlatformActions -->
For every place where the action appears, a new [`Presentation`](upsource:///platform/platform-api/src/com/intellij/ide/presentation/Presentation.java) is created.
Therefore the same action can have different text or icons when it appears in different places of the user interface.
Different presentations for the action are created by copying the Presentation returned by the `AnAction.getTemplatePresentation()` method.
A group's "compact" attribute specifies whether an action within that group is visible when disabled.
See [Registering Actions in plugin.xml](#registering-actions-in-pluginxml) for an explanation of how the `compact` attribute is set for a group.
If the `compact` attribute is `true` for a menu group, an action in the menu will only appear if its state is both enabled and visible.
In contrast, if the `compact` attribute is `false`, an action in the menu will appear if its state is disabled but visible.
Some menus like **Tools** have the `compact` attribute set, so there isn't a way to show an action on the tools menu if it is not enabled.
| Host Menu<br>`compact` Setting | Action Enabled | Visibility Enabled | Menu Item Visible? | Menu Item Appears Gray? |
| :-----: | :------------: | :----------------: | :----------------: | :---------------------: |
| F | T | T | T | F |
| F | T | F | F | x |
| ***F*** | F | T | ***T*** | ***T*** |
| F | F | F | F | x |
| T | T | T | T | F |
| T | T | F | F | x |
| ***T*** | F | T | ***F*** | x |
| T | F | F | F | x |
See the [Grouping Actions](/tutorials/action_system/grouping_action.md) tutorial for examples of creating action groups.
## Registering Actions
There are two main ways to register an action: either by listing it in the `<actions>` section of the `plugin.xml` file, or through Java code.
There are two main ways to register an action: either by listing it in the `<actions>` section of a plugin's `plugin.xml` file, or through code.
### Registering Actions in plugin.xml
Registering actions in `plugin.xml` is demonstrated in the following example. The example section of `plugin.xml` demonstrates all elements which can be used in the `<actions>` section, and describes the meaning of each element.
Registering actions in `plugin.xml` is demonstrated in the following example, which documents all elements and attributes that can be used in the `<actions>` section, and describes the meaning of each element.
This information can also be found by using the [Code Completion](https://www.jetbrains.com/help/idea/auto-completing-code.html#invoke-basic-completion), [Quick Definition](https://www.jetbrains.com/help/idea/viewing-reference-information.html#view-definition-symbols) and [Quick Documentation](https://www.jetbrains.com/help/idea/viewing-reference-information.html#inline-quick-documentation) features.
```xml
<!-- Actions -->
<actions>
<!-- The <action> element defines an action to register.
The mandatory "id" attribute specifies an unique
The mandatory "id" attribute specifies a unique
identifier for the action.
The mandatory "class" attribute specifies the
full-qualified name of the class implementing the action.
FQN of the class implementing the action.
The mandatory "text" attribute specifies the text of the
action (tooltip for toolbar button or text for menu item).
The optional "use-shortcut-of" attribute specifies the ID
@ -62,7 +179,7 @@ Registering actions in `plugin.xml` is demonstrated in the following example. Th
<!-- The <keyboard-shortcut> node specifies the keyboard shortcut
for the action. An action can have several keyboard shortcuts.
The mandatory "first-keystroke" attribute specifies the first
keystroke of the action. The key strokes are specified according
keystroke of the action. The keystrokes are specified according
to the regular Swing rules.
The optional "second-keystroke" attribute specifies the second
keystroke of the action.
@ -98,21 +215,23 @@ Registering actions in `plugin.xml` is demonstrated in the following example. Th
</action>
<!-- The <group> element defines an action group. <action>, <group> and
<separator> elements defined within it are automatically included in the group.
The mandatory "id" attribute specifies an unique identifier for the action.
The optional "class" attribute specifies the full-qualified name of
The mandatory "id" attribute specifies a unique identifier for the action.
The optional "class" attribute specifies the FQN of
the class implementing the group. If not specified,
com.intellij.openapi.actionSystem.DefaultActionGroup is used.
The optional "text" attribute specifies the text of the group (text
for the menu item showing the submenu).
The optional "description" attribute specifies the text which is displayed
in the status bar when the group is focused.
in the status bar when the group has focus.
The optional "icon" attribute specifies the icon which is displayed on
the toolbar button or next to the group.
the toolbar button or next to the menu group.
The optional "popup" attribute specifies how the group is presented in
the menu. If a group has popup="true", actions in it are placed in a
submenu; for popup="false", actions are displayed as a section of the
same menu delimited by separators. -->
<group class="com.foo.impl.MyActionGroup" id="TestActionGroup" text="Test Group" description="Group with test actions" icon="icons/testgroup.png" popup="true">
same menu delimited by separators.
The optional "compact" attribute specifies whether an action within that group is visible when disabled.
Setting compact="true" specifies an action in the group isn't visible unless the action is enabled. -->
<group class="com.foo.impl.MyActionGroup" id="TestActionGroup" text="Test Group" description="Group with test actions" icon="icons/testgroup.png" popup="true" compact="true">
<action id="VssIntegration.TestAction" class="com.foo.impl.TestAction" text="My Test Action" description="My test action"/>
<!-- The <separator> element defines a separator between actions.
It can also have an <add-to-group> child element. -->
@ -126,15 +245,16 @@ Registering actions in `plugin.xml` is demonstrated in the following example. Th
</actions>
```
## Registering Actions from Code
To register an action from code, two steps are required.
* First, an instance of the class derived from `AnAction` must be passed to the `registerAction` method of the [`ActionManager`](upsource:///platform/editor-ui-api/src/com/intellij/openapi/actionSystem/ActionManager.java) class, to associate the action with an ID.
* Second, the action needs to be added to one or more groups. To get an instance of an action group by ID, it is necessary to call `ActionManager.getAction()` and cast the returned value to the [`DefaultActionGroup`](upsource:///platform/platform-api/src/com/intellij/openapi/actionSystem/DefaultActionGroup.java) class.
### Registering Actions from Code
Two steps are required to register an action from code:
* First, an instance of the class derived from `AnAction` must be passed to the `registerAction()` method of [`ActionManager`](upsource:///platform/editor-ui-api/src/com/intellij/openapi/actionSystem/ActionManager.java), to associate the action with an ID.
* Second, the action needs to be added to one or more groups.
To get an instance of an action group by ID, it is necessary to call `ActionManager.getAction()` and cast the returned value to [`DefaultActionGroup`](upsource:///platform/platform-api/src/com/intellij/openapi/actionSystem/DefaultActionGroup.java).
## Building UI from Actions
If a plugin needs to include a toolbar or popup menu built from a group of actions in its user interface, that is accomplished through [`ActionPopupMenu`](upsource:///platform/editor-ui-api/src/com/intellij/openapi/actionSystem/ActionPopupMenu.java) and [`ActionToolbar`](upsource:///platform/editor-ui-api/src/com/intellij/openapi/actionSystem/ActionToolbar.java).
These objects can be created through calls to the `ActionManager.createActionPopupMenu()` and `createActionToolbar()` methods.
To get a Swing component from such an object, call the respective `getComponent()` method.
If a plugin needs to include a toolbar or popup menu built from a group of actions in its own user interface, that can be accomplished through the [`ActionPopupMenu`](upsource:///platform/editor-ui-api/src/com/intellij/openapi/actionSystem/ActionPopupMenu.java) and [`ActionToolbar`](upsource:///platform/editor-ui-api/src/com/intellij/openapi/actionSystem/ActionToolbar.java) classes. These objects can be created through calls to `ActionManager.createActionPopupMenu` and `ActionManager.createActionToolbar`. To get a Swing component from such an object, simply call the getComponent() method.
If your action toolbar is attached to a specific component (for example, a panel in a tool window), you usually need to call `ActionToolbar.setTargetComponent()` and pass the instance of the related component as a parameter. This ensures that the state of the toolbar buttons depends on the state of the related component, and not on the current focus location within the IDE frame.
If an action toolbar is attached to a specific component (for example, a panel in a tool window), call `ActionToolbar.setTargetComponent()` and pass the instance of the related component as a parameter.
Setting the target ensures that the state of the toolbar buttons depends on the state of the related component, and not on the current focus location within the IDE frame.

View File

@ -1,19 +1,15 @@
---
title: IntelliJ Action System
title: IntelliJ Action System Tutorial
---
This tutorial leads you through a series of steps which show how to create, register, and customize custom actions
and action groups. By registering actions, you can add your own menu items, toolbar buttons and keyboard shortcuts
to the IntelliJ IDEA user interface. For more information, please refer to the [IntelliJ Platform Action System](/basics/action_system.md)
documentation.
* [Registering Actions](action_system/working_with_custom_actions.md)
* [Grouping Action](action_system/grouping_action.md)
This tutorial leads you through a series of steps which show how to create, register, and customize custom actions and action groups.
By registering actions, you can add your own menu items, toolbar buttons and keyboard shortcuts to the IntelliJ IDEA user interface.
* [Creating Actions](action_system/working_with_custom_actions.md)
* [Grouping Actions](action_system/grouping_action.md)
[Plugin source code](https://github.com/JetBrains/intellij-sdk-docs/tree/master/code_samples/register_actions)
[Home](/)
The source code for the [`action_basics`](https://github.com/JetBrains/intellij-sdk-docs/tree/master/code_samples/action_basics) code sample is used throughout this tutorial.

View File

@ -1,148 +1,130 @@
---
title: 2. Grouping Actions
title: Grouping Actions
---
If an implementation requires several actions, or there are simply too many actions that overload the menu, they can be joined into groups.
If an implementation requires several actions, or there are simply too many actions that overload the menu, the actions can be placed into groups.
This tutorial demonstrates adding an action to an existing group, creating a new action group, and action groups with a variable number of actions.
The sample code discussed in this tutorial is from the code sample [`action_basics`].
### 2.1. Simple action groups
Some content in this tutorial assumes the reader is familiar with the tutorial for [Creating Actions](working_with_custom_actions.md).
In this first example the action group will be available as a top-level menu item, and actions will be represented as drop-down menu items.
* bullet list
{:toc}
#### 2.1.1. Creating simple action groups
## Simple Action Groups
In this first example, the action group will be available as a top-level menu item, and actions are represented as drop-down menu items.
The group is based on a default IntelliJ Platform implementation.
Grouping can be done by adding a `<group>` element to the `<actions>` section in
[plugin.xml](https://github.com/JetBrains/intellij-sdk-docs/blob/master/code_samples/register_actions/resources/META-INF/plugin.xml).
Note this example has no `class` attribute in the `<group>` element because we want the IntelliJ Platform framework to
supply a default implementation class for the group. Section 2.2 discusses using specialized implementations. The `id` attribute
must be unique, so incorporating the plugin ID or package name is encouraged.
### Creating Simple Groups
Grouping can be registered by adding a `<group>` element to the `<actions>` section of a plugin's `plugin.xml` file.
This example has no `class` attribute in the `<group>` element because the IntelliJ Platform framework will supply a default implementation class for the group.
This default implementation is used if a set of actions belonging to the group is static, i.e. does not change at runtime, which is the majority of cases.
The `id` attribute must be unique, so incorporating the plugin ID or package name is the best practice.
The `popup` attribute determines whether actions in the group are placed in a submenu.
The `icon` attribute specifies the FQN of an [`Icon`](/reference_guide/work_with_icons_and_images.md) object to be displayed.
No `compact` attribute is specified, which means this group will support submenus.
See [Registering Actions in plugin.xml](/basics/action_system.md#registering-actions-in-pluginxml) for more information about these attributes.
```xml
<actions>
<group id="org.jetbrains.tutorials.actions.GroupedActions" text="Example Grouped Actions" popup="true">
<group id="org.intellij.sdk.action.GroupedActions" text="Static Grouped Actions" popup="true" icon="ActionBasicsIcons.Sdk_default_icon">
</group>
</actions>
```
#### 2.1.2. Binding action groups to UI components
The following sample shows how to use an `<add-to-group>` element to place a custom action group relative to
an entry in the **Tools** menu. Note the attribute `relative-to-action` references the action `id` for `SimpleAction`, which is not a native IntelliJ menu entry.
Rather `SimpleAction` is defined in the same
[plugin.xml](https://github.com/JetBrains/intellij-sdk-docs/blob/master/code_samples/register_actions/resources/META-INF/plugin.xml) file.
### Binding Action Groups to UI Components
The following sample shows how to use an `<add-to-group>` element to place a custom action group relative to an entry in the **Tools** menu.
The attribute `relative-to-action` references the action `id` for `PopupDialogAction`, which is not a native IntelliJ menu entry.
Rather `PopupDialogAction` is defined in the same [plugin.xml](https://github.com/JetBrains/intellij-sdk-docs/blob/master/code_samples/action_basics/src/main/resources/META-INF/plugin.xml) file.
This group is placed after the single entry for the action `PopupDialogAction`, as defined in the tutorial [Creating Actions](working_with_custom_actions.md#registering-an-action-with-the-new-action-form).
```xml
<actions>
<group id="org.jetbrains.tutorials.actions.GroupedActions" text="Example Grouped Actions" popup="true">
<add-to-group group-id="ToolsMenu" anchor="after" relative-to-action="org.jetbrains.tutorials.actions.SimpleAction"/>
<group id="org.intellij.sdk.action.GroupedActions" text="Static Grouped Actions" popup="true" icon="ActionBasicsIcons.Sdk_default_icon">
<add-to-group group-id="ToolsMenu" anchor="after" relative-to-action="org.intellij.sdk.action.PopupDialogAction"/>
</group>
</actions>
```
#### 2.1.3. Creating an action for the simple action group
To create an action we need to extend the
[`AnAction`](upsource:///platform/editor-ui-api/src/com/intellij/openapi/actionSystem/AnAction.java)
class. This example uses the `SimplePopDialogAction` class, which pops a dialog to give users feedback when a
menu item is chosen. See the [Registering an Action](working_with_custom_actions.md)
page for more information about this class.
#### 2.1.4. Adding an action to the simple action group
Now the `SimplePopDialogAction` needs to be registered in the newly created group. Note the `id` attribute is set to
something unique, and different from, the fully qualified `class` attribute in the `<group>` element. A unique `id` supports reuse of
action classes in more than one menu or group.
### Adding a New Action to the Static Grouped Actions
The `PopupDialogAction` implementation will be reused and registered in the newly created static group.
The `id` attribute for the reused `PopupDialogAction` implementation is set to a unique value, `org.intellij.sdk.action.GroupPopDialogAction`.
This value differentiates this new `<action>` entry from the `id` previously used to register this action implementation in the [Creating Actions](working_with_custom_actions.md#registering-an-action-with-the-new-action-form) tutorial.
A unique `id` supports reuse of action classes in more than one menu or group.
The action in this group will display the menu text "A Group Action".
```xml
<group id="org.jetbrains.tutorials.actions.GroupedActions" text="Example Grouped Actions" popup="true">
<add-to-group group-id="ToolsMenu" anchor="after" relative-to-action="org.jetbrains.tutorials.actions.SimpleAction"/>
<action class="org.jetbrains.tutorials.actions.SimplePopDialogAction"
id="org.jetbrains.tutorials.actions.SimpleGroupedAction" text="A Grouped Action" description="Grouped Action Demo">
</action>
</group>
<group id="org.intellij.sdk.action.GroupedActions" text="Static Grouped Actions" popup="true" icon="ActionBasicsIcons.Sdk_default_icon">
<add-to-group group-id="ToolsMenu" anchor="after" relative-to-action="org.intellij.sdk.action.PopupDialogAction"/>
<action class="org.intellij.sdk.action.PopupDialogAction" id="org.intellij.sdk.action.GroupPopDialogAction"
text="A Group Action" description="SDK static grouped action example" icon="ActionBasicsIcons.Sdk_default_icon">
</action>
</group>
```
After performing the steps described above the action group and its content will be available in the **Tools** menu:
After performing the steps described above the action group and its content will be available in the **Tools** menu.
The underlying `PopupDialogAction` implementation is reused for two entries in the **Tools** menu:
* Once for the top menu entry **Tools \| Pop Dialog Action** with the action `id` equal to `org.intellij.sdk.action.PopupDialogAction` as set in the [Creating Actions](/tutorials/action_system/working_with_custom_actions.md#registering-an-action-with-the-new-action-form) tutorial.
* A section time for the menu entry **Tools \| Static Grouped Actions \| A Group Action** with the action `id` equal to `org.intellij.sdk.action.GroupPopDialogAction`.
![Simple Action Group](img/grouped_action.png)
![Simple Action Group](img/grouped_action.png){:width="550px"}
### 2.2. Implementing custom action group classes
## Implementing Custom Action Group Classes
In some cases, the specific behavior of a group of actions needs to depend on the context.
The solution is analagous to making a [single action entry dependent on context](working_with_custom_actions.md#extending-the-update-method).
In some cases we need to implement some specific behaviour of a group of actions depending on the context.
The steps below show how to make a group of actions available and visible if certain conditions are met.
In this case the condition is having an instance of an editor is available. This condition is needed because the custom
action group will be added to an IntelliJ menu that is only enabled for editing.
In this case, the condition is having an instance of an editor is available.
This condition is needed because the custom action group will be added to an IntelliJ menu that is only enabled for editing.
#### 2.2.1. Extending DefaultActionGroup
[`DefaultActionGroup`](upsource:///platform/platform-api/src/com/intellij/openapi/actionSystem/DefaultActionGroup.java)
is an implementation of
[`ActionGroup`](upsource:///platform/editor-ui-api/src/com/intellij/openapi/actionSystem/ActionGroup.java).
### Extending DefaultActionGroup
The [`DefaultActionGroup`](upsource:///platform/platform-api/src/com/intellij/openapi/actionSystem/DefaultActionGroup.java) is an implementation of [`ActionGroup`](upsource:///platform/editor-ui-api/src/com/intellij/openapi/actionSystem/ActionGroup.java).
The `DefaultActionGroup` class is used to add child actions and separators between them to a group.
This class is used if a set of actions belonging to the group does not change at runtime, which is the majority of all the cases.
(See section 2.3 for groups with variable child actions at runtime.)
This class is used if a set of actions belonging to the group does not change at runtime, which is the majority of cases.
As an example we will extend
[`DefaultActionGroup`](upsource:///platform/platform-api/src/com/intellij/openapi/actionSystem/DefaultActionGroup.java)
to create the `CustomDefaultActionGroup` class in the `register_actions` code sample:
As an example, extend [`DefaultActionGroup`](upsource:///platform/platform-api/src/com/intellij/openapi/actionSystem/DefaultActionGroup.java)
to create the `CustomDefaultActionGroup` class in the `action_basics` code sample:
```java
package org.jetbrains.tutorials.actions;
public class CustomDefaultActionGroup extends DefaultActionGroup {
public class CustomDefaultActionGroup extends DefaultActionGroup {
@Override
public void update(AnActionEvent event) {
// Enable/disable depending on whether user is editing...
}
}
}
```
#### 2.2.2. Registering the custom action group
As in the case with the simple action group, the action `<group>` should be declared in the *`<actions>`* section of
[plugin.xml](https://github.com/JetBrains/intellij-sdk-docs/blob/master/code_samples/register_actions/resources/META-INF/plugin.xml)
file. Note:
* The presence of the `class` attribute in the `<group>` element, which tells the IntelliJ Platform framework to
use `CustomDefaultActionGroup` rather than the default implementation.
* The `<add-to-group>` element specifies adding the group in the first position of the existing `EditorPopupMenu`.
### Registering the Custom Action Group
As in the case with the static action group, the action `<group>` should be declared in the `<actions>` section of the`plugin.xml` file, for example, the [action_basics](https://github.com/JetBrains/intellij-sdk-docs/blob/master/code_samples/action_basics/src/main/resources/META-INF/plugin.xml) plugin.
The declaration below shows:
* The presence of the `class` attribute in the `<group>` element, which tells the IntelliJ Platform framework to use `CustomDefaultActionGroup` rather than the default implementation.
* Setting the group's `popup` attribute to allow submenus.
* The `<add-to-group>` element specifies adding the group in the first position of the existing `EditorPopupMenu`.
```xml
<actions>
<group id="org.jetbrains.tutorials.actions.ExampleCustomDefaultActionGroup"
<group id="org.jetbrains.tutorials.actions.ExampleCustomDefaultActionGroup"
class="org.jetbrains.tutorials.actions.CustomDefaultActionGroup" popup="true"
text="Example Custom DefaultActionGroup" description="Custom DefaultActionGroup Demo">
<add-to-group group-id="EditorPopupMenu" anchor="first"/>
</group>
</actions>
```
#### 2.2.3. Creating an action
For simplicity the `SimplePopDialogAction` action class will be reused.
#### 2.2.4. Adding actions to the group
As in Section 2.1.4, the `SimplePopDialogAction` action is
added as an `<action>` element in the `<group>` element. Note:
* The `class` attribute in the `<group>` element has the same fully qualified name as used in Section 2.1.4.
* The `id` attribute is unique to distinguish it from the use of the `SimplePopDialogAction` class in (Section 2.1.4) `GroupedActions`.
### Adding Actions to the Custom Group
As in [Static Grouped Actions](#adding-a-new-action-to-the-static-grouped-actions), the `PopupDialogAction` action is added as an `<action>` element in the `<group>` element.
In the declaration below, note:
* The `class` attribute in the `<action>` element has the same FQN to reuse this action implementation.
* The `id` attribute is unique to distinguish it from other uses of the implementation in the Action System.
```xml
<actions>
<group id="org.jetbrains.tutorials.actions.ExampleCustomDefaultActionGroup"
class="org.jetbrains.tutorials.actions.CustomDefaultActionGroup" popup="true"
text="Example Custom DefaultActionGroup" description="Custom DefaultActionGroup Demo">
<group id="org.intellij.sdk.action.CustomDefaultActionGroup" class="org.intellij.sdk.action.CustomDefaultActionGroup" popup="true"
text="Popup Grouped Actions" description="Custom defaultActionGroup demo" icon="ActionBasicsIcons.Sdk_default_icon">
<add-to-group group-id="EditorPopupMenu" anchor="first"/>
<action class="org.jetbrains.tutorials.actions.SimplePopDialogAction" id="org.jetbrains.tutorials.actions.CustomGroupedAction"
text="A Custom Grouped Action" description="Custom Grouped Action Demo"/>
<action class="org.intellij.sdk.action.PopupDialogAction" id="org.intellij.sdk.action.CustomGroupedAction"
text="A Popup Action" description="SDK popup grouped action example" icon="ActionBasicsIcons.Sdk_default_icon"/>
</group>
</actions>
```
#### 2.2.5. Providing specific behaviour for the group
In this case we override the `DefaultActionGroup.update(AnActionEvent event)` method to make the group visible only
if there's an instance of the editor available. Also a custom icon is set up:
### Providing Specific Behavior for the Custom Group
Override the `CustomDefaultActionGroup.update()` method to make the group visible only if there's an instance of the editor available.
Also, a custom icon is added to demonstrate that icons can be changed depending on the action context:
```java
public class CustomDefaultActionGroup extends DefaultActionGroup {
@ -151,72 +133,61 @@ public class CustomDefaultActionGroup extends DefaultActionGroup {
// Enable/disable depending on whether user is editing
Editor editor = event.getData(CommonDataKeys.EDITOR);
event.getPresentation().setEnabled(editor != null);
// Always make visible.
event.getPresentation().setVisible(true);
// Take this opportunity to set an icon for the menu entry.
event.getPresentation().setIcon(AllIcons.General.Error);
event.getPresentation().setIcon(ActionBasicsIcons.Sdk_default_icon);
}
}
```
After compiling and running the code sample above, and opening a file in the editor and right-clicking,
the **Editing** menu will popup containing an new group of actions in the first position. The new group
will also have an icon:
After compiling and running the code sample above and opening a file in the editor and right-clicking, the **Editing** menu will pop up containing a new group of actions in the first position.
The new group will also have an icon:
![Default Action Group](img/editor_popup_menu.png)
![Custom Action Group](img/editor_popup_menu.png){:width="600px"}
### 2.3. Action groups with a variable actions set
## Action Groups with Variable Actions Sets
If a set of actions belonging to a custom group will vary depending on the context, the group must extend [`ActionGroup`](upsource:///platform/editor-ui-api/src/com/intellij/openapi/actionSystem/ActionGroup.java).
The set of actions in the `ActionGroup` is dynamically defined.
If a set of actions belonging to a custom actions group will vary depending on the context, the group must extend
[`ActionGroup`](upsource:///platform/editor-ui-api/src/com/intellij/openapi/actionSystem/ActionGroup.java).
In this case set of actions to be grouped are dynamically defined.
#### 2.3.1. Creating variable action group
To create a group of actions with a variable number of actions we extend
`ActionGroup.java` to create the `DynamicActionGroup` class in the `register_actions` code sample:
### Creating Variable Action Group
To create a group of actions with a variable number of actions, extend `ActionGroup`.
For example, as in the `action_basics` class [`DynamicActionGroup`](https://github.com/JetBrains/intellij-sdk-docs/blob/master/code_samples/action_basics/src/main/java/org/intellij/sdk/action/DynamicActionGroup.java) code:
```java
public class DynamicActionGroup extends ActionGroup {
}
```
#### 2.3.2. Registering a variable action group
To register the dynamic menu group, a `<group>` attribute needs to be placed in the `<actions>` section of
[plugin.xml](https://github.com/JetBrains/intellij-sdk-docs/blob/master/code_samples/register_actions/resources/META-INF/plugin.xml).
Note that when enabled this group will appear as the last entry in the **Tools** menu:
### Registering a Variable Action Group
To register the dynamic menu group, a `<group>` attribute needs to be placed in the `<actions>` section of [plugin.xml](https://github.com/JetBrains/intellij-sdk-docs/blob/master/code_samples/action_basics/src/main/resources/META-INF/plugin.xml).
When enabled, this group will appear at the entry just below the [Static Grouped Actions](#binding-action-groups-to-ui-components) in the **Tools** menu:
```xml
<actions>
<group id="org.jetbrains.tutorials.actions.DynamicActionGroup" class="org.jetbrains.tutorials.actions.DynamicActionGroup" popup="true"
text="Dynamic ActionGroup" description="Dynamic ActionGroup Demo">
<add-to-group group-id="ToolsMenu" anchor="last"/>
<group id="org.intellij.sdk.action.DynamicActionGroup" class="org.intellij.sdk.action.DynamicActionGroup" popup="true"
text="Dynamically Grouped Actions" description="SDK dynamically grouped action example" icon="ActionBasicsIcons.Sdk_default_icon">
<add-to-group group-id="ToolsMenu" anchor="after" relative-to-action="org.intellij.sdk.action.GroupedActions"/>
</group>
</actions>
```
*Note*: If a`<group>` element's `class` attribute names a class derived from `ActionGroup`, then any static `<action>` declarations in the `<group>`
will throw an exception. For a statically defined group of actions use `DefaultActionGroup.java`.
#### 2.3.3. Adding child actions to the group
> **Warning** If a`<group>` element's `class` attribute names a class derived from `ActionGroup`, then any static `<action>` declarations in that group will throw an exception.
For a statically defined group, use `DefaultActionGroup`.
To add actions to the `DynamicActionGroup`, a non-empty array of
`AnAction` instances should be returned from the `DynamicActionGroup.getChildren(AnActionEvent)` method. Here again we reuse the
`SimplePopDialogAction` action class.
### Adding Child Actions to the Dynamic Group
To add actions to the `DynamicActionGroup`, a non-empty array of `AnAction` instances should be returned from the `DynamicActionGroup.getChildren()` method.
Here again, reuse the `PopupDialogAction` implementation.
This use case is why `PopupDialogAction` overrides a constructor:
```java
public class DynamicActionGroup extends ActionGroup {
@NotNull
@Override
public AnAction[] getChildren(AnActionEvent anActionEvent) {
return new AnAction[]{ new SimplePopDialogAction( "Action Added at Runtime",
"Dynamic Action Demo",
null)};
public AnAction[] getChildren(AnActionEvent e) {
return new AnAction[]{ new PopupDialogAction("Action Added at Runtime",
"Dynamic Action Demo",
ActionBasicsIcons.Sdk_default_icon) };
}
}
```
After providing the implementation of `DynamicActionGroup` and making it return a non-empty array of actions, the last position in the **Tools** Menu will contain a new group of actions:
After providing the implementation of `DynamicActionGroup` and making it return a non-empty array of actions, the third position in the **Tools** Menu will contain a new group of actions:
![Dynamic Action Group](img/dynamic_action_group.png)
![Dynamic Action Group](img/dynamic_action_group.png){:width="600px"}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 26 KiB

After

Width:  |  Height:  |  Size: 64 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

After

Width:  |  Height:  |  Size: 126 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 47 KiB

After

Width:  |  Height:  |  Size: 173 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 44 KiB

After

Width:  |  Height:  |  Size: 102 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 156 KiB

After

Width:  |  Height:  |  Size: 165 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 50 KiB

After

Width:  |  Height:  |  Size: 147 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 38 KiB

After

Width:  |  Height:  |  Size: 269 KiB

View File

@ -1,165 +1,188 @@
---
title: 1. Registering an Action
title: Creating Actions
---
## Introduction
Plugins can add actions to existing IDE menus and toolbars, as well as add new menus and toolbars.
The IntelliJ Platform calls the actions of plugins in response to user interactions with the IDE.
However, the actions of a plugin must first be defined and registered with the IntelliJ Platform.
An action is technically a class, derived from the
[`AnAction`](upsource:///platform/editor-ui-api/src/com/intellij/openapi/actionSystem/AnAction.java)
class.
To update the state of the action, the method `AnAction.update(AnActionEvent)` is called by the IntelliJ Platform framework.
The object of type
[`AnActionEvent`](upsource:///platform/editor-ui-api/src/com/intellij/openapi/actionSystem/AnActionEvent.java)
passed to this method carries the information about the current context for the action,
and in particular, the specific presentation which needs to be updated.
Using the SDK code sample `action_basics`, this tutorial illustrates the steps to create an action for a plugin.
* bullet list
{:toc}
### 1.1. Creating actions
To create a new action we need to extend the [`AnAction`](upsource:///platform/editor-ui-api/src/com/intellij/openapi/actionSystem/AnAction.java)
class. As an example we will do that in the `SimplePopDialogAction` class in the `register_actions` code sample.
## Creating a Custom Action
Custom actions extend the abstract class [`AnAction`](upsource:///platform/editor-ui-api/src/com/intellij/openapi/actionSystem/AnAction.java).
Classes that extend it should override `AnAction.update()`, and must override `AnAction.actionPerformed()`.
* The `update()` method implements the code that enables or disables an action.
* The `actionPerformed()` method implements the code that executes when an action is invoked by the user.
As an example, [`PopupDialogAction`](https://github.com/JetBrains/intellij-sdk-docs/blob/master/code_samples/action_basics/src/main/java/org/intellij/sdk/action/PopupDialogAction.java) overrides `AnAction` for the `action_basics` code sample.
```java
public class SimplePopDialogAction extends AnAction {
}
```
**Note** the `SimplePopDialogAction` does not have class fields of any kind. This is because an instance of `AnAction` class
exists for the entire lifetime of the application. If `AnAction` class uses a field to store data which has a shorter
lifetime, and doesn't clear this data promptly, the data will be leaked. For example, any `AnAction` data that exists
only within the context of a `Project` will cause the `Project` to be kept in memory after the user has closed it.
### 1.2. Overriding actionPerformed()
The [`AnAction`](upsource:///platform/editor-ui-api/src/com/intellij/openapi/actionSystem/AnAction.java)
class is abstract, and classes that extend it must override the `AnAction.actionPerformed(AnActionEvent)` method.
This method should contain the code to be executed when the action has been invoked.
In this case `SimplePopDialogAction.actionPerformed(AnActionEvent)` doesn't do anything yet.
```java
public class SimplePopDialogAction extends AnAction {
public class PopupDialogAction extends AnAction {
@Override
public void actionPerformed(@NotNull AnActionEvent anActionEvent) {
// Using the event, create and show a dialog
public void update(AnActionEvent e) {
// Using the event, evaluate the context, and enable or disable the action.
}
@Override
public void actionPerformed(@NotNull AnActionEvent e) {
// Using the event, implement an action. For example, create and show a dialog.
}
}
```
### 1.3. Registering actions
> **Warning** `AnAction` classes do not have class fields of any kind. This restriction prevents memory leaks.
For more information about why, see [Action Implementation](/basics/action_system.md#action-implementation).
To register a newly created action, an `<action>` attribute should be added to the `<actions>` section of the plugin configuration file
[plugin.xml](https://github.com/JetBrains/intellij-sdk-docs/blob/master/code_samples/register_actions/resources/META-INF/plugin.xml).
IntelliJ IDEA has an embedded inspection that spots unregistered actions. Here is an example using the `SimplePopDialogAction` class:
At this stage, `update()` implicitly defaults to always enable this action.
The implementation of `actionPerformed()` does nothing.
These methods will be more fully implemented in [Developing the AnAction Methods](#developing-the-anaction-methods) below.
!["Action never used" inspection](img/action_never_used.png)
Before fleshing out those methods, to complete this minimal implementation `PopupDialogAction` must be registered with the IntelliJ Platform.
To register `SimplePopDialogAction` and set up its attributes press ***Alt + Enter*** while the caret is placed on the action's declaration.
## Registering a Custom Action
Actions can be registered by declaring them in code or by declaring them in the `<actions>` section of a plugin configuration (`plugin.xml`) file.
This section describes using IDE tooling - the New Action Form - to add a declaration to the `plugin.xml` file, and then tuning registration attributes manually.
A more comprehensive explanation of action registration is available in the [Action Registration](/basics/action_system.md#registering-actions) section of this guide.
Then fill out the **New Action** form to set up `SimplePopDialogAction`'s parameters such as: the action's name and description,
a UI component the action is bound to, the visual position of the menu item the action is bound to, and a shortcut for invoking the action.
In this case `SimplePopDialogAction` would be available in the **Tools Menu**, it would be placed on top, and would have no shortcuts.
### Registering an Action with the New Action Form
IntelliJ IDEA has an embedded inspection that spots unregistered actions.
Verify the inspection is enabled at **Settings/Preferences \| Editor \| Inspections \| Plugin DevKit \| Code \| Component/Action not registered**.
Here is an example for this stage of the `PopupDialogAction` class:
![New Action](img/new_action.png)
!["Action never used" inspection](img/action_never_used.png){:width="600px"}
In this example, after completing the **New Action** form and applying the changes, the `<actions>` section of the plugin's `plugins.xml` file
would now contain:
To register `PopupDialogAction` and set up its basic attributes press ***Alt + Shift + Enter***.
Fill out the **New Action** form to set up the parameters for `PopupDialogAction`:
![New Action](img/new_action.png){:width="800px"}
The fields of the form are:
* _Action ID_ - Every action must have a unique ID.
If the action class is used in only one place in the IDE UI, then the class FQN is a good default for the ID.
Using the action class in multiple places requires mangling the ID, such as adding a suffix to the FQN, for each ID.
* _Class Name_ - The FQN implementation class for the action.
If the same action is used in multiple places in the IDE UI, the implementation FQN can be reused with a different _Action ID_.
* _Name_ - The text to appear in the menu.
* _Description_ - Hint text to be displayed.
* _Add to Group_ - The action group - menu or toolbar - to which the action is added.
Clicking in the list of groups and typing will invoke a search, such as "ToolsMenu."
* _Anchor_ - Where the menu action should be placed in the **Tools** menu relative to the other actions in that menu.
In this case, `PopupDialogAction` would be available in the **Tools** menu, it would be placed at the top, and would have no shortcuts.
After finishing the **New Action** form and applying the changes, the `<actions>` section of the plugin's `plugins.xml` file
would contain:
```xml
<actions>
<!-- Add your actions here -->
<action id="org.jetbrains.tutorials.actions.SimplePopDialogAction"
class="org.jetbrains.tutorials.actions.SimplePopDialogAction" text="Simple Action"
description="IntelliJ Action System Demo">
<actions>
<action id="org.intellij.sdk.action.PopupDialogAction" class="org.intellij.sdk.action.PopupDialogAction"
text="Pop Dialog Action" description="SDK action example">
<add-to-group group-id="ToolsMenu" anchor="first"/>
</action>
</actions>
</actions>
```
This declaration is adequate, but as we'll see in the next section there are more elements that can be added to the declaration.
The `<action>` element declares the _Action ID_ (`id`,) _Class Name_ (`class`,) _Name_ (`text`,) and _Description_ from the **New Action** form.
The `<add-to-group>` element declares where the action will appear and mirrors the names of entries from the form.
### 1.4. Setting attributes manually
This declaration is adequate, but adding more attributes is discussed in the next section.
You can configure additional attributes of the action by adding them to the **New Action** form or by editing its registration in the plugin.xml file.
Please refer to the [Action System documentation](../../basics/action_system.md#registering-actions) for the full list
of supported attributes.
The `<action>` declaration for `SimplePopDialogAction` in the register_actions
[plugin.xml](https://github.com/JetBrains/intellij-sdk-docs/blob/master/code_samples/register_actions/resources/META-INF/plugin.xml)
file actually contains elements for `<keyboard-shortcut>` and `<mouse-shortcut>`. The full declaration is:
### Setting Registration Attributes Manually
An action declaration can be added manually to the `plugin.xml` file.
An exhaustive list of declaration elements and attributes is presented in [Registering Actions in plugin.xml](/basics/action_system.md#registering-actions-in-pluginxml).
Attributes are added by selecting them from the **New Action** form, or by editing the registration declaration directly in the plugin.xml file.
The `<action>` declaration for `PopupDialogAction` in the `action_basics` [plugin.xml](https://github.com/JetBrains/intellij-sdk-docs/blob/master/code_samples/action_basics/src/main/resources/META-INF/plugin.xml) file.
It also contains an attribute for an [`Icon`](/reference_guide/work_with_icons_and_images.md), and encloses elements declaring keyboard and mouse shortcuts.
The full declaration is:
```xml
<action id="org.jetbrains.tutorials.actions.SimpleAction" class="org.jetbrains.tutorials.actions.SimplePopDialogAction"
text="Simple Action" description="IntelliJ Action System Demo">
<keyboard-shortcut first-keystroke="control alt A" second-keystroke="C" keymap="$default"/>
<mouse-shortcut keystroke="control button3 doubleClick" keymap="$default"/>
<add-to-group group-id="ToolsMenu" anchor="first"/>
</action>
<action id="org.intellij.sdk.action.PopupDialogAction" class="org.intellij.sdk.action.PopupDialogAction"
text="Pop Dialog Action" description="SDK action example" icon="ActionBasicsIcons.Sdk_default_icon">
<keyboard-shortcut first-keystroke="control alt A" second-keystroke="C" keymap="$default"/>
<mouse-shortcut keystroke="control button3 doubleClick" keymap="$default"/>
<add-to-group group-id="ToolsMenu" anchor="first"/>
</action>
```
The [plugin.xml](https://github.com/JetBrains/intellij-sdk-docs/blob/master/code_samples/register_actions/resources/META-INF/plugin.xml)
file contains copious comments about the declaration.
After performing the steps described above we need to compile and run the plugin to the newly created action available as a Tools Menu item:
!["Register action" quick fix](img/tools_menu_item_action.png)
### 1.5. Performing an action
## Testing the Minimal Custom Action Implementation
After performing the steps described above, compile and run the plugin to see the newly created action available as a Tools Menu item:
In order to make the action do something we need to add code to the `SimplePopDialoigAction.actionPerformed(AnActionEvent)` method.
The following code gets information from the `anActionEvent` input parameter and constructs a simple message dialog.
A generic icon, and the `description` and `text` attributes from the invoking menu action are displayed.
!["Register action" quick fix](img/tools_menu_item_action.png){:width="350px"}
For demonstration purposes the `AnActionEvent.getData()` method tests if a [`Navigatable`](upsource:///platform/core-api/src/com/intellij/pom/Navigatable.java)
object is available, meaning e.g. an element has been selected in the editor. If so, information about
the selected element is opportunistically added to the dialog.
Selecting the action from the menu or using the keyboard shortcuts won't do anything because the implementations are empty.
However, it confirms the new entry appears at **Tools \| Pop Dialog Action**
## Developing the AnAction Methods
At this point, the new action `PopupDialogAction` is registered with the IntelliJ Platform and functions in the sense that `update()` and `actionPerformed()` are called in response to user interaction with the IDE Tools menu.
However, neither method implements any code to perform useful work.
This section describes adding useful code to these methods.
The `update()` method defaults to always enable the action, which is satisfactory for intermediate testing.
So `actionPerformed()` will be developed first.
### Extending the actionPerformed Method
Adding code to the `PopupDialogAction.actionPerformed()` method makes the action do something useful.
The code below gets information from the `anActionEvent` input parameter and constructs a message dialog.
A generic icon, and the `dlgMsg` and `dlgTitle` attributes from the invoking menu action are displayed.
However, code in this method could manipulate a project, invoke an inspection, change the contents of a file, etc.
For demonstration purposes the `AnActionEvent.getData()` method tests if a [`Navigatable`](upsource:///platform/core-api/src/com/intellij/pom/Navigatable.java) object is available.
If so, information about the selected element is added to the dialog.
See [Determining the Action Context](/basics/action_system.md#determining-the-action-context) for more information about accessing information from the `AnActionEvent` input parameter.
```java
@Override
public void actionPerformed(@NotNull AnActionEvent anActionEvent) {
@Override
public void actionPerformed(@NotNull AnActionEvent event) {
// Using the event, create and show a dialog
Project currentProject = anActionEvent.getProject();
StringBuffer dlgMsg = new StringBuffer(anActionEvent.getPresentation().getText() + " Selected!");
String dlgTitle = anActionEvent.getPresentation().getDescription();
Project currentProject = event.getProject();
StringBuffer dlgMsg = new StringBuffer(event.getPresentation().getText() + " Selected!");
String dlgTitle = event.getPresentation().getDescription();
// If an element is selected in the editor, add info about it.
Navigatable nav = anActionEvent.getData(CommonDataKeys.NAVIGATABLE);
Navigatable nav = event.getData(CommonDataKeys.NAVIGATABLE);
if (nav != null) {
dlgMsg.append(String.format("\nSelected Element: %s", nav.toString()));
}
Messages.showMessageDialog(currentProject, dlgMsg.toString(), dlgTitle, Messages.getInformationIcon());
}
Messages.showMessageDialog(currentProject, dlgMsg.toString(), dlgTitle, Messages.getInformationIcon());
}
```
### 1.6. Setting up an action's visibility and availability
### Extending the update Method
Adding code to `PopupDialogAction.update()` gives finer control of the action's visibility and availability.
The action's state and(or) presentation can be dynamically changed depending on the context.
To control the action's visibility and availability we need to override the `AnAction.update(AnActionEvent)` method.
The default implementation of this method does nothing, which means the action is always disabled.
Override this method to provide the ability to dynamically change action's state and(or) presentation depending on the context.
> **Warning** This method needs to _execute very quickly_. For more information about this constraint, see the warning in [Overriding the AnAction.update Method](/basics/action_system.md#overriding-the-anactionupdate-method).
In this example the `SimplePopDialogAction.actionPerformed(AnActionEvent)` method relies on a `Project`
object being available. So the `SimplePopDialogAction.update(AnActionEvent)` method disables
the action for contexts where a`Project` object isn't defined:
In this example, the `update()` method relies on a `Project` object being available.
This requirement means the user must have at least one project open in the IDE for the `PopupDialogAction` to be available.
So the `update()` method disables the action for contexts where a `Project` object isn't defined.
The availability (enabled and visible) is set on the `Presentation` object.
Setting both the enabled state and visibility produces consistent behavior despite possible host menu settings, as discussed in [Grouping Actions](/basics/action_system.md#grouping-actions).
```java
@Override
public void update(AnActionEvent anActionEvent) {
@Override
public void update(AnActionEvent e) {
// Set the availability based on whether a project is open
Project project = anActionEvent.getProject();
anActionEvent.getPresentation().setEnabledAndVisible(project != null);
}
Project project = e.getProject();
e.getPresentation().setEnabledAndVisible(project != null);
}
```
Parameter `anActionEvent` carries information on the invocation place and data available. Note the `update()` method does
not check to see if a [`Navigatable`](upsource:///platform/core-api/src/com/intellij/pom/Navigatable.java) object is available
before enabling `SimplePopDialogAction`. This is done for the purposes of demonstration code.
**Note** 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 the file system is not.
If you cannot understand the state of the action fast you should do it in the
[`AnActionEvent`](upsource:///platform/editor-ui-api/src/com/intellij/openapi/actionSystem/AnActionEvent.java)
method and notify the user that the action cannot be executed if it's the case.
The `update()` method does not check to see if a `Navigatable` object is available before enabling `PopupDialogAction`.
This check is unnecessary because using the `Navigatable` object is opportunistic in `actionPerformed()`.
See [Determining the Action Context](/basics/action_system.md#determining-the-action-context) for more information about accessing information from the `AnActionEvent` input parameter.
### Other Method Overrides
A constructor is overridden in `PopupDialogAction`, but this is an artifact of reusing this class for a dynamically created menu action.
Otherwise, overriding constructors for `AnAction` is not required.
## Testing the Custom Action
After compiling and running the plugin project and invoking the action, the dialog will pop up:
![Action performed](img/action_performed.png)
![Action performed](img/action_performed.png){:width="800px"}