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