/* * Copyright (c) 2005-2016 Vincent Vandenschrick. All rights reserved. * * This file is part of the Jspresso framework. * * Jspresso is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * Jspresso 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. * * You should have received a copy of the GNU Lesser General Public License * along with Jspresso. If not, see <http://www.gnu.org/licenses/>. */ package org.jspresso.framework.application.model; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.List; import org.jspresso.framework.application.backend.IBackendController; import org.jspresso.framework.application.model.descriptor.BeanCollectionModuleDescriptor; import org.jspresso.framework.model.descriptor.ICollectionDescriptorProvider; import org.jspresso.framework.model.descriptor.IComponentDescriptor; import org.jspresso.framework.util.gui.Icon; import org.jspresso.framework.util.lang.ObjectUtils; import org.jspresso.framework.view.action.ActionList; import org.jspresso.framework.view.action.ActionMap; import org.jspresso.framework.view.descriptor.ICollectionViewDescriptor; import org.jspresso.framework.view.descriptor.IViewDescriptor; import org.jspresso.framework.view.descriptor.basic.BasicBorderViewDescriptor; import org.jspresso.framework.view.descriptor.basic.BasicCollectionViewDescriptor; import org.jspresso.framework.view.descriptor.basic.BasicTabViewDescriptor; import org.jspresso.framework.view.descriptor.basic.BasicViewDescriptor; /** * This type of module keeps a reference on a beans collection. There is no * assumption made on whether these beans are actually persistent entities or any * other type of java beans. * <p/> * Simple bean collection modules must have their collection of referenced beans * initialized somehow. There is no standard built-in action to do so, since it * is highly dependent on what's needed. So it's rather common to have the * module content initialized through a startup action depending on the session * state. * * @author Vincent Vandenschrick */ public class BeanCollectionModule extends Module { /** * {@code MODULE_OBJECTS} is "moduleObjects". */ public static final String MODULE_OBJECTS = "moduleObjects"; private IComponentDescriptor<Object> elementComponentDescriptor; private IViewDescriptor elementViewDescriptor; private List<?> moduleObjects; private boolean detailViewIncluded; private ActionList navigateModuleObjectsActionList; /** * Instantiates a new Bean collection module. */ public BeanCollectionModule() { detailViewIncluded = false; } /** * Adds an element to the module's projected object collection at the * specified index. If the index is out of the list bounds, the element is * simply added at the end of the list. * * @param index * the index to add the events element at. * @param element * the element to add. */ public void addToModuleObjects(int index, Object element) { List<Object> newModuleObjects; if (getModuleObjects() != null) { newModuleObjects = new ArrayList<>(getModuleObjects()); } else { newModuleObjects = new ArrayList<>(); } if (index < 0) { newModuleObjects.add(0, element); } else if (index >= newModuleObjects.size()) { newModuleObjects.add(element); } else { newModuleObjects.add(index, element); } setModuleObjects(newModuleObjects); } /** * Adds an element to the module's projected object collection. * * @param element * the element to add. */ public void addToModuleObjects(Object element) { List<Object> newModuleObjects; if (getModuleObjects() != null) { newModuleObjects = new ArrayList<>(getModuleObjects()); } else { newModuleObjects = new ArrayList<>(); } newModuleObjects.add(element); setModuleObjects(newModuleObjects); } /** * Gets the elementComponentDescriptor. * * @return the elementComponentDescriptor. */ public IComponentDescriptor<?> getElementComponentDescriptor() { if (elementComponentDescriptor == null) { if (getProjectedViewDescriptor() instanceof ICollectionViewDescriptor && getProjectedViewDescriptor().getModelDescriptor() != null) { return ((ICollectionDescriptorProvider<?>) getProjectedViewDescriptor().getModelDescriptor()) .getCollectionDescriptor().getElementDescriptor(); } } return elementComponentDescriptor; } /** * Gets the elementViewDescriptor. * * @return the elementViewDescriptor. */ public IViewDescriptor getElementViewDescriptor() { return elementViewDescriptor; } /** * {@inheritDoc} * * @return the granted roles */ @Override public Collection<String> getGrantedRoles() { Collection<String> grantedRoles = super.getGrantedRoles(); if (grantedRoles == null && elementViewDescriptor != null) { grantedRoles = elementViewDescriptor.getGrantedRoles(); } if (grantedRoles == null && elementComponentDescriptor != null) { grantedRoles = elementComponentDescriptor.getGrantedRoles(); } return grantedRoles; } /** * {@inheritDoc} * * @return the icon */ @Override public Icon getIcon() { Icon icon = super.getIcon(); if (icon == null) { icon = getElementComponentDescriptor().getIcon(); setIcon(icon); } return icon; } /** * Gets the module's projected objects. * * @return the projected objects. */ public List<?> getModuleObjects() { return moduleObjects; } /** * {@inheritDoc} * * @return the view descriptor */ @Override public IViewDescriptor getViewDescriptor() { IViewDescriptor projectedViewDescriptor = getProjectedViewDescriptor(); IViewDescriptor moduleObjectsView = BasicCollectionViewDescriptor.extractMainCollectionView( projectedViewDescriptor); BeanCollectionModuleDescriptor moduleDescriptor = getDescriptor(); ((BasicViewDescriptor) moduleObjectsView).setModelDescriptor( moduleDescriptor.getPropertyDescriptor(BeanCollectionModule.MODULE_OBJECTS)); BasicBorderViewDescriptor moduleViewDescriptor = new BasicBorderViewDescriptor(); if (isDetailViewIncluded()) { BasicTabViewDescriptor wrapperTabViewDescriptor = new BasicTabViewDescriptor(); wrapperTabViewDescriptor.setCascadingModels(true); BasicViewDescriptor elementViewDescriptor = (BasicViewDescriptor) getElementViewDescriptor(); if (getNavigateModuleObjectsActionList() != null) { ActionMap elementViewActionMap = elementViewDescriptor.getActionMap(); elementViewDescriptor = elementViewDescriptor.clone(); ActionMap actionMapWithNavigation = new ActionMap(); if (elementViewActionMap != null) { actionMapWithNavigation.setParentActionMaps(Arrays.asList(elementViewActionMap)); } actionMapWithNavigation.setActionLists(Arrays.asList(getNavigateModuleObjectsActionList())); elementViewDescriptor.setActionMap(actionMapWithNavigation); } List<IViewDescriptor> tabs = new ArrayList<>(); tabs.add(moduleObjectsView); tabs.add(elementViewDescriptor); wrapperTabViewDescriptor.setTabs(tabs); moduleViewDescriptor.setCenterViewDescriptor(wrapperTabViewDescriptor); } else { moduleViewDescriptor.setCenterViewDescriptor(projectedViewDescriptor); } moduleViewDescriptor.setModelDescriptor(moduleDescriptor); return moduleViewDescriptor; } /** * Removes an element from the the module's projected object collection. * * @param element * the element to remove. */ public void removeFromModuleObjects(Object element) { if (getModuleObjects() != null) { List<Object> newModuleObjects; newModuleObjects = new ArrayList<>(getModuleObjects()); newModuleObjects.remove(element); setModuleObjects(newModuleObjects); } } /** * Configures the type of bean element this collection module manages. A bunch * of default values are inferred from this element component descriptor. For * instance, paging size (if used) will default to the component one unless * explicitly set. Same goes for icon image URL, default ordering properties * or even granted roles. The latter means that bean collection modules based * on forbidden entities will automatically be excluded from the workspace of * the logged-in user. * <p/> * if not explicitly configured, the element component descriptor can be * inferred from the collection view descriptor configured as projected view * descriptor. * * @param elementComponentDescriptor * the elementComponentDescriptor to set. */ public void setElementComponentDescriptor(IComponentDescriptor<Object> elementComponentDescriptor) { this.elementComponentDescriptor = elementComponentDescriptor; } /** * This property is not used by the module itself, but by built-in actions * that maybe registered on this module. One of these actions is * {@code AddBeanAsSubModuleAction}. * <p/> * This property indicates the view to use whenever the user requests a * "form-like" view on a collection element. Naturally the * configured element view descriptor must be backed by a model matching the * type of the module managed beans. * * @param elementViewDescriptor * the elementViewDescriptor to set. */ public void setElementViewDescriptor(IViewDescriptor elementViewDescriptor) { this.elementViewDescriptor = elementViewDescriptor; } /** * Assigns the list of beans this module manages. The projected view will * automatically reflect this change since a "moduleObjects" * property change will be fired. * * @param moduleObjects * the projected object collection. */ public void setModuleObjects(List<?> moduleObjects) { if (ObjectUtils.equals(this.moduleObjects, moduleObjects)) { return; } Object oldValue = getModuleObjects(); this.moduleObjects = moduleObjects; firePropertyChange(MODULE_OBJECTS, oldValue, getModuleObjects()); } /** * Gets the module descriptor. * * @return the module descriptor. */ protected BeanCollectionModuleDescriptor getDescriptor() { return new BeanCollectionModuleDescriptor(getElementComponentDescriptor()); } /** * {@inheritDoc} * * @return the bean collection module */ @Override public BeanCollectionModule clone() { BeanCollectionModule clone = (BeanCollectionModule) super.clone(); clone.moduleObjects = null; return clone; } /** * {@inheritDoc} * * @param backendController * the backend controller * @return the boolean */ @Override protected boolean isLocallyDirty(IBackendController backendController) { boolean locallyDirty = backendController.isAnyDirtyInDepth(getModuleObjects()); return locallyDirty; } /** * Is sub module sticky. Never consider a bean module sticky if it holds a component that is a detail of the * collection module. * * @param subModule * the sub module * @return the boolean */ @Override public boolean isSubModuleSticky(Module subModule) { if (!isStarted()) { if (subModule instanceof BeanModule) { IComponentDescriptor<?> subModuleComponentDescriptor = ((BeanModule) subModule).getComponentDescriptor(); IComponentDescriptor<?> elementComponentDescriptor = getElementComponentDescriptor(); if (subModuleComponentDescriptor != null && elementComponentDescriptor != null && subModuleComponentDescriptor .getComponentContract().isAssignableFrom(elementComponentDescriptor.getComponentContract())) { return false; } } } return super.isSubModuleSticky(subModule); } /** * Is detail view included boolean. * * @return the boolean */ protected boolean isDetailViewIncluded() { return detailViewIncluded; } /** * This property allows to automatically include the detail view in a tab of the main collection module * view. A complementary action list is installed to navigate between module objects. Default value is false. * * * @param detailViewIncluded * the detail view included */ public void setDetailViewIncluded(boolean detailViewIncluded) { this.detailViewIncluded = detailViewIncluded; } /** * Gets navigate module objects action list. * * @return the navigate module objects action list */ protected ActionList getNavigateModuleObjectsActionList() { return navigateModuleObjectsActionList; } /** * Sets navigate module objects action list. * * @param navigateModuleObjectsActionList * the navigate module objects action list */ public void setNavigateModuleObjectsActionList(ActionList navigateModuleObjectsActionList) { this.navigateModuleObjectsActionList = navigateModuleObjectsActionList; } }