/** * Licensed to Apereo under one or more contributor license agreements. See the NOTICE file * distributed with this work for additional information regarding copyright ownership. Apereo * licenses this file to you 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 the * following location: * * <p>http://www.apache.org/licenses/LICENSE-2.0 * * <p>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 org.apereo.portal.layout.dlm; import org.apereo.portal.layout.node.IUserLayoutNodeDescription; /** * A class that embodies the logic for determining if a node can be moved to the left or right of * another node based on getMovedAllowed() and getPrecedence(). * * @since 2.5 */ public class MovementRules { /** * Returns true if hopper is allowed to hop in the rightward, higher- sibling direction over the * node being hopped; nbh. This is determined from the following tables. See notes from * canHopLeft for details. In the tables below a zero equates to false and a one equates to * true. Since moveAllowed is an attribute on a node a value of false equates to a string value * of 'false'. The non-existence of a moveAllowed attribute defaults to making that node * moveable. In otherwords the attribute is only included (asserted) when movement is being * restricted. * * <pre> * Scenario | NBH | hopper | * | moveAllowed | moveAllowed | * ----------+-------------+-------------+ * A | 0 | 0 | * B | 0 | 1 | * C | 1 | 0 | * D | 1 | 1 | * ----------+-------------+-------------+ * </pre> * * In the table below Ph is the precedence of the hopper node. Pnbh is the precedence of the * node being hopped. The values in the table indicate what values should be returned from this * method. The scenarios A through D are as defined above for the moveAllowed values. * * <pre> * Scenario --> | A | B | C | D | * -------------+---+---+---+---+ * Pnbh = Ph | 0 | 0 | 0 | 1 | * Pnbh > Ph | 0 | 1 | 1 | 1 | * Pnbh < Ph | 0 | 1 | 0 | 1 | * -------------+---+---+---+---+ * </pre> */ public static boolean canHopRight( IUserLayoutNodeDescription hopper, IUserLayoutNodeDescription nbh) { boolean nbhMoveAld = nbh.isMoveAllowed(); boolean hopperMoveAld = hopper.isMoveAllowed(); if (nbhMoveAld == hopperMoveAld) return nbhMoveAld; // from the above test we know that if we get here, moveAld's differ double Pnbh = nbh.getPrecedence(); double Ph = hopper.getPrecedence(); if (Pnbh > Ph) return true; if (Pnbh < Ph && hopperMoveAld == true) return true; return false; } /** * Returns true if hopper is allowed to hop in the leftward, lower- sibling direction over the * node being hopped; nbh. This is determined from the following tables. Since lower sibling * order is tied to left or top most viewing locations on the screen these positions are * considered to be superior in real-estate value. Hence to protect viewability as much as * possible within a precedence a fragment owner can movement restrict a node, lets say a tab * for example, to prevent users from placing nodes with equal or lesser precedence to its left * and ultimately force that tab off of the right side of the screen. * * <p>Sibling nodes are mapped left to right on the screen for lowest to highest child node * index in the parent node for tabs and columns and from top to bottom on the screen for lowest * to highest child node index in the parent node for channels. In the tables below a zero * equates to false and a one equates to true. * * <pre> * Scenario | NBH | hopper | * | moveAllowed | moveAllowed | * ----------+-------------+-------------+ * A | 0 | 0 | * B | 0 | 1 | * C | 1 | 0 | * D | 1 | 1 | * ----------+-------------+-------------+ * </pre> * * In the table below Ph is the precedence of the hopper node. Pnbh is the precedence of the * node being hopped. The values in the table indicate what values should be returned from this * method. The scenarios are A through D are as defined above for the moveAllowed values. * * <p>These return values were determined by setting up each scenario on paper with tabs as the * nodes and determining what expected and reasonable behavior should be. A higher precedence * value takes precedence over movement restrictions imposed by a node from a fragment with * lesser precedence. * * <pre> * Scenario --> | A | B | C | D | * -------------+---+---+---+---+ * Pnbh = Ph | 0 | 0 | 0 | 1 | * Pnbh > Ph | 0 | 0 | 1 | 1 | * Pnbh < Ph | 0 | 1 | 1 | 1 | * -------------+---+---+---+---+ * </pre> * * Patterns in these tables were used to simplify checks needed to return the appropriate * values. For example when the moveAllowed values are the same the returned value matches the * moveAllowed value. */ public static boolean canHopLeft( IUserLayoutNodeDescription hopper, IUserLayoutNodeDescription nbh) { boolean nbhMoveAld = nbh.isMoveAllowed(); boolean hopperMoveAld = hopper.isMoveAllowed(); if (nbhMoveAld == hopperMoveAld) return nbhMoveAld; // from the above test we know that if we get here, moveAld's differ double Pnbh = nbh.getPrecedence(); double Ph = hopper.getPrecedence(); if (Pnbh < Ph) return true; if (Pnbh > Ph && nbhMoveAld == true) return true; return false; } }