001/* 002 * Copyright 2018 Anyware Services 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016package org.ametys.runtime.model; 017 018import java.util.ArrayList; 019import java.util.Collection; 020import java.util.Collections; 021import java.util.LinkedHashMap; 022import java.util.List; 023import java.util.Map; 024import java.util.Objects; 025 026import org.apache.cocoon.ProcessingException; 027 028import org.ametys.runtime.i18n.I18nizableText; 029import org.ametys.runtime.model.exception.BadItemTypeException; 030import org.ametys.runtime.util.ModifiableLabelable; 031 032/** 033 * View of items 034 */ 035public class View implements ViewItemContainer, ModifiableLabelable 036{ 037 private String _name; 038 private I18nizableText _label; 039 private I18nizableText _description; 040 private String _iconGlyph; 041 private String _iconDecorator; 042 private String _smallIcon; 043 private String _mediumIcon; 044 private String _largeIcon; 045 private boolean _isInternal; 046 047 private List<ViewItem> _items = new ArrayList<>(); 048 049 /** 050 * Creates a {@link View} with the items of the given {@link Model} 051 * @param model the model 052 * @return the created {@link View} 053 * @throws IllegalArgumentException if the model is <code>null</code> 054 */ 055 public static View of(Model model) throws IllegalArgumentException 056 { 057 if (model == null) 058 { 059 throw new IllegalArgumentException("Unable to create the view from a null model"); 060 } 061 else 062 { 063 return ViewHelper.createViewItemAccessor(List.of(model)); 064 } 065 } 066 067 /** 068 * Creates a {@link View} with the items of the given {@link Model}s 069 * @param models the models 070 * @return the created {@link View} 071 * @throws IllegalArgumentException if the models collection is empty 072 */ 073 public static View of(Collection<? extends Model> models) throws IllegalArgumentException 074 { 075 return ViewHelper.createViewItemAccessor(models); 076 } 077 078 /** 079 * Creates a {@link View} with the given items 080 * @param model the model containing items definitions 081 * @param itemPaths the paths of the items to put in the view 082 * @return the created {@link View} 083 * @throws IllegalArgumentException if the model is <code>null</code> or if an item path is <code>null</code>, empty, or is not defined in the given models 084 * @throws BadItemTypeException if a segment in a path (but not the last) does not represent a group item 085 */ 086 public static View of(Model model, String... itemPaths) throws IllegalArgumentException, BadItemTypeException 087 { 088 if (model == null) 089 { 090 throw new IllegalArgumentException("Unable to create the view from a null model"); 091 } 092 else 093 { 094 return ViewHelper.createViewItemAccessor(List.of(model), itemPaths); 095 } 096 } 097 098 /** 099 * Creates a {@link View} with the given items 100 * @param models the models containing items definitions 101 * @param itemPaths the paths of the items to put in the view 102 * @return the created {@link View} 103 * @throws IllegalArgumentException if the models collection is empty or if an item path is <code>null</code>, empty, or is not defined in the given models 104 * @throws BadItemTypeException if a segment in a path (but not the last) does not represent a group item 105 */ 106 public static View of(Collection<? extends Model> models, String... itemPaths) throws IllegalArgumentException, BadItemTypeException 107 { 108 return ViewHelper.createViewItemAccessor(models, itemPaths); 109 } 110 111 /** 112 * Creates a {@link View} with the given items. If the items are in a group, the hierarchy will be kept and the corresponding containers will be created 113 * @param modelItems the items to put in the view 114 * @return the created {@link View} 115 */ 116 public static View of(ModelItem... modelItems) 117 { 118 View view = new View(); 119 120 for (ModelItem modelItem : modelItems) 121 { 122 ViewHelper.addViewItem(modelItem.getPath(), view, modelItem.getModel()); 123 } 124 125 return view; 126 } 127 128 /** 129 * Copy the current view in the given one. 130 * Its view items are not copied 131 * @param view the copy 132 */ 133 public void copyTo(View view) 134 { 135 view.setName(getName()); 136 view.setLabel(getLabel()); 137 view.setDescription(getDescription()); 138 view.setInternal(isInternal()); 139 140 view.setIconGlyph(getIconGlyph()); 141 view.setIconDecorator(getIconDecorator()); 142 view.setSmallIcon(getSmallIcon()); 143 view.setMediumIcon(getMediumIcon()); 144 view.setLargeIcon(getLargeIcon()); 145 } 146 147 public String getName() 148 { 149 return _name; 150 } 151 152 public void setName(String name) 153 { 154 _name = name; 155 } 156 157 public I18nizableText getLabel() 158 { 159 return _label; 160 } 161 162 public void setLabel(I18nizableText label) 163 { 164 _label = label; 165 } 166 167 public I18nizableText getDescription() 168 { 169 return _description; 170 } 171 172 public void setDescription(I18nizableText description) 173 { 174 _description = description; 175 } 176 177 /** 178 * Retrieves the CSS class to use for glyph icon 179 * @return the glyph name. 180 */ 181 public String getIconGlyph() 182 { 183 return _iconGlyph; 184 } 185 186 /** 187 * Set the CSS class to use for glyph icon 188 * @param iconGlyph the glyph name. 189 */ 190 public void setIconGlyph(String iconGlyph) 191 { 192 _iconGlyph = iconGlyph; 193 } 194 195 /** 196 * Retrieves the CSS class to use for decorator above the main icon 197 * @return the glyph name. 198 */ 199 public String getIconDecorator() 200 { 201 return _iconDecorator; 202 } 203 204 /** 205 * Set the CSS class to use for decorator above the main icon 206 * @param iconDecorator the glyph name. 207 */ 208 public void setIconDecorator(String iconDecorator) 209 { 210 _iconDecorator = iconDecorator; 211 } 212 213 /** 214 * Retrieves the URL of the small icon without the context path. 215 * @return the icon URL for the small image 16x16. 216 */ 217 public String getSmallIcon() 218 { 219 return _smallIcon; 220 } 221 222 /** 223 * Set the URL of the small icon. 224 * @param smallIcon the URL of the small icon, without the context path. 225 */ 226 public void setSmallIcon(String smallIcon) 227 { 228 _smallIcon = smallIcon; 229 } 230 231 /** 232 * Retrieves the URL of the small icon without the context path. 233 * @return the icon URL for the medium sized image 32x32. 234 */ 235 public String getMediumIcon() 236 { 237 return _mediumIcon; 238 } 239 240 /** 241 * Set the URL of the medium icon. 242 * @param mediumIcon the URL of the medium icon, without the context path. 243 */ 244 public void setMediumIcon(String mediumIcon) 245 { 246 _mediumIcon = mediumIcon; 247 } 248 249 /** 250 * Retrieves the URL of the small icon without the context path. 251 * @return the icon URL for the large image 48x48. 252 */ 253 public String getLargeIcon() 254 { 255 return _largeIcon; 256 } 257 258 /** 259 * Set the URL of the large icon. 260 * @param largeIcon the URL of the large icon, without the context path. 261 */ 262 public void setLargeIcon(String largeIcon) 263 { 264 _largeIcon = largeIcon; 265 } 266 267 /** 268 * Determines if the view is for internal use only 269 * @return <code>true</code> if the view is for internal use only, <code>false</code> otherwise 270 */ 271 public boolean isInternal() 272 { 273 return _isInternal; 274 } 275 276 /** 277 * Set the internal status 278 * @param isInternal <code>true</code> to make the view for internal use only, <code>false</code> otherwise 279 */ 280 public void setInternal(boolean isInternal) 281 { 282 _isInternal = isInternal; 283 } 284 285 public List<ViewItem> getViewItems() 286 { 287 return Collections.unmodifiableList(this._items); 288 } 289 290 public void addViewItem(ViewItem item) 291 { 292 _items.add(item); 293 } 294 295 public void insertViewItem(ViewItem item, int index) 296 { 297 if (index >= 0 && index <= _items.size()) 298 { 299 _items.add(index, item); 300 } 301 else 302 { 303 throw new IllegalArgumentException("Unable to insert an item at index " + index + ". This group contains " + _items.size() + " items."); 304 } 305 } 306 307 public boolean removeViewItem(ViewItem item) 308 { 309 return _items.remove(item); 310 } 311 312 public void clear() 313 { 314 _items.clear(); 315 } 316 317 /** 318 * Converts the view in a JSON map 319 * @param context the context of the definitions included in the view 320 * @return The view as a JSON map 321 * @throws ProcessingException If an error occurs when converting the view 322 */ 323 public Map<String, Object> toJSON(DefinitionContext context) throws ProcessingException 324 { 325 Map<String, Object> result = new LinkedHashMap<>(); 326 327 result.put("name", getName()); 328 result.put("label", getLabel()); 329 result.put("description", getDescription()); 330 331 result.put("icon-glyph", getIconGlyph()); 332 result.put("icon-decorator", getIconDecorator()); 333 result.put("small-icon-path", getSmallIcon()); 334 result.put("medium-icon-path", getMediumIcon()); 335 result.put("large-icon-path", getLargeIcon()); 336 337 result.put("elements", ViewHelper.viewItemsToJSON(getViewItems(), context)); 338 339 return result; 340 } 341 342 /** 343 * Include the given view to the current one. 344 * Add the items of the view to include if they are not already present in the current view 345 * @param viewToInclude the view to include 346 */ 347 public void includeView(View viewToInclude) 348 { 349 View referenceView = new View(); 350 referenceView.addViewItems(getViewItems()); 351 ViewHelper.addViewAccessorItems(this, viewToInclude, referenceView); 352 } 353 354 @Override 355 public int hashCode() 356 { 357 return Objects.hash(_items, _name); 358 } 359 360 @Override 361 public boolean equals(Object obj) 362 { 363 if (this == obj) 364 { 365 return true; 366 } 367 if (obj == null) 368 { 369 return false; 370 } 371 if (getClass() != obj.getClass()) 372 { 373 return false; 374 } 375 View other = (View) obj; 376 return Objects.equals(_items, other._items) && Objects.equals(_name, other._name); 377 } 378 379 /** 380 * Indicates whether some other object is "equal to" this one. 381 * @param obj the reference object with which to compare. 382 * @param checkDetails <code>true</code> to check the view's details during comparison (label, description, icon, ...) 383 * @return <code>true</code> if this object is the same as the given obj, <code>false</code> otherwise. 384 */ 385 public boolean equals(Object obj, boolean checkDetails) 386 { 387 if (!equals(obj)) 388 { 389 return false; 390 } 391 else if (checkDetails) 392 { 393 View other = (View) obj; 394 395 for (int i = 0; i < _items.size(); i++) 396 { 397 ViewItem item = _items.get(i); 398 ViewItem otherItem = other._items.get(i); 399 400 if (!item.equals(otherItem, checkDetails)) 401 { 402 return false; 403 } 404 } 405 406 return Objects.equals(_description, other._description) && Objects.equals(_iconDecorator, other._iconDecorator) && Objects.equals(_iconGlyph, other._iconGlyph) 407 && _isInternal == other._isInternal && Objects.equals(_label, other._label); 408 } 409 else 410 { 411 return true; 412 } 413 } 414}