Untitled diff
27 removals
Words removed | 46 |
Total words | 926 |
Words removed (%) | 4.97 |
299 lines
26 additions
Words added | 63 |
Total words | 943 |
Words added (%) | 6.68 |
298 lines
/*
/*
* Copyright (c) 2008-2016 Haulmont.
* Copyright (c) 2008-2016 Haulmont.
*
*
* Licensed under the Apache License, Version 2.0 (the "License");
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* You may obtain a copy of the License at
*
*
* http://www.apache.org/licenses/LICENSE-2.0
* http://www.apache.org/licenses/LICENSE-2.0
*
*
* Unless required by applicable law or agreed to in writing, software
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* See the License for the specific language governing permissions and
* limitations under the License.
* limitations under the License.
*
*
*/
*/
package com.haulmont.cuba.gui.components.actions;
package com.haulmont.cuba.gui.components.actions;
import com.haulmont.bali.events.Subscription;
import com.haulmont.bali.util.Preconditions;
import com.haulmont.bali.util.Preconditions;
import com.haulmont.cuba.gui.components.*;
import com.haulmont.cuba.gui.components.AbstractAction;
import com.haulmont.cuba.gui.components.Action;
import com.haulmont.cuba.gui.components.Component;
import com.haulmont.cuba.gui.components.KeyCombination;
import javax.annotation.Nullable;
import javax.annotation.Nullable;
import java.util.ArrayList;
import java.util.ArrayList;
import java.util.List;
import java.util.List;
import java.util.function.Consumer;
import java.util.function.Consumer;
/**
/**
* Action that can change its enabled and visible properties depending on the user permissions and current context.
* Action that can change its enabled and visible properties depending on the user permissions and current context.
* <p> The BaseAction is visible if the following conditions are met:
* <p> The BaseAction is visible if the following conditions are met:
* <ul>
* <ul>
* <li>setVisible(false) method was not called;</li>
* <li>setVisible(false) method was not called;</li>
* <li>there is no "hide" UI permission for this action.</li>
* <li>there is no "hide" UI permission for this action.</li>
* </ul>
* </ul>
* <p>The action is enabled if the following conditions are met:
* <p>The action is enabled if the following conditions are met:
* <ul>
* <ul>
* <li>setEnabled(false) method was not called;</li>
* <li>setEnabled(false) method was not called;</li>
* <li>there are no "hide" and "read-only" UI permissions for this action;</li>
* <li>there are no "hide" and "read-only" UI permissions for this action;</li>
* <li>isPermitted() method returns true;</li>
* <li>isPermitted() method returns true;</li>
* <li>isApplicable() method returns true;</li>
* <li>isApplicable() method returns true;</li>
* <li>all {@link EnabledRule}s (if any) return true.</li>
* <li>all {@link EnabledRule}s (if any) return true.</li>
* </ul>
* </ul>
* <p> Descendants may override {@link #isPermitted()} and {@link #isApplicable()} methods to define conditions in which
* <p> Descendants may override {@link #isPermitted()} and {@link #isApplicable()} methods to define conditions in which
* action will be enabled.
* action will be enabled.
*
*
* Also, you can use fluent API to create instances of BaseAction and assign handlers to them:
* Also, you can use fluent API to create instances of BaseAction and assign handlers to them:
* <pre>{@code
* <pre>{@code
* Action action = new BaseAction("printAll")
* Action action = new BaseAction("printAll")
* .withCaption("Print all")
* .withCaption("Print all")
* .withIcon("icons/print.png")
* .withIcon("icons/print.png")
* .withHandler(event -> {
* .withHandler(event -> {
* // action logic here
* // action logic here
* });
* });
* docsTable.addAction(action);
* docsTable.addAction(action);
* }</pre>
* }</pre>
*/
*/
public class BaseAction extends AbstractAction implements Action.HasTarget, Action.UiPermissionAware {
public class BaseAction extends AbstractAction implements Action.SecuredAction {
private boolean enabledByUiPermissions = true;
private boolean enabledByUiPermissions = true;
private boolean visibleByUiPermissions = true;
private boolean visibleByUiPermissions = true;
private boolean enabledExplicitly = true;
private boolean enabledExplicitly = true;
private boolean visibleExplicitly = true;
private boolean visibleExplicitly = true;
private List<EnabledRule> enabledRules; // lazy initialized list
private List<EnabledRule> enabledRules; // lazy initialized list
protected ListComponent target;
protected Consumer<ActionPerformedEvent> actionPerformHandler;
public BaseAction(String id) {
public BaseAction(String id) {
this(id, null);
this(id, null);
}
}
protected BaseAction(String id, @Nullable String shortcut) {
protected BaseAction(String id, @Nullable String shortcut) {
super(id, shortcut);
// do not init messages in parent class
super();
this.id = id;
if (shortcut != null) {
this.shortcut = KeyCombination.create(shortcut);
}
}
}
/**
/**
* Callback method which is invoked by the action to determine its enabled state.
* Callback method which is invoked by the action to determine its enabled state.
*
*
* @return true if the action is enabled for the current user
* @return true if the action is enabled for the current user
*/
*/
protected boolean isPermitted() {
protected boolean isPermitted() {
return true;
return true;
}
}
/**
/**
* Callback method which is invoked by the action to determine its enabled state.
* Callback method which is invoked by the action to determine its enabled state.
*
*
* @return true if the action is enabled for the current context, e.g. there is a selected row in a table
* @return true if the action is enabled for the current context, e.g. there is a selected row in a table
*/
*/
protected boolean isApplicable() {
protected boolean isApplicable() {
return true;
return true;
}
}
protected boolean isEnabledByRule() {
protected boolean isEnabledByRule() {
if (enabledRules == null) {
if (enabledRules == null) {
return true;
return true;
}
}
for (EnabledRule rule : enabledRules) {
for (EnabledRule rule : enabledRules) {
if (!rule.isActionEnabled()) {
if (!rule.isActionEnabled()) {
return false;
return false;
}
}
}
}
return true;
return true;
}
}
@Override
@Override
public void setVisible(boolean visible) {
public void setVisible(boolean visible) {
if (this.visibleExplicitly != visible) {
if (this.visibleExplicitly != visible) {
this.visibleExplicitly = visible;
this.visibleExplicitly = visible;
refreshState();
refreshState();
}
}
}
}
@Override
@Override
public void setEnabled(boolean enabled) {
public void setEnabled(boolean enabled) {
if (this.enabledExplicitly != enabled) {
if (this.enabledExplicitly != enabled) {
this.enabledExplicitly = enabled;
this.enabledExplicitly = enabled;
refreshState();
refreshState();
}
}
}
}
protected void setVisibleInternal(boolean visible) {
protected void setVisibleInternal(boolean visible) {
super.setVisible(visible);
super.setVisible(visible);
}
}
protected void setEnabledInternal(boolean enabled) {
protected void setEnabledInternal(boolean enabled) {
super.setEnabled(enabled);
super.setEnabled(enabled);
}
}
@Override
@Override
public void refreshState() {
public void refreshState() {
super.refreshState();
super.refreshState();
setVisibleInternal(visibleExplicitly && visibleByUiPermissions);
setVisibleInternal(visibleExplicitly && visibleByUiPermissions);
setEnabledInternal(enabledExplicitly && enabledByUiPermissions && visibleByUiPermissions
setEnabledInternal(enabledExplicitly && enabledByUiPermissions && visibleByUiPermissions
&& isPermitted() && isApplicable() && isEnabledByRule());
&& isPermitted() && isApplicable() && isEnabledByRule());
}
}
@Override
@Override
public ListComponent getTarget() {
return target;
}
@Override
public void setTarget(ListComponent target) {
if (this.target != target) {
this.target = target;
refreshState();
}
}
@Override
public boolean isEnabledByUiPermissions() {
public boolean isEnabledByUiPermissions() {
return enabledByUiPermissions;
return enabledByUiPermissions;
}
}
@Override
@Override
public void setEnabledByUiPermissions(boolean enabledByUiPermissions) {
public void setEnabledByUiPermissions(boolean enabledByUiPermissions) {
if (this.enabledByUiPermissions != enabledByUiPermissions) {
if (this.enabledByUiPermissions != enabledByUiPermissions) {
this.enabledByUiPermissions = enabledByUiPermissions;
this.enabledByUiPermissions = enabledByUiPermissions;
refreshState();
refreshState();
}
}
}
}
@Override
@Override
public boolean isVisibleByUiPermissions() {
public boolean isVisibleByUiPermissions() {
return visibleByUiPermissions;
return visibleByUiPermissions;
}
}
@Override
@Override
public void setVisibleByUiPermissions(boolean visibleByUiPermissions) {
public void setVisibleByUiPermissions(boolean visibleByUiPermissions) {
if (this.visibleByUiPermissions != visibleByUiPermissions) {
if (this.visibleByUiPermissions != visibleByUiPermissions) {
this.visibleByUiPermissions = visibleByUiPermissions;
this.visibleByUiPermissions = visibleByUiPermissions;
refreshState();
refreshState();
}
}
}
}
/**
/**
* Add new enabled rule for the action.
* Add new enabled rule for the action.
*
*
* @param enabledRule boolean rule for the action enabled state
* @param enabledRule boolean rule for the action enabled state
*/
*/
public void addEnabledRule(EnabledRule enabledRule) {
public void addEnabledRule(EnabledRule enabledRule) {
Preconditions.checkNotNullArgument(enabledRule);
Preconditions.checkNotNullArgument(enabledRule);
if (enabledRules == null) {
if (enabledRules == null) {
enabledRules = new ArrayList<>();
enabledRules = new ArrayList<>(2);
}
}
if (!enabledRules.contains(enabledRule)) {
if (!enabledRules.contains(enabledRule)) {
enabledRules.add(enabledRule);
enabledRules.add(enabledRule);
}
}
}
}
/**
/**
* Remove enabled rule.
* Remove enabled rule.
*
*
* @param enabledRule boolean rule for the action enabled state
* @param enabledRule boolean rule for the action enabled state
*/
*/
public void removeEnabledRule(EnabledRule enabledRule) {
public void removeEnabledRule(EnabledRule enabledRule) {
if (enabledRules != null) {
if (enabledRules != null) {
enabledRules.remove(enabledRule);
enabledRules.remove(enabledRule);
}
}
}
}
/**
/**
* Callback interface which is invoked by the action to determine its enabled state.
* Callback interface which is invoked by the action to determine its enabled state.
*
*
* @see #addEnabledRule(EnabledRule)
* @see #addEnabledRule(EnabledRule)
*/
*/
public interface EnabledRule {
public interface EnabledRule {
boolean isActionEnabled();
boolean isActionEnabled();
}
}
@Override
@Override
public void actionPerform(Component component) {
public void actionPerform(Component component) {
if (actionPerformHandler != null) {
if (eventHub != null) {
actionPerformHandler.accept(new ActionPerformedEvent(this, component));
ActionPerformedEvent event = new ActionPerformedEvent(this, component);
eventHub.publish(ActionPerformedEvent.class, event);
}
}
}
}
@SuppressWarnings("unused") // called on declarative events registration
public Subscription addActionPerformedListener(Consumer<ActionPerformedEvent> listener) {
return getEventHub().subscribe(ActionPerformedEvent.class, listener);
}
/**
/**
* Set caption usin fluent API method.
* Set caption using fluent API method.
*
*
* @param caption caption
* @param caption caption
* @return current instance of action
* @return current instance of action
*/
*/
public BaseAction withCaption(String caption) {
public BaseAction withCaption(String caption) {
this.caption = caption;
this.caption = caption;
return this;
return this;
}
}
/**
/**
* Set description using fluent API method.
* Set description using fluent API method.
*
*
* @param description description
* @param description description
* @return current instance of action
* @return current instance of action
*/
*/
public BaseAction withDescription(String description) {
public BaseAction withDescription(String description) {
this.description = description;
this.description = description;
return this;
return this;
}
}
/**
/**
* Set icon using fluent API method.
* Set icon using fluent API method.
*
*
* @param icon icon
* @param icon icon
* @return current instance of action
* @return current instance of action
*/
*/
public BaseAction withIcon(String icon) {
public BaseAction withIcon(String icon) {
this.icon = icon;
this.icon = icon;
return this;
return this;
}
}
/**
/**
* Set shortcut using fluent API method.
* Set shortcut using fluent API method.
*
*
* @param shortcut shortcut
* @param shortcut shortcut
* @return current instance of action
* @return current instance of action
*/
*/
public BaseAction withShortcut(String shortcut) {
public BaseAction withShortcut(String shortcut) {
if (shortcut != null) {
if (shortcut != null) {
this.shortcut = KeyCombination.create(shortcut);
this.shortcut = KeyCombination.create(shortcut);
}
}
return this;
return this;
}
}
/**
/**
* Set actionPerformed handler using fluent API method. Can be used instead of subclassing BaseAction class.
* Set action performed event handler using fluent API method. Can be used instead of subclassing BaseAction class.
*
*
* @param handler action performed handler
* @param handler action performed handler
* @return current instance of action
* @return current instance of action
*/
*/
public BaseAction withHandler(Consumer<ActionPerformedEvent> handler) {
public BaseAction withHandler(Consumer<ActionPerformedEvent> handler) {
this.actionPerformHandler = handler;
getEventHub().subscribe(ActionPerformedEvent.class, handler);
return this;
return this;
}
}
/**
/**
* Set whether this action is primary using fluent API method. Can be used instead of subclassing BaseAction class.
* Set whether this action is primary using fluent API method. Can be used instead of subclassing BaseAction class.
*
*
* @param primary primary
* @param primary primary
* @return current instance of action
* @return current instance of action
*/
*/
public BaseAction withPrimary(boolean primary) {
public BaseAction withPrimary(boolean primary) {
this.primary = primary;
this.primary = primary;
return this;
return this;
}
}
}
}