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