001/* 002 * Copyright 2011 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.skinfactory.generators; 017 018import java.io.File; 019import java.io.IOException; 020import java.util.ArrayList; 021import java.util.Collection; 022import java.util.HashMap; 023import java.util.LinkedHashMap; 024import java.util.List; 025import java.util.Map; 026import java.util.regex.Pattern; 027 028import org.apache.avalon.framework.service.ServiceException; 029import org.apache.avalon.framework.service.ServiceManager; 030import org.apache.cocoon.ProcessingException; 031import org.apache.cocoon.components.source.SourceUtil; 032import org.apache.cocoon.generation.ServiceableGenerator; 033import org.apache.cocoon.xml.AttributesImpl; 034import org.apache.cocoon.xml.XMLUtils; 035import org.apache.commons.lang.StringUtils; 036import org.apache.excalibur.source.impl.FileSource; 037import org.xml.sax.SAXException; 038 039import org.ametys.core.util.I18nUtils; 040import org.ametys.core.util.IgnoreRootHandler; 041import org.ametys.runtime.i18n.I18nizableText; 042import org.ametys.skinfactory.SkinFactoryComponent; 043import org.ametys.skinfactory.parameters.AbstractSkinParameter; 044import org.ametys.skinfactory.parameters.AbstractSkinParameter.SkinParameterType; 045import org.ametys.web.skin.SkinModel; 046import org.ametys.web.skin.SkinModelsManager; 047 048/** 049 * Generate the ribbon file 050 */ 051public class GenerateRibbonFile extends ServiceableGenerator 052{ 053 private SkinFactoryComponent _skinFactoryManager; 054 private SkinModelsManager _modelsManager; 055 private I18nUtils _i18nUtils; 056 057 private final HashMap<Pattern, String> _glyphAssociations = new LinkedHashMap<>(); 058 { 059 _glyphAssociations.put(Pattern.compile("^(h1|h2|h3|h4)$"), "ametysicon-header"); 060 _glyphAssociations.put(Pattern.compile("text"), "ametysicon-text"); 061 _glyphAssociations.put(Pattern.compile("link"), "ametysicon-link23"); 062 _glyphAssociations.put(Pattern.compile("list"), "ametysicon-list4"); 063 _glyphAssociations.put(Pattern.compile("vmenu^$"), "ametysicon-vmenu"); 064 _glyphAssociations.put(Pattern.compile("menu"), "ametysicon-menu"); 065 _glyphAssociations.put(Pattern.compile("^(item|subitem)$"), "ametysicon-menu-element"); 066 _glyphAssociations.put(Pattern.compile("title|header"), "ametysicon-header"); 067 _glyphAssociations.put(Pattern.compile("table"), "ametysicon-tables1"); 068 _glyphAssociations.put(Pattern.compile("border"), "ametysicon-tables1"); // FIXME when new icon has arrived 069 _glyphAssociations.put(Pattern.compile("image"), "ametysicon-image2"); 070 // Default glyph for unknown style 071 _glyphAssociations.put(Pattern.compile("."), "ametysicon-designer"); 072 } 073 074 @Override 075 public void service(ServiceManager smanager) throws ServiceException 076 { 077 super.service(smanager); 078 _skinFactoryManager = (SkinFactoryComponent) smanager.lookup(SkinFactoryComponent.ROLE); 079 _modelsManager = (SkinModelsManager) smanager.lookup(SkinModelsManager.ROLE); 080 _i18nUtils = (I18nUtils) smanager.lookup(I18nUtils.ROLE); 081 } 082 083 @Override 084 public void generate() throws IOException, SAXException, ProcessingException 085 { 086 contentHandler.startDocument(); 087 XMLUtils.startElement(contentHandler, "CMS"); 088 089 String modelName = parameters.getParameter("modelName", null); 090 SkinModel model = _modelsManager.getModel(modelName); 091 092 File ribbonFile = new File (model.getFile(), "model/cms-ribbon.xml"); 093 if (ribbonFile.exists()) 094 { 095 FileSource ribbonSrc = null; 096 try 097 { 098 ribbonSrc = new FileSource("file", ribbonFile); 099 SourceUtil.toSAX(ribbonSrc, new IgnoreRootHandler(contentHandler)); 100 } 101 finally 102 { 103 if (ribbonSrc != null) 104 { 105 resolver.release(ribbonSrc); 106 } 107 } 108 } 109 110 Map<String, RibbonTab> tabs = _getGroupedParams(_skinFactoryManager.getModelParameters(modelName)); 111 112 XMLUtils.startElement(contentHandler, "parameters"); 113 for (RibbonTab tab : tabs.values()) 114 { 115 AttributesImpl attrs = new AttributesImpl(); 116 attrs.addCDATAAttribute("id", tab.getId()); 117 attrs.addCDATAAttribute("label", _i18nUtils.translate(tab.getLabel())); 118 XMLUtils.startElement(contentHandler, "tab", attrs); 119 120 XMLUtils.startElement(contentHandler, "groups"); 121 122 Collection<RibbonGroup> groups = tab.getGroups(); 123 for (RibbonGroup group : groups) 124 { 125 attrs = new AttributesImpl(); 126 attrs.addCDATAAttribute("id", group.getId()); 127 attrs.addCDATAAttribute("label", _i18nUtils.translate(group.getLabel())); 128 XMLUtils.startElement(contentHandler, "group", attrs); 129 130 Collection<RibbonElement> elmts = group.getRibbonElements(); 131 for (RibbonElement elt : elmts) 132 { 133 if (elt instanceof ParameterControl) 134 { 135 attrs = new AttributesImpl(); 136 attrs.addCDATAAttribute("id", elt.getId()); 137 XMLUtils.createElement(contentHandler, "parameter", attrs); 138 } 139 else if (elt instanceof Menu) 140 { 141 _saxMenu ((Menu) elt); 142 } 143 } 144 XMLUtils.endElement(contentHandler, "group"); 145 } 146 XMLUtils.endElement(contentHandler, "groups"); 147 148 XMLUtils.endElement(contentHandler, "tab"); 149 } 150 XMLUtils.endElement(contentHandler, "parameters"); 151 152 XMLUtils.endElement(contentHandler, "CMS"); 153 contentHandler.endDocument(); 154 155 } 156 157 private void _saxMenu (Menu menu) throws SAXException 158 { 159 AttributesImpl attrs = new AttributesImpl(); 160 attrs.addCDATAAttribute("id", menu.getId()); 161 attrs.addCDATAAttribute("label", _i18nUtils.translate(menu.getLabel())); 162 _saxMenuIcons (menu, attrs); 163 XMLUtils.startElement(contentHandler, "menu", attrs); 164 165 for (String itemId : menu.getItems()) 166 { 167 attrs = new AttributesImpl(); 168 attrs.addCDATAAttribute("id", itemId); 169 XMLUtils.createElement(contentHandler, "parameter", attrs); 170 } 171 172 for (Menu submenu : menu.getMenus()) 173 { 174 _saxMenu(submenu); 175 } 176 177 XMLUtils.endElement(contentHandler, "menu"); 178 } 179 180 private Map<String, RibbonTab> _getGroupedParams (Map<String, AbstractSkinParameter> skinParameters) 181 { 182 Map<String, RibbonTab> tabs = new HashMap<>(); 183 184 for (AbstractSkinParameter param : skinParameters.values()) 185 { 186 String id = param.getId(); 187 String[] parts = id.split("\\."); 188 189 String tabId = "org.ametys.skinfactory.Tab." + (parts.length >= 3 ? parts[0] : "default"); 190 String groupId = parts.length >= 3 ? StringUtils.join(parts, ".", 0, 2) : "default.default"; 191 String eltId = null; 192 193 String itemId = null; 194 String subItemId = null; 195 196 if (parts.length <= 3 || !param.getType().equals(SkinParameterType.CSS)) 197 { 198 eltId = StringUtils.join(parts, "."); 199 } 200 else 201 { 202 eltId = StringUtils.join(parts, ".", 0, 3); 203 itemId = parts.length == 4 ? StringUtils.join(parts, ".") : StringUtils.join(parts, ".", 0, 4); 204 205 if (parts.length > 4) 206 { 207 subItemId = StringUtils.join(parts, "."); 208 } 209 } 210 211 _addGroupedParam(tabs, tabId, groupId, eltId, itemId, subItemId); 212 } 213 214 return tabs; 215 } 216 217 private void _addGroupedParam (Map<String, RibbonTab> tabs, String tabId, String groupId, String controlId, String itemId, String subItemId) 218 { 219 if (!tabs.containsKey(tabId)) 220 { 221 tabs.put(tabId, new RibbonTab(tabId, new I18nizableText(tabId.substring(tabId.lastIndexOf(".") + 1)))); 222 } 223 224 RibbonTab ribbonTab = tabs.get(tabId); 225 if (!ribbonTab.hasGroup(groupId)) 226 { 227 ribbonTab.addGroup(new RibbonGroup(groupId, new I18nizableText(groupId.substring(groupId.lastIndexOf(".") + 1)))); 228 } 229 230 RibbonGroup ribbonGroup = ribbonTab.getGroup(groupId); 231 232 if (itemId != null) 233 { 234 if (!ribbonGroup.hasRibbonElement(controlId)) 235 { 236 ribbonGroup.addRibbonElement(new Menu(controlId, new I18nizableText(controlId.substring(controlId.lastIndexOf(".") + 1)))); 237 } 238 239 RibbonElement ribbonControl = ribbonGroup.getRibbonElement(controlId); 240 241 if (ribbonControl instanceof Menu) 242 { 243 Menu menu = (Menu) ribbonControl; 244 245 if (subItemId == null) 246 { 247 menu.addItem(itemId); 248 } 249 else 250 { 251 if (!menu.hasMenu(itemId)) 252 { 253 menu.addMenu(new Menu(itemId, new I18nizableText(itemId.substring(itemId.lastIndexOf(".") + 1)))); 254 } 255 256 Menu subMenu = menu.getMenu(itemId); 257 subMenu.addItem(subItemId); 258 } 259 } 260 } 261 else 262 { 263 ribbonGroup.addRibbonElement(new ParameterControl(controlId)); 264 } 265 } 266 267 private void _saxMenuIcons (Menu menu, AttributesImpl attrs) 268 { 269 String label = _i18nUtils.translate(menu.getLabel()); 270 271 for (Map.Entry<Pattern, String> entry : _glyphAssociations.entrySet()) 272 { 273 Pattern pattern = entry.getKey(); 274 if (pattern.matcher(label).matches()) 275 { 276 attrs.addCDATAAttribute("iconGlyph", entry.getValue()); 277 return; 278 } 279 } 280 } 281 282 class RibbonTab 283 { 284 private I18nizableText _label; 285 private String _id; 286 private Map<String, RibbonGroup> _groups; 287 288 public RibbonTab(String id, I18nizableText label) 289 { 290 _id = id; 291 _label = label; 292 _groups = new HashMap<>(); 293 } 294 295 String getId () 296 { 297 return _id; 298 } 299 300 I18nizableText getLabel () 301 { 302 return _label; 303 } 304 305 Collection<RibbonGroup> getGroups () 306 { 307 return _groups.values(); 308 } 309 310 void addGroup (RibbonGroup group) 311 { 312 _groups.put(group.getId(), group); 313 } 314 315 boolean hasGroup (String groupId) 316 { 317 return _groups.containsKey(groupId); 318 } 319 320 RibbonGroup getGroup (String groupId) 321 { 322 return _groups.get(groupId); 323 } 324 } 325 326 class RibbonGroup 327 { 328 private String _id; 329 private I18nizableText _label; 330 private Map<String, RibbonElement> _ribbonElts; 331 332 public RibbonGroup(String id, I18nizableText label) 333 { 334 _id = id; 335 _label = label; 336 _ribbonElts = new HashMap<>(); 337 } 338 339 String getId() 340 { 341 return _id; 342 } 343 344 I18nizableText getLabel () 345 { 346 return _label; 347 } 348 349 void addRibbonElement (RibbonElement control) 350 { 351 _ribbonElts.put(control.getId(), control); 352 } 353 354 boolean hasRibbonElement (String controlId) 355 { 356 return _ribbonElts.containsKey(controlId); 357 } 358 359 RibbonElement getRibbonElement (String controlId) 360 { 361 return _ribbonElts.get(controlId); 362 } 363 364 Collection<RibbonElement> getRibbonElements () 365 { 366 return _ribbonElts.values(); 367 } 368 } 369 370 interface RibbonElement 371 { 372 public String getId(); 373 } 374 375 class Menu implements RibbonElement 376 { 377 private String _id; 378 private I18nizableText _label; 379 private List<String> _items; 380 private Map<String, Menu> _menus; 381 382 public Menu(String id, I18nizableText label) 383 { 384 _id = id; 385 _label = label; 386 _items = new ArrayList<>(); 387 _menus = new HashMap<>(); 388 } 389 390 @Override 391 public String getId() 392 { 393 return _id; 394 } 395 396 I18nizableText getLabel () 397 { 398 return _label; 399 } 400 401 void addItem (String id) 402 { 403 _items.add(id); 404 } 405 406 void addMenu (Menu menu) 407 { 408 _menus.put(menu.getId(), menu); 409 } 410 411 boolean hasMenu (String menuId) 412 { 413 return _menus.containsKey(menuId); 414 } 415 416 Menu getMenu (String menuId) 417 { 418 return _menus.get(menuId); 419 } 420 421 List<String> getItems () 422 { 423 return _items; 424 } 425 426 Collection<Menu> getMenus() 427 { 428 return _menus.values(); 429 } 430 } 431 432 class ParameterControl implements RibbonElement 433 { 434 private String _id; 435 public ParameterControl(String id) 436 { 437 _id = id; 438 } 439 440 @Override 441 public String getId() 442 { 443 return _id; 444 } 445 } 446}