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; 017 018import java.util.Collection; 019import java.util.List; 020import java.util.Optional; 021 022import org.apache.avalon.framework.configuration.ConfigurationException; 023import org.apache.avalon.framework.configuration.DefaultConfiguration; 024 025import org.ametys.cms.contenttype.AbstractContentTypeViewParser; 026import org.ametys.cms.contenttype.ContentType; 027import org.ametys.cms.repository.Content; 028import org.ametys.cms.search.model.SystemProperty; 029import org.ametys.cms.search.ui.model.impl.RepeaterSearchUIColumn; 030import org.ametys.plugins.repository.model.CompositeDefinition; 031import org.ametys.plugins.repository.model.RepeaterDefinition; 032import org.ametys.runtime.model.ElementDefinition; 033import org.ametys.runtime.model.ItemParserHelper.ConfigurationAndPluginName; 034import org.ametys.runtime.model.Model; 035import org.ametys.runtime.model.ModelItem; 036import org.ametys.runtime.model.ModelItemAccessor; 037import org.ametys.runtime.model.ModelViewItem; 038import org.ametys.runtime.model.ModelViewItemGroup; 039import org.ametys.runtime.model.View; 040import org.ametys.runtime.model.ViewItem; 041 042/** 043 * Component that parses the columns of a {@link StaticSearchUIModel} 044 */ 045public class StaticSearchUIModelColumnsParser extends AbstractContentTypeViewParser 046{ 047 private static final String __VIEW_NAME = "StaticSearchUIModel-Columns"; 048 049 /** Content types containing the item available in the search model's columns */ 050 protected Collection<ContentType> _contentTypes; 051 052 /** 053 * Creates a {@link StaticSearchUIModel}'s columns parser 054 * @param contentTypes The content types containing the item available in the search model's columns 055 */ 056 public StaticSearchUIModelColumnsParser(Collection<ContentType> contentTypes) 057 { 058 _contentTypes = contentTypes; 059 } 060 061 @Override 062 protected String _parseViewName(ConfigurationAndPluginName viewConfiguration) throws ConfigurationException 063 { 064 return __VIEW_NAME; 065 } 066 067 @Override 068 public View overrideView(ConfigurationAndPluginName viewConfiguration, View existingView) throws ConfigurationException 069 { 070 throw new UnsupportedOperationException("Unable to override columns of a search model"); 071 } 072 073 @Override 074 protected void _fillViewGeneralInformation(ConfigurationAndPluginName viewConfiguration, View view, View existingView, Collection< ? extends Model> model) throws ConfigurationException 075 { 076 // Do nothing - there is no general information in search model's columns 077 } 078 079 @Override 080 protected Collection<? extends Model> _getModel() 081 { 082 return _contentTypes; 083 } 084 085 @Override 086 protected ModelItem _getModelItem(ConfigurationAndPluginName itemConfiguration, String modelItemName, Collection< ? extends ModelItemAccessor> parents) throws ConfigurationException 087 { 088 ModelItem modelItem = parents.isEmpty() && Content.ATTRIBUTE_TITLE.equals(modelItemName) 089 ? _contentTypesHelper.getTitleAttributeDefinition() 090 : super._getModelItem(itemConfiguration, modelItemName, parents); 091 092 if (modelItem instanceof SystemProperty systemProperty && !systemProperty.isDisplayable()) 093 { 094 throw new ConfigurationException("The property '" + systemProperty.getName() + "' is not displayable."); 095 } 096 097 return modelItem; 098 } 099 100 @Override 101 protected ModelViewItem createModelViewItemForAllItemsReference(ConfigurationAndPluginName itemConfiguration, ModelItem modelItem, View referenceView, boolean override) throws ConfigurationException 102 { 103 if (modelItem instanceof CompositeDefinition compositeDefinition) 104 { 105 ModelViewItemGroup<CompositeDefinition> itemGroup = new ModelViewItemGroup<>(); 106 itemGroup.setDefinition(compositeDefinition); 107 return itemGroup; 108 } 109 else 110 { 111 return super.createModelViewItemForAllItemsReference(itemConfiguration, modelItem, referenceView, override); 112 } 113 } 114 115 @SuppressWarnings("unchecked") 116 @Override 117 protected ModelViewItem createModelViewItem(ConfigurationAndPluginName itemConfiguration, ModelItem modelItem, View referenceView, boolean override) throws ConfigurationException 118 { 119 ModelViewItem<? extends ModelItem> modelViewItem = super.createModelViewItem(itemConfiguration, modelItem, referenceView, override); 120 121 if (modelViewItem instanceof SearchUIColumn searchColumn) 122 { 123 searchColumn.setWidth(itemConfiguration.configuration().getChild("width").getValueAsInteger(-1)); 124 searchColumn.setHidden(itemConfiguration.configuration().getChild("hidden").getValueAsBoolean(false)); 125 126 searchColumn.setEditable(itemConfiguration.configuration().getChild("editable").getValueAsBoolean(true)); 127 searchColumn.setSortable(itemConfiguration.configuration().getChild("sortable").getValueAsBoolean(true)); 128 searchColumn.setAllowSortOnMultipleJoin(itemConfiguration.configuration().getChild("allow-sort-on-multiple-join").getValueAsBoolean(false)); 129 searchColumn.setDefaultSorter(Optional.ofNullable(itemConfiguration.configuration().getChild("default-sorter").getValue(null))); 130 131 searchColumn.setRenderer(Optional.ofNullable(itemConfiguration.configuration().getChild("renderer").getValue(null))); 132 searchColumn.setConverter(Optional.ofNullable(itemConfiguration.configuration().getChild("converter").getValue(null))); 133 } 134 135 if (modelViewItem instanceof RepeaterSearchUIColumn repeaterColumn && modelViewItem.getDefinition() instanceof RepeaterDefinition repeaterDefinition 136 && !_getModelItemReference(itemConfiguration.configuration()).endsWith(ALL_ITEMS_REFERENCE) 137 && itemConfiguration.configuration().getChildren(ADD_ITEM_TAG_NAME).length == 0 && itemConfiguration.configuration().getChildren(ADD_GROUP_TAG_NAME).length == 0) 138 { 139 // Reference to a repeater with no child => add all model items in the view item 140 DefaultConfiguration fakeConfiguration = new DefaultConfiguration(ADD_ITEM_TAG_NAME); 141 fakeConfiguration.setAttribute(ITEM_REFERENCE_ATTRIBUTE_NAME, ALL_ITEMS_REFERENCE); 142 _parseModelViewItem(new ConfigurationAndPluginName(fakeConfiguration, itemConfiguration.pluginName()), repeaterColumn, List.of(repeaterDefinition), referenceView, override); 143 } 144 145 return modelViewItem; 146 } 147 148 @Override 149 protected ModelViewItem _createModelViewItemInstance(ModelItem modelItem) 150 { 151 return SearchUIColumnHelper.createModelItemColumn(modelItem); 152 } 153 154 @Override 155 protected ViewItem _createViewItemCopyInstanceForReferencedView(ViewItem viewItem) 156 { 157 return Optional.of(viewItem) 158 .filter(ModelViewItem.class::isInstance) 159 .map(ModelViewItem.class::cast) 160 .map(ModelViewItem::getDefinition) 161 // Keep only items that can be represented in columns 162 .filter(modelViewItem -> modelViewItem instanceof RepeaterDefinition || modelViewItem instanceof ElementDefinition) 163 .map(this::_createModelViewItemInstance) 164 .map(ViewItem.class::cast) 165 .orElseGet(() -> super._createViewItemCopyInstanceForReferencedView(viewItem)); 166 } 167}