/**
*
*/
package org.richfaces.renderkit;
import java.io.IOException;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.MissingResourceException;
import java.util.ResourceBundle;
import javax.faces.component.UIComponent;
import javax.faces.component.UIViewRoot;
import javax.faces.context.FacesContext;
import javax.faces.context.ResponseWriter;
import javax.faces.convert.Converter;
import org.ajax4jsf.component.UIDataAdaptor;
import org.ajax4jsf.javascript.JSFunctionDefinition;
import org.ajax4jsf.javascript.JSReference;
import org.ajax4jsf.javascript.ScriptString;
import org.ajax4jsf.javascript.ScriptUtils;
import org.ajax4jsf.renderkit.ComponentVariables;
import org.ajax4jsf.renderkit.ComponentsVariableResolver;
import org.ajax4jsf.renderkit.RendererUtils.HTML;
import org.richfaces.component.UIOrderingBaseComponent;
import org.richfaces.component.UIOrderingBaseComponent.ItemState;
/**
* @author Nick Belaevski
*
*/
public abstract class OrderingComponentRendererBase extends AbstractRowsRenderer {
private static final Converter DEFAULT_CONVERTER = new Converter() {
public Object getAsObject(FacesContext context, UIComponent component,
String value) {
return value;
}
public String getAsString(FacesContext context, UIComponent component,
Object value) {
if (value instanceof String) {
return (String) value;
}
if (null == value) {
return "";
}
return value.toString();
}
};
private static final String ITEM_STATE_VAR_NAME = "itemState";
protected final static String SHOW_LABELS_ATTRIBUTE_NAME = "showButtonLabels";
protected final static String ATTRIBUTE_CE_ONHEADERCLICK = "onheaderclick";
protected final static String CONTROL_TYPE_LINK = "link";
protected final static String CONTROL_TYPE_BUTTON = "button";
protected final static String CONTROL_TYPE_NONE = "none";
protected final static String ATTRIBUTE_CONTROLS_TYPE = "controlsType";
protected static abstract class ControlsHelper {
private String name;
private String bundlePropertyName;
private String imageURI;
private String facetName;
private String styleClassName;
private String idSuffix;
String customEvent;
String styleFromAttribute;
private String buttonStyleClass;
boolean enable;
private String defaultText;
private String labelAttributeName;
public abstract boolean isRendered(FacesContext context, UIOrderingBaseComponent list);
public ControlsHelper(String name, String bundlePropertyName, String defaultText, String imageURI,
String facetName, String styleClassName, String styleFromAttribute, String buttonStyleClass,
String idSuffix, String customEvent, boolean isEnable, String labelAttributeName) {
super();
this.name = name;
this.bundlePropertyName = bundlePropertyName;
this.defaultText = defaultText;
this.imageURI = imageURI;
this.facetName = facetName;
this.styleClassName = styleClassName;
this.styleFromAttribute = styleFromAttribute;
this.idSuffix = idSuffix;
this.customEvent = customEvent;
this.buttonStyleClass = buttonStyleClass;
this.enable = isEnable;
this.labelAttributeName = labelAttributeName;
}
public String getName() {
return name;
}
public String getBundlePropertyName() {
return bundlePropertyName;
}
public String getImageURI() {
return imageURI;
}
public String getFacetName() {
return facetName;
}
public String getStyleClassName() {
return styleClassName;
}
public String getIdSuffix() {
return idSuffix;
}
public String getCustomEvent() {
return customEvent;
}
public String getStyleFromAttribute() {
return styleFromAttribute;
}
public String getButtonStyleClass() {
return buttonStyleClass;
}
public boolean isEnable() {
return enable;
}
public String getDefaultText() {
return defaultText;
}
public String getLabelAttributeName() {
return labelAttributeName;
}
}
protected static final class SelectionState {
private boolean firstSelected = false;
private boolean firstSelectedLatch = false;
private boolean selectedLatch = false;
private boolean itemsExist = false;
private boolean lastSelected = false;
public SelectionState() {
super();
}
public void addState(boolean selected) {
itemsExist = true;
if (!firstSelectedLatch) {
firstSelected = selected;
firstSelectedLatch = true;
}
if (selected) {
selectedLatch = true;
}
lastSelected = selected;
}
public boolean isFirstSelected() {
return firstSelected;
}
public boolean isSelected() {
return selectedLatch;
}
public boolean isItemExist() {
return itemsExist;
}
public boolean isLastSelected() {
return lastSelected;
}
}
private final String bundleName;
public OrderingComponentRendererBase(String bundleName) {
super();
this.bundleName = bundleName;
}
public void encodeCaption(FacesContext context, UIComponent component) throws IOException {
encodeCaption(context, component, OrderingComponentControlsHelper.FACET_CAPTION,
"rich-ordering-list-caption");
}
protected void encodeCaption(FacesContext context, UIComponent component,
String facetCaption, String captionStyle, String attributeName) throws IOException{
ResponseWriter writer = context.getResponseWriter();
UIComponent facetEl = component.getFacet(facetCaption);
boolean renderFacet = ((facetEl != null) && facetEl.isRendered());
String captionAttr = (String) component.getAttributes().get(attributeName);
if (renderFacet || (captionAttr != null)) {
writer.startElement(HTML.DIV_ELEM, component);
writer.writeAttribute(HTML.class_ATTRIBUTE, captionStyle, null);
if (renderFacet) {
renderChild(context, facetEl);
} else {
writer.write(captionAttr);
}
writer.endElement(HTML.DIV_ELEM);
}
}
protected void encodeCaption(FacesContext context, UIComponent component, String facetCaption, String captionStyle)
throws IOException {
encodeCaption(context, component, facetCaption, captionStyle, OrderingComponentControlsHelper.ATTRIBUTE_CAPTION_LABEL);
}
public void encodeHeader(FacesContext context, UIOrderingBaseComponent component)
throws IOException {
encodeHeader(context, component, "rich-ordering-list-table-header", "rich-ordering-list-table-header-cell", "headerClass");
}
protected void encodeHeader(FacesContext context, UIOrderingBaseComponent component, String rowClass,
String cellClass, String headerClassAttr) throws IOException {
ResponseWriter writer = context.getResponseWriter();
//UIComponent header = orderingList.getHeader();
Iterator headers = component.columns();
if (headers.hasNext()) {
writer.startElement("thead", component);
String headerClass = (String) component.getAttributes().get(headerClassAttr);
writer.startElement("tr", component);
encodeStyleClass(writer, null, rowClass, null, headerClass);
encodeHeaderFacets(context, writer, headers, cellClass, headerClass, "header", "th", component);
writer.endElement("tr");
writer.endElement("thead");
}
}
protected void renderDefaultControl(FacesContext context,
UIOrderingBaseComponent orderingList, ResponseWriter writer,
boolean useFacet, OrderingComponentRendererBase.ControlsHelper helper, String clientId, ResourceBundle bundle,
boolean enabled, String baseStyle, String baseControlStyle)
throws IOException {
UIComponent facet = orderingList.getFacet(helper.getFacetName());
String customEvent = null;
Map attributes = orderingList.getAttributes();
if (helper.customEvent != null) {
customEvent = (String) attributes.get(helper.customEvent);
}
String styleFromAttribute = (String) attributes
.get(helper.styleFromAttribute);
String baseStyleLight = baseStyle.concat("-light");
String baseStylePress = baseStyle.concat("-press");
String currentStyle = baseControlStyle + helper.getStyleClassName();
if (styleFromAttribute != null) {
currentStyle = styleFromAttribute.concat(currentStyle);
}
writer.startElement(HTML.DIV_ELEM, orderingList);
String controlId = clientId + helper.getIdSuffix();
writer.writeAttribute(HTML.id_ATTRIBUTE, controlId, null); //FIXME:
writer.writeAttribute(HTML.class_ATTRIBUTE, currentStyle, null);
String style = null;
if (enabled) {
style = "display:block;";
} else {
style = "display:none;";
}
writer.writeAttribute(HTML.style_ATTRIBUTE, style, null);
if (!useFacet) {
writer.startElement(HTML.DIV_ELEM, orderingList);
writer.writeAttribute(HTML.class_ATTRIBUTE, baseStyle + helper.getButtonStyleClass(), null);
if (helper.enable) {
writer.writeAttribute(HTML.onmouseover_ATTRIBUTE, "this.className='" + baseStyleLight + "'", null);
writer.writeAttribute(HTML.onmousedown_ATTRIBUTE, "this.className='" + baseStylePress + "'", null);
writer.writeAttribute(HTML.onmouseup_ATTRIBUTE, "this.className='" + baseStyle + "'", null);
writer.writeAttribute(HTML.onmouseout_ATTRIBUTE, "this.className='" + baseStyle + "'", null);
}
writer.startElement(HTML.a_ELEMENT, orderingList);
writer.writeAttribute(HTML.id_ATTRIBUTE, controlId + "link", null); //FIXME:
writer.writeAttribute(HTML.HREF_ATTR, "#", null);
writer.writeAttribute(HTML.onclick_ATTRIBUTE, "return false;", null);
if (!helper.enable) {
writer.writeAttribute(HTML.DISABLED_ATTR, "disabled", null);
writer.writeAttribute(HTML.class_ATTRIBUTE, baseStyle + "-a-disabled", null);
writer.startElement(HTML.a_ELEMENT, orderingList);
} else {
writer.writeAttribute(HTML.class_ATTRIBUTE, baseStyle + "-selection", null);
writer.writeAttribute(HTML.onblur_ATTRIBUTE, "Control.onblur(this);", null);
writer.writeAttribute(HTML.onfocus_ATTRIBUTE, "Control.onfocus(this);", null);
}
writer.startElement(HTML.DIV_ELEM, orderingList);
writer.writeAttribute(HTML.class_ATTRIBUTE, baseStyle + "-content", null);
}
if (customEvent != null) {
writer.writeAttribute(HTML.onclick_ATTRIBUTE, customEvent,null);
}
if (useFacet) {
renderChild(context, facet);
} else {
writer.startElement(HTML.IMG_ELEMENT, orderingList);
//buttons sometimes don't work under IE if mouse cursor
//is above some special areas of the button
writer.writeAttribute(HTML.style_ATTRIBUTE, "margin:0px;padding:0px;border:0px;", null);
writer.writeAttribute(HTML.width_ATTRIBUTE, "15", null);
writer.writeAttribute(HTML.height_ATTRIBUTE, "15", null);
writer.writeAttribute(HTML.border_ATTRIBUTE, "0", null);
writer.writeAttribute(HTML.alt_ATTRIBUTE, helper.getFacetName(),
null);
writer.writeAttribute(HTML.src_ATTRIBUTE, getResource(
helper.getImageURI()).getUri(context, null), null);
writer.endElement(HTML.IMG_ELEMENT);
if (getUtils().isBooleanAttribute(orderingList, SHOW_LABELS_ATTRIBUTE_NAME)) {
String label = (String) attributes.get(helper.getLabelAttributeName());
if (label == null && bundle != null) {
try {
label = bundle.getString(helper.getBundlePropertyName());
} catch (MissingResourceException e) {
}
}
if (label == null) {
label = helper.getDefaultText();
}
writer.writeText(label, null);
}
}
// writer.writeAttribute(HTML.id_ATTRIBUTE, clientId +
// helper.getIdSuffix(), null);
// writer.writeAttribute(HTML.class_ATTRIBUTE, currentStyle, null);
if (!useFacet) {
writer.endElement(HTML.DIV_ELEM);
if (!helper.enable) {
writer.endElement(HTML.a_ELEMENT);
}
writer.endElement(HTML.a_ELEMENT);
writer.endElement(HTML.DIV_ELEM);
}
writer.endElement(HTML.DIV_ELEM);
}
protected boolean isHeaderExists(FacesContext context, UIOrderingBaseComponent component, String facetName) {
Iterator headers = component.columns();
while (headers.hasNext()) {
UIComponent column = (UIComponent) headers.next();
UIComponent facet = column.getFacet(facetName);
if (facet != null) {
return true;
}
}
return false;
}
protected void encodeHeaderFacets(FacesContext context, ResponseWriter writer,
Iterator headers, String skinCellClass,
String headerClass, String facetName, String element, UIOrderingBaseComponent orderingList
)
throws IOException {
while (headers.hasNext()) {
UIComponent column = (UIComponent) headers.next();
String classAttribute = facetName + "Class";
String columnHeaderClass = (String) column.getAttributes().get(classAttribute);
writer.startElement(element, column);
if (!headers.hasNext()) {
skinCellClass = skinCellClass + "-last";
}
encodeStyleClass(writer, null, skinCellClass, headerClass, columnHeaderClass);
getUtils().encodeAttribute(context, column, "colspan");
writer.startElement("div", column);
writer.writeAttribute("style", "overflow:hidden;white-space: nowrap;", null);
String onHeaderClickEvent = (String) orderingList.getAttributes().get(ATTRIBUTE_CE_ONHEADERCLICK);
if (onHeaderClickEvent != null) {
writer.writeAttribute(HTML.onclick_ATTRIBUTE, onHeaderClickEvent, null);
}
UIComponent facet = column.getFacet(facetName);
if (facet != null && facet.isRendered()) {
renderChild(context, facet);
} else {
writer.write(" ");
}
writer.endElement("div");
writer.endElement(element);
}
}
protected void encodeControlFacet(FacesContext context,
UIOrderingBaseComponent orderingList, OrderingComponentRendererBase.ControlsHelper helper,
String clientId, ResponseWriter writer, boolean enabled, String baseStyle,
String baseControlStyle) throws IOException {
Locale locale = null;
UIViewRoot viewRoot = context.getViewRoot();
if (viewRoot != null) {
locale = viewRoot.getLocale();
}
ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader();
ResourceBundle bundle = null;
if (locale != null) {
try {
bundle = ResourceBundle.getBundle(bundleName, locale, contextClassLoader);
} catch (MissingResourceException e) {
}
}
Map attributes = orderingList.getAttributes();
UIComponent facet = orderingList.getFacet(helper.getFacetName());
boolean useFacet = (facet != null && facet.isRendered());
String controlType = (String) attributes.get(ATTRIBUTE_CONTROLS_TYPE);
if (CONTROL_TYPE_NONE.equals(controlType)) {
if (useFacet) {
renderChild(context, facet);
}
} else {
renderDefaultControl(context, orderingList, writer, useFacet,
helper, clientId, bundle ,enabled, baseStyle, baseControlStyle);
}
}
public void encodeBegin(FacesContext context, UIComponent component)
throws IOException {
UIOrderingBaseComponent orderingComponent = (UIOrderingBaseComponent) component;
ComponentVariables variables = ComponentsVariableResolver.getVariables(this, component);
variables.setVariable(ITEM_STATE_VAR_NAME, orderingComponent.getItemState());
super.encodeBegin(context, component);
}
protected ItemState getItemState(FacesContext context, UIComponent component, ComponentVariables variables)
throws IOException {
return (ItemState) variables.getVariable(ITEM_STATE_VAR_NAME);
}
protected Converter getConverter(FacesContext context, UIOrderingBaseComponent component) {
Converter converter = component.getConverter();
if (converter == null) {
converter = component.getConverterForValue(context);
}
if (converter == null) {
converter = DEFAULT_CONVERTER;
}
return converter;
}
public String getCaptionDisplay(FacesContext context, UIComponent component) {
Object caption = component.getAttributes().get(OrderingComponentControlsHelper.ATTRIBUTE_CAPTION_LABEL);
UIComponent facet = component.getFacet(OrderingComponentControlsHelper.FACET_CAPTION);
if ((null != caption && !"".equals(caption)) ||
(null != facet && facet.isRendered())) {
return "";
}
return "display: none;";
}
public String getAsEventHandler(FacesContext context, UIComponent component, String attributeName) {
String event = (String) component.getAttributes().get(attributeName);
ScriptString result = JSReference.NULL;
if (event != null) {
event = event.trim();
if (event.length() != 0) {
JSFunctionDefinition function = new JSFunctionDefinition();
function.addParameter("event");
function.addToBody(event);
result = function;
}
}
return ScriptUtils.toScript(result);
}
public String getColumnClassesAsJSArray(FacesContext context, UIComponent component) {
return ScriptUtils.toScript(getClassesAsList(context, component, "columnClasses"));
}
public String getRowClassesAsJSArray(FacesContext context, UIComponent component) {
return ScriptUtils.toScript(getClassesAsList(context, component, "rowClasses"));
}
protected List getClassesAsList(FacesContext context, UIComponent component, String attr) {
String value = (String) ((UIDataAdaptor) component).getAttributes().get(attr);
if (value != null && (value.length() != 0)) {
return Arrays.asList(value.split(","));
}
return null;
}
}