BaseAction

BaseAction – это базовый класс реализации действий. От него рекомендуется наследовать собственные нестандартные действия, если возможностей декларативного создания действий не хватает.

При создании конкретного класса действия необходимо определить метод actionPerform() и передать в конструктор BaseAction идентификатор действия. Можно также переопределить любые методы получения свойств действия: getCaption(), getDescription(), getIcon(), getShortcut(), isEnabled(), isVisible(), isPrimary(). Стандартные реализации этих методов возвращают значения, установленные соответствующими setter-методами. Исключение составляет метод getCaption(): если название действия явно не установлено методом setCaption(), то он обращается в пакет локализованных сообщений с именем, соответствующим пакету класса действия, и возвращает сообщение с ключом, равным идентификатору действия. Если сообщения с таким ключом нет, то возвращается сам ключ, то есть идентификатор действия.

В качестве альтернативы переопределению методов можно использовать fluent API для установки свойств и lambda-выражений для предоставления кода обработки действия: см. методы withXYZ().

BaseAction может изменять свои свойства enabled и visible в соответствии с разрешениями пользователя и текущим контекстом.

BaseAction видим (visible), если:

  • метод setVisible(false) не вызывался;

  • для действия не установлено UI разрешение hide.

Действие разрешено (enabled), если:

  • метод setEnabled(false) не вызывался;

  • для действия не установлено UI разрешений hide или read-only;

  • метод isPermitted() возвращает true;

  • метод isApplicable() возвращает true;

  • все EnabledRules (если таковые есть) возвращают true.

Примеры использования:

Действие Button

@Autowired
private Notifications notifications;
@Autowired
private Button sayHelloBtn;
@Autowired
private Button sayGoodbyeBtn;

@Subscribe
public void onInit(InitEvent event) {
    sayHelloBtn.setAction(new BaseAction("hello") {
        @Override
        public boolean isPrimary() {
            return true;
        }

        @Override
        public void actionPerform(Component component) {
            notifications.create()
                    .withCaption("Hello!")
                    .withType(Notifications.NotificationType.TRAY)
                    .show();
        }
    });

    sayGoodbyeBtn.setAction(new BaseAction("goodbye")
            .withPrimary(true)
            .withHandler(e ->
                    notifications.create()
                            .withCaption("Goodbye!")
                            .withType(Notifications.NotificationType.TRAY)
                            .show()));
}

В данном случае кнопка sayHelloBtn получит в качестве заголовка строку, находящуюся в пакете сообщений с ключом hello. Для того, чтобы получить название кнопки каким-либо иным способом, можно переопределить метод getCaption() действия.

Действие ValuePicker

Действие программно создаваемого ValuePicker:

@Autowired
protected Notifications notifications;
@Autowired
private UiComponents uiComponents;
@Autowired
private MessageBundle messageBundle;
@Autowired
private VBoxLayout vBox;
@Subscribe
protected void onInit(InitEvent event) {
    ValuePicker valueField = uiComponents.create(ValuePicker.NAME);

    valueField.addAction(new BaseAction("hello") {
        @Override
        public String getCaption() {
            return null;
        }

        @Override
        public String getDescription() {
            return messageBundle.getMessage("helloDescription");
        }

        @Override
        public String getIcon() {
            return JmixIcon.HANDSHAKE_O.source();
        }

        @Override
        public void actionPerform(Component component) {
            notifications.create()
                    .withCaption("Hello!")
                    .withType(Notifications.NotificationType.TRAY)
                    .show();
        }
    });
    valueField.addAction(new BaseAction("goodbye")
            .withCaption(null)
            .withDescription(messageBundle.getMessage("goodbyeDescription"))
            .withIcon(JmixIcon.HAND_PAPER_O.source())
            .withHandler(e ->
                    notifications.create()
                            .withCaption("Goodbye!")
                            .withType(Notifications.NotificationType.TRAY)
                            .show()));
    vBox.add(valueField);
}

Здесь анонимный класс-наследник BaseAction используется для задания действия кнопки поля выбора. Заголовок кнопки не отображается, вместо него используется значок и описание, всплывающее при наведении курсора мыши.

Действие Table

@Autowired
private Table<Customer> customersTable;
@Autowired
private Notifications notifications;

@Subscribe
public void onInit(InitEvent event) {
    customersTable.addAction(new AboutSingleAction());
}

private class AboutSingleAction extends BaseAction {

    public AboutSingleAction() {
        super("aboutSingle");
    }

    @Nullable
    @Override
    public String getCaption() {
        return "About Single";
    }

    @Override
    public void actionPerform(Component component) {
        notifications.create()
                .withCaption("Hello " + customersTable.getSingleSelected())
                .withType(Notifications.NotificationType.TRAY)
                .show();
    }

    @Override
    public boolean isApplicable() {
        return customersTable != null && customersTable.getSelected().size() == 1;
    }
}

Здесь объявлен класс AboutSingleAction, экземпляр которого добавляется в список действий таблицы. Действие разрешено когда выбрана одна строка таблицы. Последнее условие реализуется с помощью свойства target действия, которое автоматически устанавливается, когда действие добавляется в ListComponent (Table или Tree).

Использование ItemTrackingAction

Если необходимо действие, которое доступно, когда выделены одна или более строк таблицы, удобно воспользоваться наследником BaseAction – классом ItemTrackingAction, который добавляет стандартную реализацию метода isApplicable():

@Autowired
private Table<Customer> customersTable;
@Autowired
private Notifications notifications;

@Subscribe
public void onInit(InitEvent event) {
    customersTable.addAction(new ItemTrackingAction("about") {
        @Nullable
        @Override
        public String getCaption() {
            return "About";
        }

        @Override
        public void actionPerform(Component component) {
            notifications.create()
                    .withCaption("Hello " + customersTable.getSelected().iterator().next())
                    .withType(Notifications.NotificationType.TRAY)
                    .show();
        }
    });
}