/*
* (C) Copyright 2006-2007 Nuxeo SAS (http://nuxeo.com/) and contributors.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the GNU Lesser General Public License
* (LGPL) version 2.1 which accompanies this distribution, and is available at
* http://www.gnu.org/licenses/lgpl.html
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* Contributors:
* Nuxeo - initial API and implementation
*
* $Id: JOOoConvertPluginImpl.java 18651 2007-05-13 20:28:53Z sfermigier $
*/
package org.nuxeo.ecm.webapp.action;
import static org.jboss.seam.ScopeType.CONVERSATION;
import static org.jboss.seam.ScopeType.EVENT;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.jboss.seam.annotations.Factory;
import org.jboss.seam.annotations.In;
import org.jboss.seam.annotations.Install;
import org.jboss.seam.annotations.Name;
import org.jboss.seam.annotations.Observer;
import org.jboss.seam.annotations.Scope;
import org.jboss.seam.annotations.intercept.BypassInterceptors;
import org.nuxeo.ecm.core.api.DocumentModel;
import org.nuxeo.ecm.platform.types.Type;
import org.nuxeo.ecm.platform.types.TypeManager;
import org.nuxeo.ecm.platform.ui.web.api.NavigationContext;
import org.nuxeo.ecm.webapp.helpers.EventNames;
import org.nuxeo.ecm.webapp.seam.NuxeoSeamHotReloader;
/**
* Document type service for document type creation.
*
* @author eionica@nuxeo.com
* @author <a href="mailto:at@nuxeo.com">Anahide Tchertchian</a>
*/
@Name("typesTool")
@Scope(CONVERSATION)
@Install(precedence = Install.FRAMEWORK)
public class TypesTool implements Serializable {
private static final long serialVersionUID = -5037578301250616973L;
protected static final Log log = LogFactory.getLog(TypesTool.class);
private static final int COLUMN_SIZE = 4;
@In(create = true)
protected transient TypeManager typeManager;
@In(create = true)
protected NuxeoSeamHotReloader seamReload;
protected Map<String, List<List<Type>>> typesMap;
protected Long typesMapTimestamp;
protected Type selectedType;
@In(create = true)
protected transient NavigationContext navigationContext;
@Observer(value = { EventNames.CONTENT_ROOT_SELECTION_CHANGED,
EventNames.DOCUMENT_SELECTION_CHANGED,
EventNames.DOMAIN_SELECTION_CHANGED,
EventNames.LOCAL_CONFIGURATION_CHANGED }, create = false)
@BypassInterceptors
public void resetTypesList() {
typesMap = null;
typesMapTimestamp = null;
}
/**
* Retrieves the list of allowed sub types given a current type.
* <p>
* This is used at creation time. Current type is retrieved thanks to the
* document model hold and passed by the event.
*/
public void populateTypesList() {
boolean set = false;
DocumentModel model = getCurrentItem();
if (model != null) {
typesMap = getOrganizedTypeMapForDocumentType(model.getType());
set = true;
}
if (!set) {
// set an empty list
typesMap = new HashMap<String, List<List<Type>>>();
}
typesMapTimestamp = typeManager.getLastModified();
}
public Map<String, List<List<Type>>> getOrganizedTypeMapForDocumentType(
String type) {
Map<String, List<Type>> docTypesMap = typeManager.getTypeMapForDocumentType(
type, getConfigurationDocument());
docTypesMap = filterTypeMap(docTypesMap);
return organizeType(docTypesMap);
}
/**
* Returns the Configuration document to be used as the local configuration
* of the {@code TypeManager}.
* <p>
* This method can be overridden by Subclasses to define a specific
* Configuration document.
*
* @since 5.4.2
*/
protected DocumentModel getConfigurationDocument() {
return navigationContext.getCurrentDocument();
}
/**
* Method to be overridden by subclasses to filter the type Map.
*
* @since 5.4.2
*/
protected Map<String, List<Type>> filterTypeMap(
Map<String, List<Type>> docTypeMap) {
return docTypeMap;
}
/**
* Split each @{code List} of {@code Type} in one or more new {@code List},
* with maximum 4 {@code Type}s in each new {@code List} and returns the
* new computed {@code Map}.
*/
protected Map<String, List<List<Type>>> organizeType(
Map<String, List<Type>> types) {
Map<String, List<List<Type>>> newTypesMap = new HashMap<String, List<List<Type>>>();
Set<Entry<String, List<Type>>> typeEntrySet = types.entrySet();
for (Entry<String, List<Type>> set : typeEntrySet) {
List<Type> typeList = set.getValue();
List<List<Type>> newList = new ArrayList<List<Type>>();
int index = 0;
newList.add(index, new ArrayList<Type>());
for (Type type : typeList) {
List<Type> currentList = newList.get(index);
if (currentList == null) {
currentList = new ArrayList<Type>();
newList.add(index, currentList);
}
currentList.add(type);
if (currentList.size() % COLUMN_SIZE == 0) {
index++;
newList.add(index, new ArrayList<Type>());
}
}
newTypesMap.put(set.getKey(), newList);
}
return newTypesMap;
}
public Type getSelectedType() {
if (selectedType != null) {
log.debug("Returning selected type with id: "
+ selectedType.getId());
}
return selectedType;
}
/**
* If the selected type is supposed to be automatically injected by Seam
* through @DataModelSelection callback (i.e. the user will select the type
* from a list), this method should be called with <code>null</code>
* parameter before.
*/
public void setSelectedType(Type type) {
if (typesMap == null) {
populateTypesList();
}
selectedType = type;
}
@Factory(value = "typesMap", scope = EVENT)
public Map<String, List<List<Type>>> getTypesList() {
// XXX : should cache per currentDocument type
if (typesMap == null
|| (seamReload.isDevModeSet() && seamReload.shouldResetCache(
typeManager, typesMapTimestamp))) {
// cache the list of allowed subtypes
populateTypesList();
}
selectedType = null;
return typesMap;
}
public void setTypesList(Map<String, List<List<Type>>> typesList) {
this.typesMap = typesList;
}
public Type getType(String typeName) {
return typeManager.getType(typeName);
}
public boolean hasType(String typeName) {
return typeManager.hasType(typeName);
}
protected DocumentModel getCurrentItem() {
return navigationContext.getCurrentDocument();
}
}