3.5.5.1. Декларативное создание действий

В XML-дескрипторе экрана для любого компонента, реализующего интерфейс Component.ActionsHolder, в том числе для всего экрана или фрейма, может быть задан набор действий. Делается это в элементе actions, который содержит вложенные элементы action.

Элемент action может иметь следующие атрибуты:

  • id − идентификатор, должен быть уникален в рамках данного компонента ActionsHolder.

  • type - задает тип действия. Если данный атрибут установлен, фреймворк находит класс, имеющий аннотацию @ActionType с таким же значением, и использует его для инстанциирования действия. Если тип не задан, фреймворк создает экземпляр класса BaseAction. Раздел Стандартные действия описывает типы действий, предоставляемые фреймворком, раздел Собственные типы действий объясняет, как создавать собственные типы действий.

  • caption - название действия.

  • description - описание действия.

  • enable - признак доступности действия (true / false).

  • icon - значок действия.

  • primary - атрибут, определяющий подсветку кнопок, обеспечивающих выполнение этого действия (true / false). Если выбрано true, для подсветки будет использован особый стиль.

    В теме hover подсветка доступна по умолчанию; для её активации в теме halo установите значение true для переменной стиля $cuba-highlight-primary-action.

    Следующие действия являются primary по умолчанию, если не установлено иное: create у табличных компонентов и lookupSelectAction в экранах выбора.

    actions primary
  • shortcut - комбинация клавиш для вызова.

    Комбинации можно жёстко задавать в XML-дескрипторе. Возможные модификаторы - ALT, CTRL, SHIFT - отделяются символом "-". Например:

    <action id="create" shortcut="ALT-N"/>

    Для большей гибкости можно использовать готовые псевдонимы комбинаций из списка ниже, к примеру:

    <action id="edit" shortcut="${TABLE_EDIT_SHORTCUT}"/>
    • TABLE_EDIT_SHORTCUT

    • COMMIT_SHORTCUT

    • CLOSE_SHORTCUT

    • FILTER_APPLY_SHORTCUT

    • FILTER_SELECT_SHORTCUT

    • NEXT_TAB_SHORTCUT

    • PREVIOUS_TAB_SHORTCUT

    • PICKER_LOOKUP_SHORTCUT

    • PICKER_OPEN_SHORTCUT

    • PICKER_CLEAR_SHORTCUT

    Кроме того, есть возможность задавать комбинацию с помощью полного имени интерфейса Config и имени метода, возвращающего нужную комбинацию:

    <action id="remove" shortcut="${com.haulmont.cuba.client.ClientConfig#getTableRemoveShortcut}"/>
  • visible - признак видимости действия (true / false).

Рассмотрим примеры декларативного объявления действий.

  • Объявление действий на уровне экрана:

    <window>
        <actions>
            <action id="sayHello" caption="msg://sayHello" shortcut="ALT-T"/>
        </actions>
    
        <layout>
            <button action="sayHello"/>
        </layout>
    </window>
    // controller
    @Inject
    private Notifications notifications;
    
    @Subscribe("sayHello")
    protected void onSayHelloActionPerformed(Action.ActionPerformedEvent event) {
        notifications.create()
                    .withCaption("Hello")
                    .withType(Notifications.NotificationType.HUMANIZED)
                    .show();
    }

    Здесь объявляется действие с идентификатором sayHello и названием из пакета сообщений. С этим действием связывается кнопка, заголовок которой будет установлен в название действия. Контроллер экрана подписан на событие действия ActionPerformedEvent, так что метод onSayHelloActionPerformed() будет вызван при нажатии на кнопку, а также при нажатии комбинации клавиш ALT-T.

Обратите внимание, что действия, объявленные на уровне экрана, не обновляют своё состояние. Это значит, если действие имеет установленный enabledRule обработчик, то он не будет применен пока refreshState() не будет вызван вручную.

  • Объявление действий для PopupButton:

    <popupButton id="sayBtn" caption="Say">
        <actions>
            <action id="hello" caption="Say Hello"/>
            <action id="goodbye" caption="Say Goodbye"/>
        </actions>
    </popupButton>
    // controller
    @Inject
    private Notifications notifications;
    
    private void showNotification(String message) {
        notifications.create()
                .withCaption(message)
                .withType(NotificationType.HUMANIZED)
                .show();
    }
    
    @Subscribe("sayBtn.hello")
    private void onSayBtnHelloActionPerformed(Action.ActionPerformedEvent event) {
        notifications.create()
                .withCaption("Hello")
                .show();
    }
    
    @Subscribe("sayBtn.goodbye")
    private void onSayBtnGoodbyeActionPerformed(Action.ActionPerformedEvent event) {
        notifications.create()
                .withCaption("Hello")
                .show();
    }
  • Объявление действий для Table:

    <groupTable id="customersTable" width="100%" dataContainer="customersDc">
        <actions>
            <action id="create" type="create"/>
            <action id="edit" type="edit"/>
            <action id="remove" type="remove"/>
            <action id="copy" caption="Copy" icon="COPY" trackSelection="true"/>
        </actions>
        <columns>
            <!-- -->
        </columns>
        <rowsCount/>
        <buttonsPanel alwaysVisible="true">
            <!-- -->
            <button action="customersTable.copy"/>
        </buttonsPanel>
    </groupTable>
    // controller
    
    @Subscribe("customersTable.copy")
    protected void onCustomersTableCopyActionPerformed(Action.ActionPerformedEvent event) {
        // ...
    }

    Здесь помимо стандартных действий таблицы create, edit и remove объявлено действие copy. Для этого действия указан также атрибут trackSelection="true", в результате чего действие и связанная с ним кнопка становятся недоступными, если в таблице не выбрана ни одна строка. Это удобно, если действие предназначено для выполнения над текущей выбранной строкой таблицы.

  • Объявление действий для PickerField:

    <pickerField id="userPickerField" dataContainer="customerDc" property="user">
        <actions>
            <action id="lookup" type="picker_lookup"/>
            <action id="show" description="Show user" icon="USER"/>
        </actions>
    </pickerField>
    // controller
    
    @Subscribe("userPickerField.show")
    protected void onUserPickerFieldShowActionPerformed(Action.ActionPerformedEvent event) {
        //
    }

    В данном примере для компонента PickerField объявлено стандартное действие picker_lookup и дополнительное действие show. Так как в кнопках PickerField, отображающих действия, используются значки, а не надписи, атрибут caption явно установлен в пустую строку, иначе названием действия и заголовком кнопки стал бы идентификатор действия. Атрибут description позволяет отображать всплывающую подсказку при наведении мыши на кнопку действия.

Ссылки на любые декларативно объявленные действия можно получить в контроллере экрана либо непосредственно путем инжекции, либо из компонентов, реализующих интерфейс Component.ActionsHolder. Это может понадобиться для программной установки свойств действия. Например:

@Named("customersTable.copy")
private Action customersTableCopy;

@Inject
private PickerField<User> userPickerField;

@Subscribe
protected void onBeforeShow(BeforeShowEvent event) {
    customersTableCopy.setEnabled(false);
    userPickerField.getActionNN("show").setEnabled(false);
}