Simon Hunt | f679c4e | 2016-04-01 17:02:24 -0700 | [diff] [blame] | 1 | /* |
Brian O'Connor | 5ab426f | 2016-04-09 01:19:45 -0700 | [diff] [blame] | 2 | * Copyright 2016-present Open Networking Laboratory |
Simon Hunt | f679c4e | 2016-04-01 17:02:24 -0700 | [diff] [blame] | 3 | * |
| 4 | * Licensed under the Apache License, Version 2.0 (the "License"); |
| 5 | * you may not use this file except in compliance with the License. |
| 6 | * You may obtain a copy of the License at |
| 7 | * |
| 8 | * http://www.apache.org/licenses/LICENSE-2.0 |
| 9 | * |
| 10 | * Unless required by applicable law or agreed to in writing, software |
| 11 | * distributed under the License is distributed on an "AS IS" BASIS, |
| 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 13 | * See the License for the specific language governing permissions and |
| 14 | * limitations under the License. |
| 15 | */ |
| 16 | |
| 17 | package org.onosproject.ui.model.topo; |
| 18 | |
Simon Hunt | d0fa284 | 2016-10-24 18:04:05 -0700 | [diff] [blame] | 19 | import com.google.common.base.MoreObjects; |
Simon Hunt | f679c4e | 2016-04-01 17:02:24 -0700 | [diff] [blame] | 20 | import org.onosproject.net.region.Region; |
Simon Hunt | d5b9673 | 2016-07-08 13:22:27 -0700 | [diff] [blame] | 21 | import org.onosproject.net.region.RegionId; |
Simon Hunt | f679c4e | 2016-04-01 17:02:24 -0700 | [diff] [blame] | 22 | |
Simon Hunt | d0fa284 | 2016-10-24 18:04:05 -0700 | [diff] [blame] | 23 | import static com.google.common.base.Preconditions.checkArgument; |
| 24 | import static com.google.common.base.Preconditions.checkNotNull; |
| 25 | |
Simon Hunt | f679c4e | 2016-04-01 17:02:24 -0700 | [diff] [blame] | 26 | /** |
| 27 | * Represents a specific "subset" of the UI model of the network topology |
| 28 | * that a user might wish to view. Backed by a {@link Region}. |
Simon Hunt | d0fa284 | 2016-10-24 18:04:05 -0700 | [diff] [blame] | 29 | * <p> |
Simon Hunt | ed81ed6 | 2017-03-21 17:53:38 -0700 | [diff] [blame] | 30 | * These instances include information about which geo-map or grid-layout |
Simon Hunt | d0fa284 | 2016-10-24 18:04:05 -0700 | [diff] [blame] | 31 | * should be displayed, along with zoom and offset parameters. |
Simon Hunt | f679c4e | 2016-04-01 17:02:24 -0700 | [diff] [blame] | 32 | */ |
| 33 | public class UiTopoLayout { |
| 34 | |
Simon Hunt | d0fa284 | 2016-10-24 18:04:05 -0700 | [diff] [blame] | 35 | // package private for unit test access |
| 36 | static final double SCALE_MIN = 0.01; |
| 37 | static final double SCALE_MAX = 100.0; |
| 38 | static final double SCALE_DEFAULT = 1.0; |
| 39 | static final double OFFSET_DEFAULT = 0.0; |
| 40 | |
| 41 | static final String E_ROOT_PARENT = "Cannot change parent ID of root layout"; |
| 42 | static final String E_ROOT_REGION = "Cannot set region on root layout"; |
| 43 | static final String E_SPRITES_SET = "Cannot set geomap if sprites is set"; |
| 44 | static final String E_GEOMAP_SET = "Cannot set sprites if geomap is set"; |
| 45 | static final String E_SCALE_OOB = |
| 46 | "Scale out of bounds; expected [" + SCALE_MIN + ".." + SCALE_MAX + "]"; |
| 47 | |
Thomas Vachuska | 4d66d0a | 2016-04-15 15:48:13 -0700 | [diff] [blame] | 48 | private final UiTopoLayoutId id; |
Simon Hunt | d0fa284 | 2016-10-24 18:04:05 -0700 | [diff] [blame] | 49 | |
| 50 | private Region region; |
| 51 | private UiTopoLayoutId parent; |
| 52 | private String geomap; |
| 53 | private String sprites; |
| 54 | private double scale = SCALE_DEFAULT; |
| 55 | private double offsetX = OFFSET_DEFAULT; |
| 56 | private double offsetY = OFFSET_DEFAULT; |
Simon Hunt | f679c4e | 2016-04-01 17:02:24 -0700 | [diff] [blame] | 57 | |
Thomas Vachuska | 4d66d0a | 2016-04-15 15:48:13 -0700 | [diff] [blame] | 58 | /** |
| 59 | * Created a new UI topology layout. |
| 60 | * |
Simon Hunt | d0fa284 | 2016-10-24 18:04:05 -0700 | [diff] [blame] | 61 | * @param id layout identifier |
Thomas Vachuska | 4d66d0a | 2016-04-15 15:48:13 -0700 | [diff] [blame] | 62 | */ |
Simon Hunt | d0fa284 | 2016-10-24 18:04:05 -0700 | [diff] [blame] | 63 | public UiTopoLayout(UiTopoLayoutId id) { |
| 64 | checkNotNull(id, "layout ID cannot be null"); |
Thomas Vachuska | 4d66d0a | 2016-04-15 15:48:13 -0700 | [diff] [blame] | 65 | this.id = id; |
Simon Hunt | d0fa284 | 2016-10-24 18:04:05 -0700 | [diff] [blame] | 66 | |
Simon Hunt | 9818919 | 2016-07-29 19:02:27 -0700 | [diff] [blame] | 67 | // NOTE: root layout is its own parent... |
Simon Hunt | d0fa284 | 2016-10-24 18:04:05 -0700 | [diff] [blame] | 68 | if (isRoot()) { |
| 69 | parent = id; |
| 70 | } |
Thomas Vachuska | 4d66d0a | 2016-04-15 15:48:13 -0700 | [diff] [blame] | 71 | } |
| 72 | |
Simon Hunt | d0fa284 | 2016-10-24 18:04:05 -0700 | [diff] [blame] | 73 | /** |
| 74 | * Returns true if this layout instance is at the top of the |
| 75 | * hierarchy tree. |
| 76 | * |
| 77 | * @return true if this is the root layout |
| 78 | */ |
| 79 | public boolean isRoot() { |
| 80 | return UiTopoLayoutId.DEFAULT_ID.equals(id); |
Simon Hunt | d5b9673 | 2016-07-08 13:22:27 -0700 | [diff] [blame] | 81 | } |
| 82 | |
Thomas Vachuska | 4d66d0a | 2016-04-15 15:48:13 -0700 | [diff] [blame] | 83 | /** |
| 84 | * Returns the UI layout identifier. |
| 85 | * |
| 86 | * @return identifier of the layout |
| 87 | */ |
| 88 | public UiTopoLayoutId id() { |
| 89 | return id; |
| 90 | } |
| 91 | |
Simon Hunt | d0fa284 | 2016-10-24 18:04:05 -0700 | [diff] [blame] | 92 | @Override |
| 93 | public String toString() { |
| 94 | return MoreObjects.toStringHelper(this) |
| 95 | .add("id", id) |
| 96 | .add("region", region) |
| 97 | .add("parent", parent) |
| 98 | .add("geomap", geomap) |
| 99 | .add("sprites", sprites) |
| 100 | .add("scale", scale) |
| 101 | .add("offsetX", offsetX) |
| 102 | .add("offsetY", offsetY) |
| 103 | .toString(); |
| 104 | } |
| 105 | |
| 106 | /** |
| 107 | * Sets the backing region for this layout. Note that an exception will |
| 108 | * be thrown if this is the root layout. |
| 109 | * |
| 110 | * @param region the backing region |
| 111 | * @return self, for chaining |
| 112 | * @throws IllegalArgumentException if this is the root layout |
| 113 | */ |
| 114 | public UiTopoLayout region(Region region) { |
| 115 | if (isRoot()) { |
| 116 | throw new IllegalArgumentException(E_ROOT_REGION); |
| 117 | } |
| 118 | |
| 119 | this.region = region; |
| 120 | return this; |
| 121 | } |
| 122 | |
Thomas Vachuska | 4d66d0a | 2016-04-15 15:48:13 -0700 | [diff] [blame] | 123 | /** |
Simon Hunt | d5b9673 | 2016-07-08 13:22:27 -0700 | [diff] [blame] | 124 | * Returns the backing region with which this layout is associated. Note |
| 125 | * that this may be null (for the root layout). |
Thomas Vachuska | 4d66d0a | 2016-04-15 15:48:13 -0700 | [diff] [blame] | 126 | * |
| 127 | * @return backing region |
| 128 | */ |
| 129 | public Region region() { |
| 130 | return region; |
| 131 | } |
| 132 | |
Thomas Vachuska | 92b016b | 2016-05-20 11:37:57 -0700 | [diff] [blame] | 133 | /** |
Simon Hunt | 4f4ffc3 | 2016-08-03 18:30:47 -0700 | [diff] [blame] | 134 | * Returns the identifier of the backing region. If this is the default |
| 135 | * layout, the null-region ID will be returned, otherwise the ID of the |
| 136 | * backing region for this layout will be returned; null in the case that |
| 137 | * there is no backing region. |
Simon Hunt | d5b9673 | 2016-07-08 13:22:27 -0700 | [diff] [blame] | 138 | * |
| 139 | * @return backing region identifier |
| 140 | */ |
| 141 | public RegionId regionId() { |
Simon Hunt | d0fa284 | 2016-10-24 18:04:05 -0700 | [diff] [blame] | 142 | return isRoot() ? UiRegion.NULL_ID : |
| 143 | (region == null ? null : region.id()); |
| 144 | } |
| 145 | |
| 146 | /** |
| 147 | * Sets the identity of this layout's parent. May be null to unset. |
| 148 | * Note that an exception will be thrown if this is the root layout, |
| 149 | * since the parent of the root is always itself, and cannot be changed. |
| 150 | * |
| 151 | * @param parentId parent layout identifier |
| 152 | * @return self, for chaining |
| 153 | * @throws IllegalArgumentException if this instance is the root layout |
| 154 | */ |
| 155 | public UiTopoLayout parent(UiTopoLayoutId parentId) { |
| 156 | if (isRoot()) { |
| 157 | throw new IllegalArgumentException(E_ROOT_PARENT); |
| 158 | } |
| 159 | // TODO: consider checking ancestry chain to prevent loops |
| 160 | |
| 161 | parent = parentId; |
| 162 | return this; |
Simon Hunt | d5b9673 | 2016-07-08 13:22:27 -0700 | [diff] [blame] | 163 | } |
| 164 | |
| 165 | /** |
Thomas Vachuska | 92b016b | 2016-05-20 11:37:57 -0700 | [diff] [blame] | 166 | * Returns the parent layout identifier. |
| 167 | * |
| 168 | * @return parent layout identifier |
| 169 | */ |
| 170 | public UiTopoLayoutId parent() { |
| 171 | return parent; |
| 172 | } |
| 173 | |
Simon Hunt | 9818919 | 2016-07-29 19:02:27 -0700 | [diff] [blame] | 174 | /** |
Simon Hunt | d0fa284 | 2016-10-24 18:04:05 -0700 | [diff] [blame] | 175 | * Sets the name of the geomap for this layout. This is the symbolic |
| 176 | * name for a "topojson" file containing a geographic map projection, |
| 177 | * to be displayed in the topology view, for this layout. |
| 178 | * <p> |
| 179 | * Since the geomap and sprites fields are mutually exclusive, this |
| 180 | * method will throw an exception if the sprites field is already set. |
Simon Hunt | 9818919 | 2016-07-29 19:02:27 -0700 | [diff] [blame] | 181 | * |
Simon Hunt | d0fa284 | 2016-10-24 18:04:05 -0700 | [diff] [blame] | 182 | * @param geomap the geomap name |
| 183 | * @return self, for chaining |
| 184 | * @throws IllegalArgumentException if the sprites field is not null |
Simon Hunt | 9818919 | 2016-07-29 19:02:27 -0700 | [diff] [blame] | 185 | */ |
Simon Hunt | d0fa284 | 2016-10-24 18:04:05 -0700 | [diff] [blame] | 186 | public UiTopoLayout geomap(String geomap) { |
| 187 | if (sprites != null) { |
| 188 | throw new IllegalArgumentException(E_SPRITES_SET); |
| 189 | } |
| 190 | this.geomap = geomap; |
| 191 | return this; |
Simon Hunt | 9818919 | 2016-07-29 19:02:27 -0700 | [diff] [blame] | 192 | } |
Simon Hunt | d0fa284 | 2016-10-24 18:04:05 -0700 | [diff] [blame] | 193 | |
| 194 | /** |
| 195 | * Returns the symbolic name for the geomap for this layout. |
| 196 | * |
| 197 | * @return name of geomap |
| 198 | */ |
| 199 | public String geomap() { |
| 200 | return geomap; |
| 201 | } |
| 202 | |
| 203 | /** |
| 204 | * Sets the name of the sprites definition for this layout. This is the |
Simon Hunt | bc30e68 | 2017-02-15 18:39:23 -0800 | [diff] [blame] | 205 | * symbolic name for a definition of sprites, |
Simon Hunt | d0fa284 | 2016-10-24 18:04:05 -0700 | [diff] [blame] | 206 | * which render as a symbolic background (e.g. a campus, or floor plan), |
| 207 | * to be displayed in the topology view, for this layout. |
| 208 | * <p> |
| 209 | * Since the geomap and sprites fields are mutually exclusive, this |
| 210 | * method will throw an exception if the geomap field is already set. |
| 211 | * |
| 212 | * @param sprites the sprites definition name |
| 213 | * @return self, for chaining |
| 214 | * @throws IllegalArgumentException if the geomap field is not null |
| 215 | */ |
| 216 | public UiTopoLayout sprites(String sprites) { |
| 217 | if (geomap != null) { |
| 218 | throw new IllegalArgumentException(E_GEOMAP_SET); |
| 219 | } |
| 220 | this.sprites = sprites; |
| 221 | return this; |
| 222 | } |
| 223 | |
| 224 | /** |
| 225 | * Returns the symbolic name for the sprites definition for this layout. |
| 226 | * |
| 227 | * @return name of sprites definition |
| 228 | */ |
| 229 | public String sprites() { |
| 230 | return sprites; |
| 231 | } |
| 232 | |
| 233 | private boolean scaleWithinBounds(double scale) { |
| 234 | return scale >= SCALE_MIN && scale <= SCALE_MAX; |
| 235 | } |
| 236 | |
| 237 | /** |
| 238 | * Sets the scale for the geomap / sprite image. Note that the |
| 239 | * acceptable bounds are from {@value #SCALE_MIN} to {@value #SCALE_MAX}. |
| 240 | * |
| 241 | * @param scale the scale |
| 242 | * @return self for chaining |
| 243 | * @throws IllegalArgumentException if the value is out of bounds |
| 244 | */ |
| 245 | public UiTopoLayout scale(double scale) { |
| 246 | checkArgument(scaleWithinBounds(scale), E_SCALE_OOB); |
| 247 | this.scale = scale; |
| 248 | return this; |
| 249 | } |
| 250 | |
| 251 | /** |
| 252 | * Returns the scale for the geomap / sprite image. |
| 253 | * |
| 254 | * @return the scale |
| 255 | */ |
| 256 | public double scale() { |
| 257 | return scale; |
| 258 | } |
| 259 | |
| 260 | /** |
| 261 | * Sets the x-offset value. |
| 262 | * |
| 263 | * @param offsetX x-offset |
| 264 | * @return self, for chaining |
| 265 | */ |
| 266 | public UiTopoLayout offsetX(double offsetX) { |
| 267 | this.offsetX = offsetX; |
| 268 | return this; |
| 269 | } |
| 270 | |
| 271 | /** |
| 272 | * Returns the x-offset value. |
| 273 | * |
| 274 | * @return the x-offset |
| 275 | */ |
| 276 | public double offsetX() { |
| 277 | return offsetX; |
| 278 | } |
| 279 | |
| 280 | /** |
| 281 | * Sets the y-offset value. |
| 282 | * |
| 283 | * @param offsetY y-offset |
| 284 | * @return self, for chaining |
| 285 | */ |
| 286 | public UiTopoLayout offsetY(double offsetY) { |
| 287 | this.offsetY = offsetY; |
| 288 | return this; |
| 289 | } |
| 290 | |
| 291 | /** |
| 292 | * Returns the y-offset value. |
| 293 | * |
| 294 | * @return the y-offset |
| 295 | */ |
| 296 | public double offsetY() { |
| 297 | return offsetY; |
| 298 | } |
| 299 | |
Simon Hunt | f679c4e | 2016-04-01 17:02:24 -0700 | [diff] [blame] | 300 | } |