Untitled diff

Created Diff never expires
27 removals
Lines
Total
Removed
Words
Total
Removed
To continue using this feature, upgrade to
Diffchecker logo
Diffchecker Pro
299 lines
26 additions
Lines
Total
Added
Words
Total
Added
To continue using this feature, upgrade to
Diffchecker logo
Diffchecker Pro
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;
}
}
}
}