Merge changes from topic "boolcond"
* changes: UiActions: defer GlobalPermission checks on views CherryPick: use BooleanCondition for visible PermissionBackend: support bulk evaluation of UiAction PermissionBackend: support testCond for UiAction Delay UiAction visible and enabled with BooleanCondition
This commit is contained in:
		| @@ -0,0 +1,217 @@ | ||||
| // Copyright (C) 2017 The Android Open Source Project | ||||
| // | ||||
| // Licensed under the Apache License, Version 2.0 (the "License"); | ||||
| // you may not use this file except in compliance with the License. | ||||
| // You may obtain a copy of the License at | ||||
| // | ||||
| // http://www.apache.org/licenses/LICENSE-2.0 | ||||
| // | ||||
| // Unless required by applicable law or agreed to in writing, software | ||||
| // distributed under the License is distributed on an "AS IS" BASIS, | ||||
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
| // See the License for the specific language governing permissions and | ||||
| // limitations under the License. | ||||
|  | ||||
| package com.google.gerrit.extensions.conditions; | ||||
|  | ||||
| import com.google.common.collect.Iterables; | ||||
| import java.util.Collections; | ||||
|  | ||||
| /** Delayed evaluation of a boolean condition. */ | ||||
| public abstract class BooleanCondition { | ||||
|   public static final BooleanCondition TRUE = new Value(true); | ||||
|   public static final BooleanCondition FALSE = new Value(false); | ||||
|  | ||||
|   public static BooleanCondition valueOf(boolean a) { | ||||
|     return a ? TRUE : FALSE; | ||||
|   } | ||||
|  | ||||
|   public static BooleanCondition and(BooleanCondition a, BooleanCondition b) { | ||||
|     return a == FALSE || b == FALSE ? FALSE : new And(a, b); | ||||
|   } | ||||
|  | ||||
|   public static BooleanCondition and(boolean a, BooleanCondition b) { | ||||
|     return and(valueOf(a), b); | ||||
|   } | ||||
|  | ||||
|   public static BooleanCondition or(BooleanCondition a, BooleanCondition b) { | ||||
|     return a == TRUE || b == TRUE ? TRUE : new Or(a, b); | ||||
|   } | ||||
|  | ||||
|   public static BooleanCondition or(boolean a, BooleanCondition b) { | ||||
|     return or(valueOf(a), b); | ||||
|   } | ||||
|  | ||||
|   public static BooleanCondition not(BooleanCondition bc) { | ||||
|     return bc == TRUE ? FALSE : bc == FALSE ? TRUE : new Not(bc); | ||||
|   } | ||||
|  | ||||
|   BooleanCondition() {} | ||||
|  | ||||
|   /** @return evaluate the condition and return its value. */ | ||||
|   public abstract boolean value(); | ||||
|  | ||||
|   /** | ||||
|    * Recursively collect all children of type {@code type}. | ||||
|    * | ||||
|    * @param type implementation type of the conditions to collect and return. | ||||
|    * @return non-null, unmodifiable iteration of children of type {@code type}. | ||||
|    */ | ||||
|   public abstract <T> Iterable<T> children(Class<T> type); | ||||
|  | ||||
|   private static final class And extends BooleanCondition { | ||||
|     private final BooleanCondition a; | ||||
|     private final BooleanCondition b; | ||||
|  | ||||
|     And(BooleanCondition a, BooleanCondition b) { | ||||
|       this.a = a; | ||||
|       this.b = b; | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public boolean value() { | ||||
|       return a.value() && b.value(); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public <T> Iterable<T> children(Class<T> type) { | ||||
|       return Iterables.concat(a.children(type), b.children(type)); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public int hashCode() { | ||||
|       return a.hashCode() * 31 + b.hashCode(); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public boolean equals(Object other) { | ||||
|       if (other instanceof And) { | ||||
|         And o = (And) other; | ||||
|         return a.equals(o.a) && b.equals(o.b); | ||||
|       } | ||||
|       return false; | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public String toString() { | ||||
|       return "(" + maybeTrim(a, getClass()) + " && " + maybeTrim(a, getClass()) + ")"; | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   private static final class Or extends BooleanCondition { | ||||
|     private final BooleanCondition a; | ||||
|     private final BooleanCondition b; | ||||
|  | ||||
|     Or(BooleanCondition a, BooleanCondition b) { | ||||
|       this.a = a; | ||||
|       this.b = b; | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public boolean value() { | ||||
|       return a.value() || b.value(); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public <T> Iterable<T> children(Class<T> type) { | ||||
|       return Iterables.concat(a.children(type), b.children(type)); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public int hashCode() { | ||||
|       return a.hashCode() * 31 + b.hashCode(); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public boolean equals(Object other) { | ||||
|       if (other instanceof Or) { | ||||
|         Or o = (Or) other; | ||||
|         return a.equals(o.a) && b.equals(o.b); | ||||
|       } | ||||
|       return false; | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public String toString() { | ||||
|       return "(" + maybeTrim(a, getClass()) + " || " + maybeTrim(a, getClass()) + ")"; | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   private static final class Not extends BooleanCondition { | ||||
|     private final BooleanCondition cond; | ||||
|  | ||||
|     Not(BooleanCondition bc) { | ||||
|       cond = bc; | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public boolean value() { | ||||
|       return !cond.value(); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public <T> Iterable<T> children(Class<T> type) { | ||||
|       return cond.children(type); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public int hashCode() { | ||||
|       return cond.hashCode() * 31; | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public boolean equals(Object other) { | ||||
|       return other instanceof Not ? cond.equals(((Not) other).cond) : false; | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public String toString() { | ||||
|       return "!" + cond; | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   private static final class Value extends BooleanCondition { | ||||
|     private final boolean value; | ||||
|  | ||||
|     Value(boolean v) { | ||||
|       value = v; | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public boolean value() { | ||||
|       return value; | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public <T> Iterable<T> children(Class<T> type) { | ||||
|       return Collections.emptyList(); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public int hashCode() { | ||||
|       return value ? 1 : 0; | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public boolean equals(Object other) { | ||||
|       return other instanceof Value ? value == ((Value) other).value : false; | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public String toString() { | ||||
|       return Boolean.toString(value); | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   /** Remove leading '(' and trailing ')' if the type is the same as the parent. */ | ||||
|   static String maybeTrim(BooleanCondition cond, Class<? extends BooleanCondition> type) { | ||||
|     String s = cond.toString(); | ||||
|     if (cond.getClass() == type | ||||
|         && s.length() > 2 | ||||
|         && s.charAt(0) == '(' | ||||
|         && s.charAt(s.length() - 1) == ')') { | ||||
|       s = s.substring(1, s.length() - 1); | ||||
|     } | ||||
|     return s; | ||||
|   } | ||||
| } | ||||
| @@ -0,0 +1,33 @@ | ||||
| // Copyright (C) 2017 The Android Open Source Project | ||||
| // | ||||
| // Licensed under the Apache License, Version 2.0 (the "License"); | ||||
| // you may not use this file except in compliance with the License. | ||||
| // You may obtain a copy of the License at | ||||
| // | ||||
| // http://www.apache.org/licenses/LICENSE-2.0 | ||||
| // | ||||
| // Unless required by applicable law or agreed to in writing, software | ||||
| // distributed under the License is distributed on an "AS IS" BASIS, | ||||
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
| // See the License for the specific language governing permissions and | ||||
| // limitations under the License. | ||||
|  | ||||
| package com.google.gerrit.extensions.conditions; | ||||
|  | ||||
| import java.util.Collections; | ||||
|  | ||||
| /** <b>DO NOT USE</b> */ | ||||
| public final class PrivateInternals_BooleanCondition { | ||||
|   private PrivateInternals_BooleanCondition() {} | ||||
|  | ||||
|   public abstract static class SubclassOnlyInCoreServer extends BooleanCondition { | ||||
|     @SuppressWarnings("unchecked") | ||||
|     @Override | ||||
|     public <T> Iterable<T> children(Class<T> type) { | ||||
|       if (type.isAssignableFrom(getClass())) { | ||||
|         return Collections.singleton((T) this); | ||||
|       } | ||||
|       return Collections.emptyList(); | ||||
|     } | ||||
|   } | ||||
| } | ||||
| @@ -14,6 +14,7 @@ | ||||
|  | ||||
| package com.google.gerrit.extensions.webui; | ||||
|  | ||||
| import com.google.gerrit.extensions.conditions.BooleanCondition; | ||||
| import com.google.gerrit.extensions.restapi.RestResource; | ||||
| import com.google.gerrit.extensions.restapi.RestView; | ||||
|  | ||||
| @@ -35,8 +36,8 @@ public interface UiAction<R extends RestResource> extends RestView<R> { | ||||
|     private String id; | ||||
|     private String label; | ||||
|     private String title; | ||||
|     private boolean visible = true; | ||||
|     private boolean enabled = true; | ||||
|     private BooleanCondition visible = BooleanCondition.TRUE; | ||||
|     private BooleanCondition enabled = BooleanCondition.TRUE; | ||||
|  | ||||
|     public String getMethod() { | ||||
|       return method; | ||||
| @@ -77,6 +78,10 @@ public interface UiAction<R extends RestResource> extends RestView<R> { | ||||
|     } | ||||
|  | ||||
|     public boolean isVisible() { | ||||
|       return getVisibleCondition().value(); | ||||
|     } | ||||
|  | ||||
|     public BooleanCondition getVisibleCondition() { | ||||
|       return visible; | ||||
|     } | ||||
|  | ||||
| @@ -85,16 +90,33 @@ public interface UiAction<R extends RestResource> extends RestView<R> { | ||||
|      * action description may not be sent to the client. | ||||
|      */ | ||||
|     public Description setVisible(boolean visible) { | ||||
|       return setVisible(BooleanCondition.valueOf(visible)); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Set if the action's button is visible on screen for the current client. If not visible the | ||||
|      * action description may not be sent to the client. | ||||
|      */ | ||||
|     public Description setVisible(BooleanCondition visible) { | ||||
|       this.visible = visible; | ||||
|       return this; | ||||
|     } | ||||
|  | ||||
|     public boolean isEnabled() { | ||||
|       return enabled && isVisible(); | ||||
|       return getEnabledCondition().value(); | ||||
|     } | ||||
|  | ||||
|     public BooleanCondition getEnabledCondition() { | ||||
|       return BooleanCondition.and(enabled, visible); | ||||
|     } | ||||
|  | ||||
|     /** Set if the button should be invokable (true), or greyed out (false). */ | ||||
|     public Description setEnabled(boolean enabled) { | ||||
|       return setEnabled(BooleanCondition.valueOf(enabled)); | ||||
|     } | ||||
|  | ||||
|     /** Set if the button should be invokable (true), or greyed out (false). */ | ||||
|     public Description setEnabled(BooleanCondition enabled) { | ||||
|       this.enabled = enabled; | ||||
|       return this; | ||||
|     } | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 Shawn Pearce
					Shawn Pearce