package com.idega.presentation.filter; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.text.Collator; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.Comparator; import java.util.List; import java.util.Locale; import java.util.logging.Level; import javax.ejb.FinderException; import javax.faces.component.UIComponentBase; import com.idega.data.IDOEntity; import com.idega.data.IDOHome; import com.idega.data.IDOLookup; import com.idega.data.IDOLookupException; import com.idega.presentation.IWContext; import com.idega.presentation.Layer; import com.idega.presentation.PresentationObjectContainer; import com.idega.presentation.Span; import com.idega.presentation.text.Heading3; import com.idega.presentation.text.Text; import com.idega.presentation.ui.CheckBox; import com.idega.presentation.ui.InterfaceObject; import com.idega.util.ArrayUtil; import com.idega.util.CoreConstants; import com.idega.util.ListUtil; import com.idega.util.PresentationUtil; import com.idega.util.StringUtil; /** * * <p>Universal selector for {@link IDOEntity} classes. Displays * {@link CheckBox}es, which possible to select and selected ones. * After changing one of {@link CheckBox} result will be saved to * {@link FilterList#getSelectedEntities()} method. You can read selected * entities from there.</p> * <p>You can report about problems to: * <a href="mailto:martynas@idega.is">Martynas Stakė</a></p> * @param <T> * * @version 1.0.0 Mar 6, 2013 * @author <a href="mailto:martynas@idega.is">Martynas Stakė</a> */ public abstract class FilterList<T extends IDOEntity> extends InterfaceObject { private List<T> selectedEntities = null; private List<T> entities = null; private String parameterName = null; protected PresentationObjectContainer getCell(){ Span span = new Span(); span.setStyleClass(getEntityCellClass()); return span; } protected Collection<UIComponentBase> getEntityFields(T entity){ ArrayList<UIComponentBase> components = new ArrayList<UIComponentBase>(); String name = getRepresentation(entity); PresentationObjectContainer spanName = getCell(); spanName.add(new Text(name)); components.add(spanName); return components; } protected String getRepresentation(T entity){ return getRepresentation(entity, getRepresentationMethodName()); } protected String getEntityCellClass(){ return "filtered-span"; } @Override public void main(IWContext iwc) throws Exception { PresentationUtil.addStyleSheetToHeader(iwc, getBundle(iwc).getVirtualPathWithFileNameString("style/filter.css")); Layer container = new Layer(); container.setStyleClass("filterListStyle"); add(container); List<T> entities = getEntities(); if (ListUtil.isEmpty(entities)) { container.add( new Heading3(getResourceBundle(iwc).getLocalizedString( "filter.nothing_found", "Nothing found" ) )); return; } Comparator<T> comparator = new Entitycomparator(this, iwc.getCurrentLocale()); Collections.sort(entities, comparator); for (T entity: entities) { Layer entityEntry = new Layer(); container.add(entityEntry); String id = entity.getPrimaryKey().toString(); PresentationObjectContainer checkBoxSpan = getCell(); entityEntry.add(checkBoxSpan); checkBoxSpan.add(getCheckBox(iwc, id)); Collection<UIComponentBase> elements = getEntityFields(entity); for(UIComponentBase element : elements){ entityEntry.add(element); } } Layer script = new Layer(); add(script); StringBuilder js = new StringBuilder("<script>jQuery(document).ready(function(){") .append("\tjQuery('#").append(container.getId()).append("').children().each(function(){") .append("\n\t\tvar element = jQuery(this);") .append("\n\t\tvar top = jQuery('<span class=\"action-layer\"/>');") .append("\n\t\telement.append(top);") .append("\n\t\ttop.click(function(){") .append("\n\t\t\tvar checkBox = jQuery(this).parent().find('input[type=\"checkbox\"]');") .append("\n\t\t\tcheckBox.prop('checked', !checkBox.is(':checked'));") .append("\n\t\t});") .append("\n\t});") .append("\n});</script>"); script.add(js.toString()); return; } protected CheckBox getCheckBox(IWContext iwc, String id) { if (StringUtil.isEmpty(id) || iwc == null) { return null; } String checkBoxName = getParameterName(); String value = id; CheckBox select = new CheckBox(checkBoxName, value); select.setChecked(getSelectedEntity(id) != null); return select; } /** * * <p>Takes name of {@link IDOEntity} from given method.</p> * @param entity to take name from, not <code>null</code>; * @param representationMethodName of entity, which should be used to * represent entity, not <code>null</code>. * @return representation of {@link IDOEntity} of * {@link CoreConstants#MINUS} if something failed. * @author <a href="mailto:martynas@idega.com">Martynas Stakė</a> */ public String getRepresentation(T entity, String representationMethodName) { if (entity == null || StringUtil.isEmpty(representationMethodName)) { return CoreConstants.MINUS; } Method[] methods = entity.getClass().getMethods(); if (ArrayUtil.isEmpty(methods)) { return CoreConstants.MINUS; } Method requiredMethod = null; for (Method method : methods) { if (representationMethodName.equals(method.getName())) { requiredMethod = method; } } if (!String.class.equals(requiredMethod.getReturnType())) { return CoreConstants.MINUS; } try { return (String) requiredMethod.invoke(entity); } catch (IllegalArgumentException e) { getLogger().log(Level.WARNING, "Wrong arguments passed to " + entity.getClass().getName() + "." + requiredMethod.getName()); } catch (IllegalAccessException e) { getLogger().log(Level.WARNING, "Method " + entity.getClass().getName() + "." + requiredMethod.getName() + " is not visible in this context"); } catch (InvocationTargetException e) { getLogger().log(Level.WARNING, "Failed to invoke " + entity.getClass().getName() + "." + requiredMethod.getName(), e); } return CoreConstants.MINUS; } @Override public String getBundleIdentifier() { return CoreConstants.CORE_IW_BUNDLE_IDENTIFIER; } /** * * <p>Contains {@link Class} instance of representable entity.</p> * @return class name of something, which extends {@link IDOEntity}. * @author <a href="mailto:martynas@idega.com">Martynas Stakė</a> */ public abstract Class<T> getRepresentableClass(); /** * * @return method name, like: "getName", which contains name of * given {@link IDOEntity} instance. * @author <a href="mailto:martynas@idega.com">Martynas Stakė</a> */ public abstract String getRepresentationMethodName(); /** * * @return {@link IDOEntity}s, which shouldbe marked as selected; * @author <a href="mailto:martynas@idega.com">Martynas Stakė</a> */ public List<T> getSelectedEntities() { return selectedEntities; } public ArrayList<String> getSelectedEntitiesIDs() { if (ListUtil.isEmpty(getSelectedEntities())) { return null; } ArrayList<String> ids = new ArrayList<String>(getSelectedEntities().size()); for (T entity : getSelectedEntities()) { ids.add(entity.getPrimaryKey().toString()); } return ids; } /** * * <p>Searches for specified {@link IDOEntity} in * {@link FilterList#getSelectedEntities()}.</p> * @param entityID to search for, not <code>null</code>; * @return selected {@link IDOEntity} or <code>null</code> if not found. * @author <a href="mailto:martynas@idega.com">Martynas Stakė</a> */ public T getSelectedEntity(String entityID) { if (StringUtil.isEmpty(entityID)) { return null; } if (ListUtil.isEmpty(getSelectedEntities())) { return null; } for (T entity : getSelectedEntities()) { if (entityID.equals(entity.getPrimaryKey().toString())) { return entity; } } return null; } /** * * <p>Appends {@link FilterList#getSelectedEntities()} list if given * {@link IDOEntity} is not in list.</p> * @param entityID to append, not <code>null</code>; * @return <code>true</code> if appended, <code>false</code> otherwise. * @author <a href="mailto:martynas@idega.com">Martynas Stakė</a> */ public boolean addSelectedEntity(String entityID) { if (StringUtil.isEmpty(entityID)) { return Boolean.FALSE; } return addSelectedEntity(getEntity(entityID)); } /** * * <p>Appends {@link FilterList#getSelectedEntities()} list if given * {@link IDOEntity} is not in list.</p> * @param entity to append, not <code>null</code>; * @return <code>true</code> if appended, <code>false</code> otherwise. * @author <a href="mailto:martynas@idega.com">Martynas Stakė</a> */ public boolean addSelectedEntity(T entity) { if (getSelectedEntities() == null) { setSelectedEntities(new ArrayList<T>(1)); } if (getSelectedEntity(entity.getPrimaryKey().toString()) != null) { return Boolean.FALSE; } return getSelectedEntities().add(entity); } /** * * <p>Removes {@link IDOEntity} from {@link FilterList#getSelectedEntities()} * list if found.</p> * @param entity to remove, not <code>null</code>; * @return <code>true</code> when removed, <code>false</code> otherwise. * @author <a href="mailto:martynas@idega.com">Martynas Stakė</a> */ public boolean removeSelectedEntity(IDOEntity entity) { if (entity == null) { return Boolean.FALSE; } return getSelectedEntities().remove(entity); } /** * * <p>Removes {@link IDOEntity} from {@link FilterList#getSelectedEntities()} * list if found.</p> * @param entityID of entity to remove, not <code>null</code>; * @return <code>true</code> when removed, <code>false</code> otherwise. * @author <a href="mailto:martynas@idega.com">Martynas Stakė</a> */ public boolean removeSelectedEntity(String entityID) { if (StringUtil.isEmpty(entityID)) { return Boolean.FALSE; } return removeSelectedEntity(getSelectedEntity(entityID)); } public void setSelectedEntities(List<T> selectedEntities) { if (!ListUtil.isEmpty(selectedEntities)) { this.selectedEntities = new ArrayList<T>(); for (T entity : selectedEntities) { this.selectedEntities.add(entity); } } } public void setSelectedEntitiesByIDs(List<String> selectedEntitiesIDs) { setSelectedEntities(getEntities(selectedEntitiesIDs)); } /** * * @return full list of {@link IDOEntity}s to select from. * @author <a href="mailto:martynas@idega.com">Martynas Stakė</a> */ public List<T> getEntities() { return entities; } /** * * @param id of entity selected or ready to select, not <code>null</code>; * @return entity if exists, <code>null</code> otherwise; * @author <a href="mailto:martynas@idega.com">Martynas Stakė</a> */ protected T getEntity(String id) { if (StringUtil.isEmpty(id)) { return null; } try { return getEntityHome().findByPrimaryKeyIDO(id); } catch (FinderException e) { getLogger().log(Level.WARNING, "Unable to find entity by ID: " + id); } return null; } /** * * @param ids of entities to get, not empty; * @return specified entities from full list of selection, <code>null</code> * on failure. * @author <a href="mailto:martynas@idega.com">Martynas Stakė</a> */ protected List<T> getEntities(List<String> ids) { if (ListUtil.isEmpty(ids)) { return null; } List<T> entities = new ArrayList<T>(); for (String id : ids) { T entity = getEntity(id); if (entity == null) { continue; } entities.add(entity); } return entities; } public void setEntities(List<T> entities) { if (!ListUtil.isEmpty(entities)) { this.entities = new ArrayList<T>(); for (T entity : entities) { this.entities.add(entity); } } } public void setEntitiesByIDs(List<String> ids) { setEntities(getEntities(ids)); } private IDOHome entityHome = null; protected IDOHome getEntityHome() { if (this.entityHome != null) { return this.entityHome; } try { this.entityHome = IDOLookup.getHome(getRepresentableClass()); } catch (IDOLookupException e) { getLogger().log(Level.WARNING, "Unable to get home for " + getRepresentableClass()); } return this.entityHome; } public String getParameterName() { return parameterName; } public void setParameterName(String parameterName) { this.parameterName = parameterName; } private class Entitycomparator implements Comparator<T>{ private FilterList<T> component = null; private Collator collator = null; public Entitycomparator(FilterList<T> component,Locale locale){ this.component = component; this.collator = Collator.getInstance(locale); } @Override public int compare(T en1, T en2) { String name1 = component.getRepresentation(en1).toUpperCase(); String name2 = component.getRepresentation(en2).toUpperCase(); //ascending order return collator.compare(name1, name2); } }; }