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();
}
});
}