001/*
002 *  Copyright 2012 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.web.clientsideelement;
017
018import java.util.HashMap;
019import java.util.Map;
020import java.util.Set;
021
022import org.apache.avalon.framework.configuration.Configuration;
023import org.apache.avalon.framework.configuration.ConfigurationException;
024import org.apache.avalon.framework.configuration.DefaultConfiguration;
025import org.apache.avalon.framework.service.ServiceException;
026import org.apache.avalon.framework.service.ServiceManager;
027import org.apache.commons.lang.StringUtils;
028
029import org.ametys.cms.contenttype.ContentType;
030import org.ametys.cms.contenttype.ContentTypeExtensionPoint;
031import org.ametys.cms.contenttype.ContentTypesHelper;
032import org.ametys.cms.repository.Content;
033import org.ametys.core.observation.Event;
034import org.ametys.core.observation.ObservationManager;
035import org.ametys.core.ui.Callable;
036import org.ametys.core.ui.SimpleMenu;
037import org.ametys.core.ui.StaticClientSideElement;
038import org.ametys.core.util.I18nUtils;
039import org.ametys.plugins.repository.AmetysObject;
040import org.ametys.plugins.repository.AmetysObjectResolver;
041import org.ametys.runtime.model.View;
042import org.ametys.web.ObservationConstants;
043import org.ametys.web.repository.page.ContentTypesAssignmentHandler;
044import org.ametys.web.repository.page.ModifiableZoneItem;
045import org.ametys.web.repository.page.ZoneItem.ZoneType;
046
047/**
048 * Menu giving the possibility to change the view rendering the content in a given ZoneItem.
049 */
050public class SetContentViewMenu extends SimpleMenu
051{
052    /** The content type extension point. */
053    protected ContentTypeExtensionPoint _contentTypeExtensionPoint;
054    
055    /** The content types assignment handler */
056    protected ContentTypesAssignmentHandler _cTypeHandler;
057    
058    /** The content types helper */
059    protected ContentTypesHelper _contentTypesHelper;
060    
061    /** Repository content */
062    protected AmetysObjectResolver _resolver;
063    
064    /** The observation manager */
065    protected ObservationManager _observationManager;
066    
067    /** The i18n utils */
068    protected I18nUtils _i18nUtils;
069    
070    private boolean _galleryInitialized;
071    
072    @Override
073    public void service(ServiceManager serviceManager) throws ServiceException
074    {
075        super.service(serviceManager);
076        _contentTypeExtensionPoint = (ContentTypeExtensionPoint) serviceManager.lookup(ContentTypeExtensionPoint.ROLE);
077        _cTypeHandler = (ContentTypesAssignmentHandler) serviceManager.lookup(ContentTypesAssignmentHandler.ROLE);
078        _resolver = (AmetysObjectResolver) serviceManager.lookup(AmetysObjectResolver.ROLE);
079        _i18nUtils = (I18nUtils) serviceManager.lookup(I18nUtils.ROLE);
080        _contentTypesHelper = (ContentTypesHelper) serviceManager.lookup(ContentTypesHelper.ROLE);
081        _observationManager = (ObservationManager) serviceManager.lookup(ObservationManager.ROLE);
082    }
083    
084    @Override
085    protected void _getGalleryItems(Map<String, Object> parameters, Map<String, Object> contextualParameters)
086    {
087        try
088        {
089            _lazyInitializeContentViewGallery();
090        }
091        catch (Exception e)
092        {
093            throw new IllegalStateException("Unable to lookup client side element local components", e);
094        }
095        
096        super._getGalleryItems(parameters, contextualParameters);
097    }
098    
099    private synchronized void _lazyInitializeContentViewGallery() throws ConfigurationException
100    {
101        if (!_galleryInitialized)
102        {
103            Set<String> contentTypesIds = _contentTypeExtensionPoint.getExtensionsIds();
104            
105            if (contentTypesIds.size() > 0)
106            {
107                GalleryItem galleryItem = new GalleryItem();
108                
109                for (String contentTypeId : contentTypesIds)
110                {
111                    ContentType contentType = _contentTypeExtensionPoint.getExtension(contentTypeId);
112                    
113                    GalleryGroup galleryGroup = new GalleryGroup(contentType.getLabel());
114                    galleryItem.addGroup(galleryGroup);
115                    
116                    for (String viewName : contentType.getViewNames(false))
117                    {
118                        View view = contentType.getView(viewName);
119                        
120                        String id = this.getId() + "." + contentTypeId + "." + viewName;
121                        
122                        Configuration conf = _getViewItemConfiguration(id, view, contentTypeId);
123                        _getGalleryItemManager().addComponent(_pluginName, null, id, StaticClientSideElement.class, conf);
124                        galleryGroup.addItem(new UnresolvedItem(id, true));
125                    }
126                }
127                
128                _galleryItems.add(galleryItem);
129            }
130            
131            if (_galleryItems.size() > 0)
132            {
133                try
134                {
135                    _getGalleryItemManager().initialize();
136                }
137                catch (Exception e)
138                {
139                    throw new ConfigurationException("Unable to lookup parameter local components", e);
140                }
141            }
142        }
143        
144        _galleryInitialized = true;
145    }
146    
147    /**
148     * Get the configuration for a view item
149     * @param itemId The item id
150     * @param view The view
151     * @param cTypeId The content type id
152     * @return The configuration
153     */
154    protected Configuration _getViewItemConfiguration (String itemId, View view, String cTypeId)
155    {
156        DefaultConfiguration conf = new DefaultConfiguration("extension");
157        conf.setAttribute("id", itemId);
158        
159        DefaultConfiguration classConf = new DefaultConfiguration("class");
160        classConf.setAttribute("name", "Ametys.ribbon.element.ui.ButtonController");
161        
162        // Label
163        DefaultConfiguration labelConf = new DefaultConfiguration("label");
164        labelConf.setValue(_i18nUtils.translate(view.getLabel()));
165        classConf.addChild(labelConf);
166        
167        // Description
168        DefaultConfiguration descConf = new DefaultConfiguration("description");
169        descConf.setValue(_i18nUtils.translate(view.getDescription()));
170        classConf.addChild(descConf);
171        
172        // Name
173        DefaultConfiguration nameConf = new DefaultConfiguration("name");
174        nameConf.setValue(view.getName());
175        classConf.addChild(nameConf);
176        
177        // Content type
178        DefaultConfiguration cTypeConf = new DefaultConfiguration("contentType");
179        cTypeConf.setValue(cTypeId);
180        classConf.addChild(cTypeConf);
181        
182        // Icons or glyph
183        if (view.getIconGlyph() != null)
184        {
185            DefaultConfiguration iconGlyphConf = new DefaultConfiguration("icon-glyph");
186            iconGlyphConf.setValue(view.getIconGlyph());
187            classConf.addChild(iconGlyphConf);
188        }
189        if (view.getIconDecorator() != null)
190        {
191            DefaultConfiguration iconDecoratorConf = new DefaultConfiguration("icon-decorator");
192            iconDecoratorConf.setValue(view.getIconDecorator());
193            classConf.addChild(iconDecoratorConf);
194        }
195        if (view.getSmallIcon() != null)
196        {
197            DefaultConfiguration iconSmallConf = new DefaultConfiguration("icon-small");
198            iconSmallConf.setValue(view.getSmallIcon());
199            classConf.addChild(iconSmallConf);
200            DefaultConfiguration iconMediumConf = new DefaultConfiguration("icon-medium");
201            iconMediumConf.setValue(view.getMediumIcon());
202            classConf.addChild(iconMediumConf);
203            DefaultConfiguration iconLargeConf = new DefaultConfiguration("icon-large");
204            iconLargeConf.setValue(view.getLargeIcon());
205            classConf.addChild(iconLargeConf);
206        }
207        
208        // Common configuration
209        @SuppressWarnings("unchecked")
210        Map<String, Object> commonConfig = (Map<String, Object>) this._script.getParameters().get("items-config");
211        for (String tagName : commonConfig.keySet())
212        {
213            DefaultConfiguration c = new DefaultConfiguration(tagName);
214            c.setValue(String.valueOf(commonConfig.get(tagName)));
215            classConf.addChild(c);
216        }
217        
218        conf.addChild(classConf);
219        return conf;
220    }
221    
222    /**
223     * Set the view of a content
224     * @param zoneItemId the id of the zone item
225     * @param viewName the name of the view to use
226      */
227    @Callable
228    public void setContentView(String zoneItemId, String viewName)
229    {
230        AmetysObject object = _resolver.resolveById(zoneItemId);
231        if (!(object instanceof ModifiableZoneItem))
232        {
233            throw new IllegalArgumentException("The provided ID '" + zoneItemId + "' does not reference a modifiable zone item.");
234        }
235        
236        ModifiableZoneItem zoneItem = (ModifiableZoneItem) object;
237        
238        if (!zoneItem.getType().equals(ZoneType.CONTENT))
239        {
240            throw new IllegalArgumentException("The zone item '" + zoneItemId + "' does not contain a content.");
241        }
242        
243        Content content = zoneItem.getContent();
244        
245        View view = _contentTypesHelper.getView(viewName, content.getTypes(), content.getMixinTypes());
246        if (view == null)
247        {
248            throw new IllegalArgumentException("The view '" + viewName + "' can't be assigned on the content '" + StringUtils.join(content.getTypes(), ",")  + "'.");
249        }
250        
251        if (getLogger().isDebugEnabled())
252        {
253            getLogger().debug("Setting view '" + viewName + "' in the content zone item '" + zoneItemId + "'.");
254        }
255        
256        // Set the view name.
257        zoneItem.setViewName(viewName);
258        
259        zoneItem.saveChanges();
260        
261        Map<String, Object> eventParams = new HashMap<>();
262        eventParams.put(ObservationConstants.ARGS_PAGE, zoneItem.getZone().getPage());
263        eventParams.put(ObservationConstants.ARGS_ZONE_ITEM_ID, zoneItemId);
264        eventParams.put(ObservationConstants.ARGS_ZONE_TYPE, ZoneType.CONTENT);
265        _observationManager.notify(new Event(ObservationConstants.EVENT_ZONEITEM_MOVED, _currentUserProvider.getUser(), eventParams));
266    }
267}