001/* 002 * Copyright 2023 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.cms.search.ui.model.impl; 017 018import java.util.ArrayList; 019import java.util.HashMap; 020import java.util.List; 021import java.util.Map; 022import java.util.Optional; 023 024import org.ametys.cms.search.ui.model.SearchUIColumn; 025import org.ametys.cms.search.ui.model.SearchUIColumnHelper; 026import org.ametys.plugins.repository.model.CompositeDefinition; 027import org.ametys.plugins.repository.model.RepeaterDefinition; 028import org.ametys.runtime.model.DefinitionContext; 029import org.ametys.runtime.model.ModelItem; 030import org.ametys.runtime.model.ModelViewItem; 031import org.ametys.runtime.model.ModelViewItemGroup; 032import org.ametys.runtime.model.ViewItem; 033import org.ametys.runtime.model.ViewItemAccessor; 034 035/** 036 * This class represents a result column 037 */ 038public class RepeaterSearchUIColumn extends ModelViewItemGroup<RepeaterDefinition> implements SearchUIColumn<RepeaterDefinition> 039{ 040 private int _width = -1; 041 private boolean _hidden; 042 private boolean _editable = true; 043 private boolean _sortable = true; 044 private boolean _allowSortOnMultipleJoin; 045 private Optional<String> _defaultSorter = Optional.empty(); 046 private Optional<String> _renderer = Optional.empty(); 047 private Optional<String> _converter = Optional.empty(); 048 049 public int getWidth() 050 { 051 return _width > 0 052 ? _width 053 : SearchUIColumnHelper.getDefaultColumnWidth(this); 054 } 055 056 public void setWidth (int width) 057 { 058 _width = width; 059 } 060 061 public boolean isHidden() 062 { 063 return _hidden; 064 } 065 066 public void setHidden (boolean hidden) 067 { 068 _hidden = hidden; 069 } 070 071 public boolean isEditable() 072 { 073 return _editable && SearchUIColumnHelper.isEditionAllowed(this); 074 } 075 076 public void setEditable (boolean editable) 077 { 078 _editable = editable; 079 } 080 081 public boolean isSortable() 082 { 083 return _sortable && SearchUIColumnHelper.isSortAllowed(this); 084 } 085 086 public void setSortable (boolean sortable) 087 { 088 _sortable = sortable; 089 } 090 091 public boolean allowSortOnMultipleJoin() 092 { 093 return _allowSortOnMultipleJoin; 094 } 095 096 public void setAllowSortOnMultipleJoin(boolean allowSortOnMultipleJoin) 097 { 098 _allowSortOnMultipleJoin = allowSortOnMultipleJoin; 099 } 100 101 public String getDefaultSorter() 102 { 103 return isSortable() 104 ? _defaultSorter.orElse(null) 105 : null; 106 } 107 108 public void setDefaultSorter(Optional<String> defaultSorter) 109 { 110 _defaultSorter = defaultSorter; 111 } 112 113 public String getRenderer() 114 { 115 return _renderer 116 .orElse("Ametys.plugins.cms.search.SearchGridHelper.renderRepeater"); 117 } 118 119 public void setRenderer(Optional<String> renderer) 120 { 121 this._renderer = renderer; 122 } 123 124 public String getConverter() 125 { 126 return _converter 127 .orElse("Ametys.plugins.cms.search.SearchGridHelper.convertRepeater"); 128 } 129 130 public void setConverter(Optional<String> converter) 131 { 132 this._converter = converter; 133 } 134 135 @Override 136 public RepeaterSearchUIColumn createInstance() 137 { 138 return new RepeaterSearchUIColumn(); 139 } 140 141 @Override 142 public Map<String, Object> toJSON(DefinitionContext context) 143 { 144 Map<String, Object> json = super.toJSON(context); 145 146 if (!json.isEmpty()) 147 { 148 json.putAll(SearchUIColumnHelper.columnPropertiesToJSON(this)); 149 } 150 return json; 151 } 152 153 @Override 154 protected Map<String, Object> _childrenToJSON(DefinitionContext context) 155 { 156 Map<String, Object> result = new HashMap<>(); 157 List<Map<String, Object>> subColumnsAsJSON = new ArrayList<>(); 158 159 ViewItemAccessor viewItemAccessor = getViewItems().isEmpty() ? _createRepeaterSearchUIColumn() : this; 160 for (ModelViewItem subColumn : _getSubColumns(viewItemAccessor)) 161 { 162 subColumnsAsJSON.add(subColumn.toJSON(context)); 163 } 164 165 result.put("columns", subColumnsAsJSON); 166 return result; 167 } 168 169 private RepeaterSearchUIColumn _createRepeaterSearchUIColumn() 170 { 171 RepeaterSearchUIColumn repeaterSearchUIColumn = new RepeaterSearchUIColumn(); 172 repeaterSearchUIColumn.setDefinition(getDefinition()); 173 174 repeaterSearchUIColumn.addViewItems(_createViewItems(repeaterSearchUIColumn)); 175 176 return repeaterSearchUIColumn; 177 } 178 179 private List<ViewItem> _createViewItems(ModelViewItemGroup group) 180 { 181 List<ViewItem> viewItems = new ArrayList<>(); 182 183 for (ModelItem modelItem : group.getDefinition().getModelItems()) 184 { 185 if (modelItem instanceof CompositeDefinition compositeDefinition) 186 { 187 ModelViewItemGroup<CompositeDefinition> compositeViewItem = new ModelViewItemGroup<>(); 188 compositeViewItem.setDefinition(compositeDefinition); 189 190 compositeViewItem.addViewItems(_createViewItems(compositeViewItem)); 191 192 viewItems.add(compositeViewItem); 193 } 194 else 195 { 196 SearchUIColumn column = SearchUIColumnHelper.createModelItemColumn(modelItem); 197 viewItems.add(column); 198 } 199 } 200 201 return viewItems; 202 } 203 204 private List<ModelViewItem> _getSubColumns(ViewItemAccessor viewItemAccessor) 205 { 206 List<ModelViewItem> subColumns = new ArrayList<>(); 207 208 org.ametys.plugins.repository.model.ViewHelper.visitView(viewItemAccessor, 209 (element, definition) -> { 210 // attribute 211 subColumns.add(element); 212 }, 213 (group, definition) -> { 214 // composite 215 // CMS-10740 - explode composite to have all its children at first level 216 subColumns.addAll(_getSubColumns(group)); 217 }, 218 (group, definition) -> { 219 // repeater 220 subColumns.add(group); 221 }, 222 group -> { 223 // group 224 subColumns.addAll(_getSubColumns(group)); 225 } 226 ); 227 228 return subColumns; 229 } 230 231 @Override 232 public void copyTo(ViewItem item) 233 { 234 super.copyTo(item); 235 236 assert item instanceof RepeaterSearchUIColumn; 237 RepeaterSearchUIColumn column = (RepeaterSearchUIColumn) item; 238 239 column.setWidth(_width); 240 column.setHidden(_hidden); 241 242 column.setEditable(_editable); 243 column.setSortable(_sortable); 244 column.setAllowSortOnMultipleJoin(_allowSortOnMultipleJoin); 245 column.setDefaultSorter(_defaultSorter); 246 247 column.setRenderer(_renderer); 248 column.setConverter(_converter); 249 } 250}