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