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