001/* 002 * Copyright 2010 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.clientsideelement; 017 018import java.util.ArrayList; 019import java.util.Comparator; 020import java.util.HashSet; 021import java.util.List; 022import java.util.Map; 023import java.util.Set; 024import java.util.TreeMap; 025import java.util.TreeSet; 026 027import org.apache.avalon.framework.configuration.Configuration; 028import org.apache.avalon.framework.configuration.DefaultConfiguration; 029import org.apache.avalon.framework.service.ServiceException; 030import org.apache.avalon.framework.service.ServiceManager; 031 032import org.ametys.cms.content.RootContentHelper; 033import org.ametys.cms.contenttype.ContentType; 034import org.ametys.cms.contenttype.ContentTypeExtensionPoint; 035import org.ametys.core.right.RightManager.RightResult; 036import org.ametys.core.ui.SimpleMenu; 037import org.ametys.core.ui.StaticClientSideElement; 038import org.ametys.core.user.UserIdentity; 039import org.ametys.core.util.I18nUtils; 040import org.ametys.core.util.I18nizableTextKeyComparator; 041import org.ametys.runtime.i18n.I18nizableText; 042 043/** 044 * This element creates a menu item with one menu item per content type. 045 * The user rights are checked. 046 */ 047public class ContentTypesMenuItem extends SimpleMenu 048{ 049 /** The list of content types */ 050 protected ContentTypeExtensionPoint _contentTypeExtensionPoint; 051 /** The i18n utils */ 052 protected I18nUtils _i18nUtils; 053 /** Helper for root content */ 054 protected RootContentHelper _rootContentHelper; 055 056 private boolean _contentTypesInitialized; 057 058 private Set<String> _addedComponents; 059 060 @Override 061 public void service(ServiceManager smanager) throws ServiceException 062 { 063 super.service(smanager); 064 _contentTypeExtensionPoint = (ContentTypeExtensionPoint) smanager.lookup(ContentTypeExtensionPoint.ROLE); 065 _i18nUtils = (I18nUtils) smanager.lookup(I18nUtils.ROLE); 066 _rootContentHelper = (RootContentHelper) smanager.lookup(RootContentHelper.ROLE); 067 } 068 069 private synchronized void _lazyInitializeContentTypeMenu() 070 { 071 if (!_contentTypesInitialized) 072 { 073 _addedComponents = new HashSet<>(); 074 075 Map<I18nizableText, Set<ContentType>> cTypesByGroup = _getContentTypesByGroup(); 076 077 if (cTypesByGroup.size() > 0) 078 { 079 for (I18nizableText groupLabel : cTypesByGroup.keySet()) 080 { 081 Set<ContentType> cTypes = cTypesByGroup.get(groupLabel); 082 for (ContentType cType : cTypes) 083 { 084 String id = this.getId() + "-" + cType.getId(); 085 086 Configuration conf = _getContentTypeConfiguration (id, cType); 087 if (!_addedComponents.contains(id)) 088 { 089 _menuItemManager.addComponent(_pluginName, null, id, StaticClientSideElement.class, conf); 090 _unresolvedMenuItems.add(new UnresolvedItem(id, true)); 091 _addedComponents.add(id); 092 } 093 } 094 } 095 } 096 } 097 098 _contentTypesInitialized = true; 099 } 100 101 /** 102 * Get the configuration of the content type item 103 * @param id The id of item 104 * @param cType The content type 105 * @return The configuration 106 */ 107 protected Configuration _getContentTypeConfiguration (String id, ContentType cType) 108 { 109 DefaultConfiguration conf = new DefaultConfiguration("extension"); 110 conf.setAttribute("id", id); 111 112 DefaultConfiguration classConf = new DefaultConfiguration("class"); 113 classConf.setAttribute("name", "Ametys.ribbon.element.ui.ButtonController"); 114 115 // Label 116 DefaultConfiguration labelConf = new DefaultConfiguration("label"); 117 labelConf.setValue(_i18nUtils.translate(cType.getLabel())); 118 classConf.addChild(labelConf); 119 120 // Description 121 DefaultConfiguration descConf = new DefaultConfiguration("description"); 122 descConf.setValue(_i18nUtils.translate(cType.getDescription())); 123 classConf.addChild(descConf); 124 125 // Content type 126 DefaultConfiguration typeConf = new DefaultConfiguration("contentTypes"); 127 typeConf.setValue(cType.getId()); 128 classConf.addChild(typeConf); 129 130 // Icons or glyph 131 if (cType.getIconGlyph() != null) 132 { 133 DefaultConfiguration iconGlyphConf = new DefaultConfiguration("icon-glyph"); 134 iconGlyphConf.setValue(cType.getIconGlyph()); 135 classConf.addChild(iconGlyphConf); 136 } 137 if (cType.getIconDecorator() != null) 138 { 139 DefaultConfiguration iconDecoratorConf = new DefaultConfiguration("icon-decorator"); 140 iconDecoratorConf.setValue(cType.getIconDecorator()); 141 classConf.addChild(iconDecoratorConf); 142 } 143 if (cType.getSmallIcon() != null) 144 { 145 DefaultConfiguration iconSmallConf = new DefaultConfiguration("icon-small"); 146 iconSmallConf.setValue(cType.getSmallIcon()); 147 classConf.addChild(iconSmallConf); 148 DefaultConfiguration iconMediumConf = new DefaultConfiguration("icon-medium"); 149 iconMediumConf.setValue(cType.getMediumIcon()); 150 classConf.addChild(iconMediumConf); 151 DefaultConfiguration iconLargeConf = new DefaultConfiguration("icon-large"); 152 iconLargeConf.setValue(cType.getLargeIcon()); 153 classConf.addChild(iconLargeConf); 154 } 155 156 // Common configuration 157 @SuppressWarnings("unchecked") 158 Map<String, Object> commonConfig = (Map<String, Object>) this._script.getParameters().get("items-config"); 159 for (String tagName : commonConfig.keySet()) 160 { 161 DefaultConfiguration c = new DefaultConfiguration(tagName); 162 c.setValue(String.valueOf(commonConfig.get(tagName))); 163 classConf.addChild(c); 164 } 165 166 conf.addChild(classConf); 167 return conf; 168 } 169 170 /** 171 * Get the list of content types classified by groups 172 * @return The content types 173 */ 174 protected Map<I18nizableText, Set<ContentType>> _getContentTypesByGroup () 175 { 176 Map<I18nizableText, Set<ContentType>> groups = new TreeMap<>(new I18nizableTextKeyComparator()); 177 178 if (this._script.getParameters().get("contentTypes") != null) 179 { 180 String[] contentTypesIds = ((String) this._script.getParameters().get("contentTypes")).split(","); 181 182 boolean allowInherit = "true".equals(this._script.getParameters().get("allowInherit")); 183 184 for (String contentTypeId : contentTypesIds) 185 { 186 ContentType contentType = _contentTypeExtensionPoint.getExtension(contentTypeId); 187 188 if (isValidContentType(contentType)) 189 { 190 addContentType (contentType, groups); 191 } 192 193 if (allowInherit) 194 { 195 for (String subTypeId : _contentTypeExtensionPoint.getSubTypes(contentTypeId)) 196 { 197 ContentType subContentType = _contentTypeExtensionPoint.getExtension(subTypeId); 198 if (isValidContentType(subContentType)) 199 { 200 addContentType (subContentType, groups); 201 } 202 } 203 } 204 } 205 } 206 else 207 { 208 Set<String> contentTypesIds = _contentTypeExtensionPoint.getExtensionsIds(); 209 210 for (String contentTypeId : contentTypesIds) 211 { 212 ContentType contentType = _contentTypeExtensionPoint.getExtension(contentTypeId); 213 214 if (isValidContentType(contentType)) 215 { 216 addContentType (contentType, groups); 217 } 218 } 219 } 220 221 return groups; 222 } 223 224 /** 225 * Add content to groups 226 * @param contentType The content type 227 * @param groups The groups 228 */ 229 protected void addContentType (ContentType contentType, Map<I18nizableText, Set<ContentType>> groups) 230 { 231 I18nizableText group = contentType.getCategory(); 232 if (group.isI18n() && group.getKey().isEmpty() 233 || !group.isI18n() && group.getLabel().isEmpty()) 234 { 235 group = new I18nizableText("plugin.cms", "PLUGINS_CMS_CONTENT_CREATECONTENTMENU_GROUP_10_CONTENT"); 236 } 237 238 if (!groups.containsKey(group)) 239 { 240 groups.put(group, new TreeSet<>(new ContentTypeComparator())); 241 } 242 Set<ContentType> cTypes = groups.get(group); 243 cTypes.add(contentType); 244 } 245 246 @Override 247 public List<Script> getScripts(boolean ignoreRights, Map<String, Object> contextParameters) 248 { 249 try 250 { 251 _lazyInitializeContentTypeMenu(); 252 } 253 catch (Exception e) 254 { 255 throw new IllegalStateException("Unable to lookup client side element local components", e); 256 } 257 258 for (String id: _contentTypeExtensionPoint.getExtensionsIds()) 259 { 260 ContentType contentType = _contentTypeExtensionPoint.getExtension(id); 261 if (isValidContentType(contentType)) 262 { 263 return super.getScripts(ignoreRights, contextParameters); 264 } 265 } 266 return new ArrayList<>(); 267 } 268 269 /** 270 * Determines if the content type is a valid content type for the gallery 271 * @param contentType The coentent 272 * @return true if it is a valid content type 273 */ 274 protected boolean isValidContentType (ContentType contentType) 275 { 276 return !contentType.isAbstract() && !contentType.isPrivate() && !contentType.isMixin(); 277 } 278 279 /** 280 * Test if the current user has the right needed by the content type to create a content. 281 * @param cType the content type 282 * @return true if the user has the right needed, false otherwise. 283 */ 284 protected boolean hasRight(ContentType cType) 285 { 286 String right = cType.getRight(); 287 288 if (right == null) 289 { 290 return true; 291 } 292 else 293 { 294 UserIdentity user = _currentUserProvider.getUser(); 295 return _rightManager.hasRight(user, right, "/cms") == RightResult.RIGHT_ALLOW || _rightManager.hasRight(user, right, _rootContentHelper.getRootContent()) == RightResult.RIGHT_ALLOW; 296 } 297 } 298 299 class ContentTypeComparator implements Comparator<ContentType> 300 { 301 @Override 302 public int compare(ContentType c1, ContentType c2) 303 { 304 I18nizableText t1 = c1.getLabel(); 305 I18nizableText t2 = c2.getLabel(); 306 307 String str1 = t1.isI18n() ? t1.getKey() : t1.getLabel(); 308 String str2 = t2.isI18n() ? t2.getKey() : t2.getLabel(); 309 310 int compareTo = str1.toString().compareTo(str2.toString()); 311 if (compareTo == 0) 312 { 313 // Content types have same keys but there are not equals, so do not return 0 to add it in TreeSet 314 // Indeed, in a TreeSet implementation two elements that are equal by the method compareTo are, from the standpoint of the set, equal 315 return 1; 316 } 317 return compareTo; 318 } 319 } 320}