5.5.4.3. BaseAction

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

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

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

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

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

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

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

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

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

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

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

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

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

  • Действие кнопки:

    @Inject
    private Button helloBtn;
    
    @Override
    public void init(Map<String, Object> params) {
        helloBtn.setAction(new BaseAction("hello") {
            @Override
            public boolean isPrimary() {
                return true;
            }
    
            @Override
            public void actionPerform(Component component) {
                showNotification("Hello!", NotificationType.TRAY);
            }
        });
        // OR
        helloBtn.setAction(new BaseAction("hello")
                .withPrimary(true)
                .withHandler(e -> showNotification("Hello", NotificationType.TRAY)));
    }

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

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

    @Inject
    private ComponentsFactory componentsFactory;
    
    @Inject
    private BoxLayout box;
    
    @Override
    public void init(Map<String, Object>params) {
        PickerField pickerField = componentsFactory.createComponent(PickerField.NAME);
    
        pickerField.addAction(new BaseAction("hello") {
            @Override
            public String getCaption() {
                return null;
            }
    
            @Override
            public String getDescription() {
                return getMessage("helloDescription");
            }
    
            @Override
            public String getIcon() {
                return"icons/hello.png";
            }
    
            @Override
            public void actionPerform(Component component) {
                showNotification("Hello!", NotificationType.TRAY);
            }
        });
        // OR
        pickerField.addAction(new BaseAction("hello")
                .withCaption(null)
                .withDescription(getMessage("helloDescription"))
                .withIcon("icons/ok.png")
                .withHandler(e -> showNotification("Hello", NotificationType.TRAY)));
    
        box.add(pickerField);
    }

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

  • Действие таблицы:

    @Inject
    private Table table;
    
    @Inject
    private Security security;
    
    @Override
    public void init(Map<String, Object> params) {
        table.addAction(new HelloAction());
    }
    
    private class HelloAction extends BaseAction {
    
        public HelloAction() {
            super("hello");
        }
    
        @Override
        public void actionPerform(Component component) {
            showNotification("Hello " + table.getSingleSelected(), NotificationType.TRAY);
        }
    
        @Override
        protected boolean isPermitted() {
            return security.isSpecificPermitted("myapp.allow-greeting");
        }
    
        @Override
        public boolean isApplicable() {
            return target != null && target.getSelected().size() == 1;
        }
    }

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

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

    @Inject
    private Table table;
    
    @Override
    public void init(Map<String, Object> params) {
        table.addAction(new ItemTrackingAction("hello") {
            @Override
            public void actionPerform(Component component) {
                showNotification("Hello " + table.getSelected().iterator().next(), NotificationType.TRAY);
            }
        });
    }