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}