/**
* Copyright (c) 2009--2012 Red Hat, Inc.
*
* This software is licensed to you under the GNU General Public License,
* version 2 (GPLv2). There is NO WARRANTY for this software, express or
* implied, including the implied warranties of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. You should have received a copy of GPLv2
* along with this software; if not, see
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
*
* Red Hat trademarks are not licensed under GPLv2. No permission is
* granted to use or replicate Red Hat trademarks that are incorporated
* in this software or its documentation.
*/
package com.redhat.rhn.frontend.taglibs.list;
import com.redhat.rhn.common.localization.LocalizationService;
import com.redhat.rhn.frontend.html.HtmlTag;
import com.redhat.rhn.frontend.struts.RequestContext;
import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.jsp.JspException;
import javax.servlet.jsp.PageContext;
import javax.servlet.jsp.tagext.BodyTagSupport;
import javax.servlet.jsp.tagext.TagSupport;
/**
* Implements one column of a displayed data list
* @version $Rev $
*/
public class ColumnTag extends BodyTagSupport {
private static final Logger LOG = Logger.getLogger(ColumnTag.class);
private static final long serialVersionUID = -1139212563984660282L;
protected String styleClass;
protected String attributeName;
protected String sortAttribute;
protected boolean isBound;
protected String headerKey;
protected String headerText;
protected String headerStyle;
protected String headerClass;
protected boolean sortable;
private String defaultSortDir;
private String filterAttr;
private String filterMessage;
private String width;
/**
* @param widthIn The width to set.
*/
public void setWidth(String widthIn) {
this.width = widthIn;
}
/**
* @param filterMessageIn The filterMessage to set.
*/
public void setFiltermessage(String filterMessageIn) {
filterMessage = filterMessageIn;
}
/**
* Sets sortable attribute
* True values: true, t, yes, y, 1
* False values: Everything else
* @param sortableIn flag
*/
public void setSortable(String sortableIn) {
sortable = ListTagUtil.toBoolean(sortableIn);
}
/**
* Sets the attribute to sort on. This will override the attribute, if any,
* bound to the column
* @param sortAttr sort attribute
*/
public void setSortattr(String sortAttr) {
sortAttribute = sortAttr;
sortable = true;
}
/**
* Sets the resource bundle key used to display the column's header
* @param key resource bundle key
*/
public void setHeaderkey(String key) {
headerKey = key;
}
/**
* Sets the text to display in the column's header. "header text" may be used
* instead of a header key in cases where there is no resource bundle needed.
* For example, if column heading was a system name and didn't need translation.
* @param text text
*/
public void setHeadertext(String text) {
headerText = text;
}
/**
* Sets the CSS class for the header
* @param styleIn CSS class name
*/
public void setHeaderclass(String styleIn) {
headerStyle = styleIn;
}
/**
* Sets the data bean attribute to use for this column
* @param attr data bean attribute
*/
public void setAttr(String attr) {
attributeName = attr;
}
/**
* Sets the CSS class to use for the data cells
* @param styleIn CSS class name
*/
public void setStyleclass(String styleIn) {
styleClass = styleIn;
}
/**
* Is this column bound or not
* @param bound bound flag
*/
public void setBound(String bound) {
isBound = ListTagUtil.toBoolean(bound);
}
/**
* ${@inheritDoc}
*/
public int doStartTag() throws JspException {
ListCommand command = ListTagUtil.getCurrentCommand(this, pageContext);
ListTag parent = (ListTag) BodyTagSupport.findAncestorWithClass(this,
ListTag.class);
int retval = BodyTagSupport.SKIP_BODY;
if (command.equals(ListCommand.ENUMERATE)) {
parent.addColumn();
retval = BodyTagSupport.EVAL_PAGE;
if (isSortable()) {
parent.setSortable(true);
}
}
else if (command.equals(ListCommand.COL_HEADER)) {
renderHeader();
retval = BodyTagSupport.EVAL_PAGE;
}
else if (command.equals(ListCommand.RENDER)) {
if (isBound) {
renderBound();
retval = BodyTagSupport.SKIP_BODY;
}
else {
renderUnbound();
retval = BodyTagSupport.EVAL_BODY_INCLUDE;
}
}
return retval;
}
/**
* ${@inheritDoc}
*/
public int doEndTag() throws JspException {
if (sortable && attributeName == null && sortAttribute == null) {
throw new JspException("Sortable columns must use either attr or sortAttr");
}
checkForBoundsAndAttrs();
ListCommand command = ListTagUtil.getCurrentCommand(this, pageContext);
if (command.equals(ListCommand.RENDER)) {
ListTagUtil.write(pageContext, "</td>");
}
else if (command.equals(ListCommand.ENUMERATE) &&
!StringUtils.isBlank(filterAttr)) {
setupColumnFilter();
}
return BodyTagSupport.EVAL_PAGE;
}
/**
* ${@inheritDoc}
*/
public void release() {
width = null;
styleClass = null;
attributeName = null;
isBound = false;
headerKey = null;
headerText = null;
headerStyle = null;
headerClass = null;
filterAttr = null;
sortable = false;
filterMessage = null;
}
protected void renderHeader() throws JspException {
if ((headerKey == null) && (headerText == null)) {
return;
}
ListTagUtil.write(pageContext, "<th");
if (headerClass != null) {
ListTagUtil.write(pageContext, " class=\"");
ListTagUtil.write(pageContext, headerClass);
ListTagUtil.write(pageContext, "\" ");
}
String sortDir = getSortDir();
if (headerStyle != null || isCurrColumnSorted()) {
ListTagUtil.write(pageContext, " class=\"");
if (headerStyle != null) {
ListTagUtil.write(pageContext, headerStyle);
ListTagUtil.write(pageContext, " ");
}
if (isCurrColumnSorted()) {
if (isAlphaBarSelected()) {
sortDir = RequestContext.SORT_ASC;
}
ListTagUtil.write(pageContext, sortDir + "Sort");
}
ListTagUtil.write(pageContext, "\"");
}
ListTagUtil.write(pageContext, ">");
if (filterAttr != null) {
HtmlTag filterClass = new HtmlTag("input");
filterClass.setAttribute("type", "hidden");
filterClass.setAttribute("name",
ListTagUtil.makeFilterAttributeByLabel(getListName()));
filterClass.setAttribute("value", filterAttr);
ListTagUtil.write(pageContext, filterClass.render());
}
if (isSortable()) {
writeSortLink();
}
else {
writeColumnName();
}
ListTagUtil.write(pageContext, "</th>");
}
private boolean isCurrColumnSorted() {
String sortName = getSortName();
ListTag parent = (ListTag) BodyTagSupport.findAncestorWithClass(this,
ListTag.class);
if (isAlphaBarSelected() && parent.getAlphaBarColumn().equals(sortName)) {
return true;
}
String requestLabel = pageContext.getRequest().
getParameter(ListTagUtil.makeSortByLabel(getListName()));
if (isSortable() && sortName.equals(requestLabel)) {
return true;
}
return isSortable() && requestLabel == null &&
!StringUtils.isBlank(defaultSortDir);
}
private void writeSortLink() throws JspException {
HttpServletRequest request = (HttpServletRequest) pageContext.getRequest();
String sortBy = getSortName();
String jsurl = ListTagUtil.makeColumnSortLink(request, getListName(),
sortBy, getSortDir());
String href = "<a href=\"javascript:%s\">";
ListTagUtil.write(pageContext, String.format(href, jsurl));
writeColumnName();
ListTagUtil.write(pageContext, "</a>");
}
/**
* @throws JspException
*/
private void writeColumnName() throws JspException {
LocalizationService ls = LocalizationService.getInstance();
if (headerKey != null) {
ListTagUtil.write(pageContext, ls.getMessage(headerKey));
}
else {
ListTagUtil.write(pageContext, headerText);
}
}
private String getSortDir() {
String sortDirectionKey = ListTagUtil.makeSortDirLabel(getListName());
String sortDir = pageContext.getRequest().getParameter(sortDirectionKey);
if (StringUtils.isBlank(sortDir)) {
if (RequestContext.SORT_DESC.equals(defaultSortDir)) {
return RequestContext.SORT_DESC;
}
return RequestContext.SORT_ASC;
}
if (sortDir.equals(RequestContext.SORT_ASC)) {
return RequestContext.SORT_ASC;
}
return RequestContext.SORT_DESC;
}
protected void renderUnbound() throws JspException {
ListTag parent = (ListTag)
BodyTagSupport.findAncestorWithClass(this, ListTag.class);
if (attributeName != null) {
Object bean = parent.getCurrentObject();
String value = ListTagUtil.getBeanValue(bean, attributeName);
pageContext.setAttribute("beanValue", value, PageContext.PAGE_SCOPE);
}
writeStartingTd();
}
protected void renderBound() throws JspException {
ListTag parent = (ListTag)
BodyTagSupport.findAncestorWithClass(this, ListTag.class);
Object bean = parent.getCurrentObject();
writeStartingTd();
ListTagUtil.write(pageContext, ListTagUtil.
getBeanValue(bean, attributeName));
}
/**
*
*/
private void checkForBoundsAndAttrs() {
if (isBound && StringUtils.isBlank(attributeName)) {
String msg = String.format("Error Rendering column - [%s]. " +
"You are probably using bound=true without an attr." +
" Either have both bound = true with " +
"an attr OR set bound=false.", headerKey);
throw new RuntimeException(msg);
}
}
protected String getListName() {
ListTag parent = (ListTag)
BodyTagSupport.findAncestorWithClass(this, ListTag.class);
return parent.getUniqueName();
}
protected void writeStartingTd() throws JspException {
ListTagUtil.write(pageContext, "<td");
ListCommand command = ListTagUtil.getCurrentCommand(this, pageContext);
if (styleClass != null ||
(isCurrColumnSorted() && command != ListCommand.COL_HEADER)) {
ListTagUtil.write(pageContext, " class=\"");
if (styleClass != null) {
ListTagUtil.write(pageContext, styleClass);
ListTagUtil.write(pageContext, " ");
}
if (isCurrColumnSorted()) {
ListTagUtil.write(pageContext, "sortedCol");
}
ListTagUtil.write(pageContext, "\"");
}
if (!StringUtils.isBlank(width)) {
ListTagUtil.write(pageContext, " width=\"");
ListTagUtil.write(pageContext, width);
ListTagUtil.write(pageContext, "\"");
}
ListTagUtil.write(pageContext, ">");
}
private boolean isSortable() {
ListTag parent = (ListTag)
TagSupport.findAncestorWithClass(this, ListTag.class);
return sortable && parent.getPageRowCount() > 0;
}
private boolean isAlphaBarSelected() {
return AlphaBarHelper.getInstance().isSelected(getListName(),
pageContext.getRequest());
}
/**
* Sets up this column as the defualt for sorting...
* @param sortDir the sort direction... asc/desc
*/
public void setDefaultsort(String sortDir) {
String sortName = getSortName();
if (!StringUtils.isBlank(sortName)) {
ListTag parent = (ListTag)
BodyTagSupport.findAncestorWithClass(this, ListTag.class);
DataSetManipulator manip = parent.getManip();
if (StringUtils.isBlank(manip.getDefaultSortAttribute())) {
defaultSortDir = sortDir;
manip.setDefaultSortAttribute(sortAttribute);
manip.setDefaultAscending(RequestContext.SORT_ASC.equals(defaultSortDir));
}
else if (!manip.getDefaultSortAttribute().equals(sortName)) {
String msg = "Trying to set column [%s] as the default sort." +
"The default sort column has already been set for [%s]." +
" Can't reset it to [%s].";
LOG.warn(String.format(msg, sortName,
manip.getDefaultSortAttribute(), sortName));
}
}
else {
String msg = "Can't set a default sort value for a " +
"column that does not have a sortattr or attr tags set. ";
LOG.warn(msg);
}
}
/**
* @return the sort by column name
*/
private String getSortName() {
if (sortAttribute != null) {
return sortAttribute;
}
return attributeName;
}
/**
* @return Returns the headerClass.
*/
public String getHeaderClass() {
return headerClass;
}
/**
* @param headerClassIn The headerClass to set.
*/
public void setHeaderClass(String headerClassIn) {
this.headerClass = headerClassIn;
}
/**
* Sets the filter attribute
* @param attribute the name of the filter attribute
*/
public void setFilterattr(String attribute) {
this.filterAttr = attribute;
}
private void setupColumnFilter() throws JspException {
ListTag parent = (ListTag)
BodyTagSupport.findAncestorWithClass(this, ListTag.class);
String key = headerKey;
if (!StringUtils.isBlank(filterMessage)) {
key = filterMessage;
}
ColumnFilter f = new ColumnFilter(key, filterAttr);
parent.setColumnFilter(f);
}
}