Декларативные действия

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

Атрибуты Action

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

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

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

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

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

  • enable - признак доступности действия. Возможные значения: true, false.

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

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

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

    Действие стандартного списка create и действие lookupSelectAction на экране поиска являются primary по умолчанию.

    primary actions
    Figure 1. Кнопка Create с primary действием create
  • shortcut - комбинация клавиш для вызова.

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

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

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

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

    Поддерживаются следующие предопределенные псевдонимы комбинаций:

    • TABLE_EDIT_SHORTCUT

    • TABLE_INSERT_SHORTCUT

    • TABLE_ADD_SHORTCUT

    • TABLE_REMOVE_SHORTCUT

    • COMMIT_SHORTCUT

    • CLOSE_SHORTCUT

    • NEXT_TAB_SHORTCUT

    • PREVIOUS_TAB_SHORTCUT

    • PICKER_LOOKUP_SHORTCUT

    • PICKER_OPEN_SHORTCUT

    • PICKER_CLEAR_SHORTCUT

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

      <action id="remove"
              shortcut="${io.jmix.ui.UiComponentProperties#getTableRemoveShortcut}"/>
  • visible - признак видимости действия. Возможные значения: true, false.

Примеры

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

Действия экранов

В нижеприведенном примере объявляется действие с идентификатором sayHello и названием из пакета сообщений. С этим действием связывается кнопка, заголовок которой будет установлен в название действия.

<window xmlns="http://jmix.io/schema/ui/window"
        caption="msg://ui.ex1.screen.actions/actionScreen.caption">
    <actions>
        <action id="sayHello" caption="msg://sayHello" shortcut="ALT-T"/>
    </actions>
    <layout>
        <vbox spacing="true">
            <button action="sayHello"/>
        </vbox>
    </layout>
</window>

Контроллер экрана подписан на событие действия ActionPerformedEvent, так что метод onSayHello() будет вызван при нажатии на кнопку, а также при нажатии комбинации клавиш ALT-T.

@Autowired
private Notifications notifications;

@Subscribe("sayHello") (1)
public void onSayHello(Action.ActionPerformedEvent event) {
    notifications.create()
            .withCaption("Hello")
            .withType(Notifications.NotificationType.HUMANIZED)
            .show();
}
1 Аннотация @Subscribe содержит id действия.

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

Заглушку реализации обработчика Action.ActionPerformedEvent можно сгенерировать с помощью Studio.

Действия PopupButton

В нижеприведенном примере popupButton с действиями объявляется в XML-дескрипторе:

<popupButton id="sayBtn" caption="Say">
    <actions>
        <action id="hello" caption="Say Hello"/>
        <action id="goodbye" caption="Say Goodbye"/>
    </actions>
</popupButton>

Подписка на ActionPerformedEvent действия в контроллере экрана:

@Autowired
private Notifications notifications;

private void showNotification(String message) {
    notifications.create()
            .withCaption(message)
            .withType(Notifications.NotificationType.HUMANIZED)
            .show();
}

@Subscribe("sayBtn.hello") (1)
public void onSayBtnHello(Action.ActionPerformedEvent event) {
    showNotification(event.getSource().getCaption());
}

@Subscribe("sayBtn.goodbye")
public void onSayBtnGoodbye(Action.ActionPerformedEvent event) {
    showNotification(event.getSource().getCaption());
}
1 Аннотация @Subscribe содержит id PopupButton и id действия, разделенные точкой.

Действия Table

В нижеприведенном примере groupTable с действиями объявляется в XML-дескрипторе:

<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>
        <column id="firstName"/>
        <column id="lastName"/>
    </columns>
    <buttonsPanel alwaysVisible="true">
        <button action="customersTable.create"/>
        <button action="customersTable.edit"/>
        <button action="customersTable.remove"/>
        <button action="customersTable.copy"/>
    </buttonsPanel>
</groupTable>

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

Подписка на ActionPerformedEvent действия в контроллере экрана:

@Subscribe("customersTable.copy")
public void onCustomersTableCopy(Action.ActionPerformedEvent event) {
    // ...
}

Действия EntityPicker

В данном примере для компонента EntityPicker объявлено стандартное действие entity_lookup и дополнительное действие points. Атрибут description позволяет отображать всплывающую подсказку при наведении мыши на кнопку действия.

<entityPicker id="customerEntityPicker"
              property="customer"
              dataContainer="orderDc">
    <actions>
        <action id="lookup" type="entity_lookup"/>
        <action id="points"
                icon="QUESTION"
                description="msg://knowPoints"/>
    </actions>
</entityPicker>

Затем реализуйте собственную логику в контроллере экрана, подписавшись на Action.ActionPerformedEvent:

@Autowired
private EntityPicker<Customer> customerEntityPicker;
@Autowired
private Notifications notifications;

@Subscribe("customerEntityPicker.points")  (1)
public void onCustomerEntityPickerPoints(Action.ActionPerformedEvent event) {
    Customer customer = customerEntityPicker.getValue();
    if (customer != null) {
        notifications.create()
                .withCaption(customer.getFirstName() +
                        " has " + customer.getRewardPoints() +
                        " reward points")
                .show();
    } else {
        notifications.create()
                .withCaption("Choose a customer")
                .show();
    }
}
1 Аннотация @Subscribe содержит id EntityPicker и id действия, разделенные точкой.

Получение ссылок на действия

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

@Named("sayBtn.hello")
private Action sayBtnHello;
@Autowired
private PopupButton sayBtn;

@Subscribe
public void onBeforeShow(BeforeShowEvent event) {
    sayBtnHello.setEnabled(false);
    sayBtn.getActionNN("goodbye").setEnabled(false);
}