001/*
002 * (C) Copyright 2010-2016 Nuxeo SA (http://nuxeo.com/) and others.
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 *
016 * Contributors:
017 *     Nuxeo - initial API and implementation
018 */
019package org.nuxeo.ecm.localconf;
020
021import static org.jboss.seam.ScopeType.CONVERSATION;
022import static org.nuxeo.ecm.platform.types.localconfiguration.UITypesConfigurationConstants.UI_TYPES_CONFIGURATION_FACET;
023import static org.nuxeo.ecm.platform.types.localconfiguration.UITypesConfigurationConstants.UI_TYPES_DEFAULT_NEEDED_SCHEMA;
024
025import java.io.Serializable;
026import java.util.ArrayList;
027import java.util.Collections;
028import java.util.Comparator;
029import java.util.Iterator;
030import java.util.List;
031import java.util.Map;
032
033import org.apache.commons.logging.Log;
034import org.apache.commons.logging.LogFactory;
035import org.jboss.seam.annotations.In;
036import org.jboss.seam.annotations.Install;
037import org.jboss.seam.annotations.Name;
038import org.jboss.seam.annotations.Scope;
039import org.nuxeo.ecm.core.api.CoreSession;
040import org.nuxeo.ecm.core.api.DocumentModel;
041import org.nuxeo.ecm.core.api.DocumentRef;
042import org.nuxeo.ecm.core.api.security.SecurityConstants;
043import org.nuxeo.ecm.core.schema.DocumentType;
044import org.nuxeo.ecm.core.schema.SchemaManager;
045import org.nuxeo.ecm.platform.types.Type;
046import org.nuxeo.ecm.platform.types.TypeManager;
047import org.nuxeo.ecm.platform.types.localconfiguration.UITypesConfiguration;
048import org.nuxeo.ecm.platform.ui.web.api.NavigationContext;
049import org.nuxeo.runtime.api.Framework;
050
051/**
052 * @author <a href="mailto:troger@nuxeo.com">Thomas Roger</a>
053 */
054@Name("typesConfigurationActions")
055@Scope(CONVERSATION)
056@Install(precedence = Install.FRAMEWORK)
057public class UITypesConfigurationActions implements Serializable {
058
059    private static final long serialVersionUID = 1L;
060
061    @In(create = true)
062    protected Map<String, String> messages;
063
064    /**
065     * @since 5.9.1
066     */
067    protected static class TypeLabelAlphabeticalOrder implements Comparator<Type> {
068
069        private static final Log log = LogFactory.getLog(TypeLabelAlphabeticalOrder.class);
070
071        private final Map<String, String> messages;
072
073        public TypeLabelAlphabeticalOrder(Map<String, String> messages) {
074            super();
075            this.messages = messages;
076        }
077
078        @Override
079        public int compare(Type type1, Type type2) {
080            return getTranslatedLabel(type1).compareTo(getTranslatedLabel(type2));
081        }
082
083        protected String getTranslatedLabel(Type type) {
084            String label = type.getLabel();
085            if (label == null) {
086                String typeId = type.getId();
087                log.error(String.format("No label for the %s type, using its id instead.", typeId));
088                return typeId;
089            }
090            String translatedLabel = messages.get(label);
091            if (translatedLabel == null) {
092                return label;
093            }
094            return translatedLabel;
095        }
096    }
097
098    @In(create = true)
099    protected transient TypeManager typeManager;
100
101    @In(create = true)
102    protected transient NavigationContext navigationContext;
103
104    @In(create = true, required = false)
105    protected transient CoreSession documentManager;
106
107    protected transient SchemaManager schemaManager;
108
109    public List<Type> getNotSelectedTypes() {
110        DocumentModel currentDoc = navigationContext.getCurrentDocument();
111        return getNotSelectedTypes(currentDoc);
112    }
113
114    /**
115     * Returns a List of type not selected for the domain given as parameter
116     *
117     * @param document the domain to configure
118     * @return a List of type of document, not currently selected for the domain
119     * @since 5.5
120     */
121    public List<Type> getNotSelectedTypes(DocumentModel document) {
122        if (!document.hasFacet(UI_TYPES_CONFIGURATION_FACET)) {
123            return Collections.emptyList();
124        }
125
126        List<String> allowedTypes = getAllowedTypes(document);
127
128        List<Type> notSelectedTypes = new ArrayList<>(typeManager.findAllAllowedSubTypesFrom(document.getType()));
129
130        for (Iterator<Type> it = notSelectedTypes.iterator(); it.hasNext();) {
131            Type type = it.next();
132            if (allowedTypes.contains(type.getId())) {
133                it.remove();
134            }
135        }
136
137        Collections.sort(notSelectedTypes, new TypeLabelAlphabeticalOrder(messages));
138
139        return notSelectedTypes;
140    }
141
142    protected List<String> getAllowedTypes(DocumentModel doc) {
143        UITypesConfiguration uiTypesConfiguration = doc.getAdapter(UITypesConfiguration.class);
144        if (uiTypesConfiguration == null) {
145            return Collections.emptyList();
146        }
147        List<String> allowedTypes = new ArrayList<>(uiTypesConfiguration.getAllowedTypes());
148        if (allowedTypes.isEmpty()) {
149            allowedTypes = computeAllowedTypes(doc);
150        }
151        return allowedTypes;
152    }
153
154    public List<Type> getSelectedTypes() {
155        DocumentModel currentDoc = navigationContext.getCurrentDocument();
156        return getSelectedTypes(currentDoc);
157    }
158
159    /**
160     * Returns a List of type selected for the domain given as parameter
161     *
162     * @param document the domain to configure
163     * @return List of documen type selected for the domain
164     * @since 5.5
165     */
166    public List<Type> getSelectedTypes(DocumentModel document) {
167        if (!document.hasFacet(UI_TYPES_CONFIGURATION_FACET)) {
168            return Collections.emptyList();
169        }
170
171        List<String> allowedTypes = getAllowedTypes(document);
172
173        List<Type> selectedTypes = new ArrayList<>();
174        for (String type : allowedTypes) {
175            Type existingType = typeManager.getType(type);
176            if (existingType != null) {
177                selectedTypes.add(existingType);
178            }
179        }
180
181        Collections.sort(selectedTypes, new TypeLabelAlphabeticalOrder(messages));
182        return selectedTypes;
183    }
184
185    protected List<String> computeAllowedTypes(DocumentModel currentDoc) {
186        List<String> types = new ArrayList<>();
187
188        DocumentModel parent = documentManager.getRootDocument();
189
190        DocumentRef parentRef = currentDoc.getParentRef();
191        if (parentRef != null && documentManager.hasPermission(parentRef, SecurityConstants.READ)) {
192            parent = documentManager.getDocument(parentRef);
193        }
194
195        for (Type type : typeManager.findAllAllowedSubTypesFrom(currentDoc.getType(), parent)) {
196            types.add(type.getId());
197        }
198
199        return types;
200    }
201
202    public List<Type> getTypesWithSchemaFile() {
203        DocumentModel document = navigationContext.getCurrentDocument();
204        return getTypesWithSchemaFile(document);
205    }
206
207    /**
208     * Returns a List of Document Types associated with Schema file for the domain given as parameter, if they're
209     * allowed for it.
210     *
211     * @param document the domain
212     * @return List of Document types which have assoctiated Schema files.
213     * @Since 5.5
214     */
215    public List<Type> getTypesWithSchemaFile(DocumentModel document) {
216        List<Type> types = new ArrayList<>();
217        for (String type : getAllowedTypes(document)) {
218            DocumentType documentType = getSchemaManager().getDocumentType(type);
219            if (documentType != null && documentType.hasSchema(UI_TYPES_DEFAULT_NEEDED_SCHEMA)) {
220                types.add(typeManager.getType(type));
221            }
222        }
223        Collections.sort(types, new TypeLabelAlphabeticalOrder(messages));
224        return Collections.unmodifiableList(types);
225    }
226
227    protected SchemaManager getSchemaManager() {
228        if (schemaManager == null) {
229            schemaManager = Framework.getService(SchemaManager.class);
230        }
231        return schemaManager;
232    }
233
234}