Package org.richfaces.renderkit

Source Code of org.richfaces.renderkit.AbstractProgressBarRenderer

/**
* License Agreement.
*
* Rich Faces - Natural Ajax for Java Server Faces (JSF)
*
* Copyright (C) 2007 Exadel, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License version 2.1 as published by the Free Software Foundation.
*
* 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.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301  USA
*/

/*
* AbstractProgressBarRenderer.java    Date created: 20.12.2007
* Last modified by: $Author$
* $Revision$  $Date$
*/

package org.richfaces.renderkit;

import java.io.IOException;
import java.io.PrintWriter;
import java.math.BigDecimal;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;

import javax.faces.FactoryFinder;
import javax.faces.component.UIComponent;
import javax.faces.context.FacesContext;
import javax.faces.context.ResponseWriter;
import javax.faces.event.ActionEvent;
import javax.faces.render.RenderKit;
import javax.faces.render.RenderKitFactory;
import javax.servlet.http.HttpServletResponse;

import org.ajax4jsf.context.AjaxContext;
import org.ajax4jsf.event.AjaxEvent;
import org.ajax4jsf.javascript.JSFunction;
import org.ajax4jsf.javascript.JSFunctionDefinition;
import org.ajax4jsf.javascript.JSLiteral;
import org.ajax4jsf.javascript.JSReference;
import org.ajax4jsf.javascript.ScriptUtils;
import org.ajax4jsf.renderkit.AjaxRendererUtils;
import org.ajax4jsf.renderkit.ComponentVariables;
import org.ajax4jsf.renderkit.ComponentsVariableResolver;
import org.ajax4jsf.renderkit.RendererUtils.HTML;
import org.ajax4jsf.resource.CountingOutputWriter;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.richfaces.component.UIProgressBar;

/**
* Abstract progress bar renderer
*
* @author "Andrey Markavtsov"
*
*/
public class AbstractProgressBarRenderer extends TemplateEncoderRendererBase {
 
  private static final Log log = LogFactory.getLog(AbstractProgressBarRenderer.class);

  /** Ajax function performing polling */
  private static final String AJAX_POLL_FUNCTION = "A4J.AJAX.Poll";

  /*
   * (non-Javadoc)
   *
   * @see org.ajax4jsf.renderkit.AjaxCommandRendererBase#doDecode(javax.faces.context.FacesContext,
   *      javax.faces.component.UIComponent)
   */
  @Override
  protected void doDecode(FacesContext facesContext, UIComponent uiComponent) {
    new AjaxEvent(uiComponent).queue();
    //uiComponent.queueEvent(new ActionEvent(uiComponent));
  }

  /**
   * Render progress state forced from javascript
   *
   * @param state
   * @param context
   * @param component
   * @throws IOException
   */
  public void renderForcedState(String state, FacesContext context,
      UIComponent component) throws IOException {
    if ("initialState".equals(state)) {
      encodeInitialState(context, component, true);
    } else if ("progressState".equals(state)) {
      encodeProgressState(context, component, true);
    } else if ("completeState".equals(state)) {
      encodeCompletedState(context, component, true);
    }
    component.getAttributes().remove(UIProgressBar.FORCE_PERCENT_PARAM);
  }

  /**
   * Gets state forced from javascript
   *
   * @param component
   * @return
   */
  public String getForcedState(FacesContext context, UIComponent component) {
    String forcedState = null;
    Map<String, String> params = context.getExternalContext()
        .getRequestParameterMap();
    if (params.containsKey(UIProgressBar.FORCE_PERCENT_PARAM)) {
      forcedState = params.get(UIProgressBar.FORCE_PERCENT_PARAM);
    }
    return forcedState;
  }

  /**
   * Renderes label markup
   *
   * @param context
   * @param component
   * @return
   */
  public StringBuffer getMarkup(FacesContext context, UIComponent component) {
    StringBuffer result = new StringBuffer();
    CountingOutputWriter customWriter = new CountingOutputWriter();
    try {
      if (hasChildren(component)) {
       
        ResponseWriter writer = context.getResponseWriter();

        String defaultRenderKitId = context.getApplication()
            .getDefaultRenderKitId();
        if (null == defaultRenderKitId) {
          defaultRenderKitId = RenderKitFactory.HTML_BASIC_RENDER_KIT;
        }
        RenderKitFactory renderKitFactory = (RenderKitFactory) FactoryFinder
            .getFactory(FactoryFinder.RENDER_KIT_FACTORY);
        RenderKit renderKit = renderKitFactory.getRenderKit(context,
            defaultRenderKitId);

        ResponseWriter responseWriter = renderKit.createResponseWriter(
            customWriter, null, "UTF-8");
        context.setResponseWriter(responseWriter);
        writeScriptBody(context, component, true);
        result = customWriter.getContent();
       
        if (writer != null) {
          context.setResponseWriter(writer);
        }else {
          HttpServletResponse response = (HttpServletResponse)context.getExternalContext().getResponse();
          PrintWriter wr = response.getWriter();
          if (wr != null) {
            context.setResponseWriter(renderKit.createResponseWriter(wr, null, "UTF-8"));
          }
        }
      } else {
        writeScriptBody(customWriter, (String) component
            .getAttributes().get("label"));
        result = customWriter.getContent();
      }
    } catch (Exception e) {
      log.error("Error occurred during rendering of progress bar label. It switched to empty string", e);
    }

    return result;

  }

  /**
   * Methods encodes AJAX script for polling
   *
   * @param context -
   *            faces context
   * @param component -
   *            component instance
   * @throws IOException -
   *             IOException
   */
  public void encodePollScript(FacesContext context, UIComponent component)
      throws IOException {

    ResponseWriter writer = context.getResponseWriter();
    UIProgressBar progressBar = (UIProgressBar) component;
    String clientId = component.getClientId(context);
    StringBuffer pollScript = new StringBuffer("\n");
    StringBuffer script = new StringBuffer("\n");
    if (isAjaxMode(component) && progressBar.isEnabled()) {
      JSFunction function = AjaxRendererUtils.buildAjaxFunction(
          component, context, AJAX_POLL_FUNCTION);

      function.addParameter(new JSReference("$('" + clientId
          + "').component.options"));
      function.appendScript(script);

      pollScript.append(script);
    } else {
      pollScript.append(getStopPollScript(clientId));
    }
    pollScript.append(";\n");
    writer.writeText(pollScript.toString(), null);
  }

  /**
   * Encodes script for state rendering in client mode
   *
   * @param context
   * @param component
   * @param state
   * @throws IOException
   */
  public void encodeRenderStateScript(FacesContext context,
      UIComponent component, String state) throws IOException {
    ResponseWriter writer = context.getResponseWriter();
    StringBuffer script = new StringBuffer("\n");
    script.append(
        "$('" + component.getClientId(context)
            + "').component.renderState('").append(state).append(
        "');");
    writer.write(script.toString());
  }

  /**
   * Encodes script for label rendering in client
   *
   * @param context
   * @param component
   * @throws IOException
   */
  public void encodeLabelScript(FacesContext context, UIComponent component)
      throws IOException {
    ResponseWriter writer = context.getResponseWriter();
    StringBuffer script = new StringBuffer("\n");
    script.append(
        "$('" + component.getClientId(context)
            + "').component.renderLabel(").append(
        getMarkup(context, component)).append(",null);\n");
    writer.append(script.toString());

  }

  /**
   * Encode initial javascript
   *
   * @param context
   * @param component
   * @throws IOException
   */
  public void encodeInitialScript(FacesContext context,
      UIComponent component, String state) throws IOException {
    ResponseWriter writer = context.getResponseWriter();
    UIProgressBar progressBar = (UIProgressBar) component;
    ComponentVariables variables = ComponentsVariableResolver.getVariables(
        this, component);
    StringBuffer script = new StringBuffer();
    String clientId = component.getClientId(context);
    String containerId = ((UIComponent) AjaxRendererUtils
        .findAjaxContainer(context, component)).getClientId(context);
    String mode = (String) component.getAttributes().get("mode");
    UIComponent form = AjaxRendererUtils.getNestingForm(component);
    String formId = "";
    if (form != null) {
      formId = form.getClientId(context);
    } else if ("ajax".equals(mode)) {
      // Ignore form absent. It can be rendered by forcing from any
      // component
      // throw new FaceletException("Progress bar component in ajax mode
      // should be placed inside the form");
    }
    Number minValue = getNumber(component.getAttributes().get("minValue"));
    Number maxValue = getNumber(component.getAttributes().get("maxValue"));
    Number value = (Number) variables.getVariable("value");
    StringBuffer markup = getMarkup(context, component);

    script.append("new ProgressBar('").append(clientId).append("','") // id
        .append(containerId).append("','") // containerId
        .append(formId).append("','") // formId
        .append(mode).append("',") // mode
        .append(minValue).append(",") // min value
        .append(maxValue).append(","); // max value
    script.append(getContext(component)); // context
    script.append(",");
    script.append(markup != null ? new JSLiteral(markup.toString())
        : JSReference.NULL); // markup
    script.append(",");
    script.append(ScriptUtils.toScript(buildAjaxOptions(clientId, // options
        progressBar, context)));
    String progressVar = (String) component.getAttributes().get(
        "progressVar");
    if (progressVar != null) {
      script.append(",'");
      script.append(progressVar); // progress var
      script.append("','");
    } else {
      script.append(",null,'");
    }
    script.append(state);
    script.append("',");
    script.append(value.toString());
    script.append(")\n;");
    writer.write(script.toString());
  }

  /**
   * Creates options map for AJAX requests
   *
   * @param clientId
   * @param progressBar
   * @param context
   * @return
   */
  private Map buildAjaxOptions(String clientId, UIProgressBar progressBar,
      FacesContext context) {
    Map options = AjaxRendererUtils.buildEventOptions(context, progressBar);
    Integer interval = new Integer(progressBar.getInterval());
    options.put("pollId", clientId);
    options.put("pollinterval", interval);
    JSFunctionDefinition onsubmit = getUtils().getAsEventHandler(context, progressBar, "onsubmit", "");
    if (onsubmit != null) {
      options.put("onsubmit", onsubmit);
    }
    if (progressBar.getAttributes().containsKey("ignoreDupResponses")) {
      options.put("ignoreDupResponses", progressBar.getAttributes().get(
          "ignoreDupResponses"));
    }
    Map parameters = (Map) options.get("parameters");
    parameters.put("percent", "percent");
    parameters.put(clientId, clientId);
    parameters.put("ajaxSingle", clientId);
    // options.put("onbeforedomupdate", getOnComplete(clientId, progressBar,
    // context));
    return options;
  }

  /**
   * Check if component mode is AJAX
   *
   * @param component
   * @return
   */
  private boolean isAjaxMode(UIComponent component) {
    String mode = (String) component.getAttributes().get("mode");
    return "ajax".equalsIgnoreCase(mode);
  }

  /**
   * Encodes client mode
   *
   * @param context
   * @param component
   * @param value
   * @param min
   * @param max
   * @throws IOException
   */
  public void encodeClientMode(FacesContext context, UIComponent component,
      Number value, Number min, Number max) throws IOException {
    ResponseWriter writer = context.getResponseWriter();
    String clientId = component.getClientId(context);
    String state = (value.doubleValue() <= min.doubleValue()) ? "initialState"
        : ((value.doubleValue() >= max.doubleValue()) ? "completeState"
            : "progressState");
    writer.startElement(HTML.DIV_ELEM, component);
    writer.writeAttribute(HTML.id_ATTRIBUTE, clientId, null);
    encodeInitialState(context, component, false);
    encodeProgressState(context, component, false);
    encodeCompletedState(context, component, false);
    startScript(writer, component);
    encodeInitialScript(context, component, state);
    encodeLabelScript(context, component);
    encodeRenderStateScript(context, component, state);
    endScript(writer, component);
    writer.endElement(HTML.DIV_ELEM);
  }

  /**
   * Methods encodes start facet of progress bar component
   *
   * @param context -
   *            faces context
   * @param component -
   *            component instance
   * @throws IOException -
   *             IOException
   */
  public void encodeInitialState(FacesContext context, UIComponent component,
      boolean isAjaxMode) throws IOException {
    String clientId = component.getClientId(context);
    String initialClass = (String) component.getAttributes().get(
        "initialClass");
    String style = (String) component.getAttributes().get("style");
    if (null==style) style="";
    ResponseWriter writer = context.getResponseWriter();
    writer.startElement(HTML.DIV_ELEM, component);
    getUtils().writeAttribute(writer, HTML.class_ATTRIBUTE, initialClass);
    getUtils().writeAttribute(writer, "style",
        style + (!isAjaxMode ? "display: none" : ""));
    writer.writeAttribute(HTML.id_ATTRIBUTE, (isAjaxMode) ? clientId
        : clientId + ":initialState", null);
    UIComponent initial = component.getFacet("initial");
    if (initial != null) {
      renderChild(context, initial);
    }
    if (isAjaxMode) {
      startScript(writer, component);
      encodeInitialScript(context, component, "initialState");
      encodePollScript(context, component);
      endScript(writer, component);
    }
    writer.endElement(HTML.DIV_ELEM);

  }

  /**
   * Encodes progress state of the component
   *
   * @param context
   * @param component
   * @throws IOException
   */
  public void encodeProgressState(FacesContext context,
      UIComponent component, boolean isAjaxMode) throws IOException {
    ResponseWriter writer = context.getResponseWriter();
    ComponentVariables variables = ComponentsVariableResolver.getVariables(
        this, component);
    String clientId = component.getClientId(context);
    String styleClass = (String) variables.getVariable("styleClass");
    boolean isSimple = isSimpleMarkup(component);
    String style = (String) component.getAttributes().get("style");
    if (null==style) style="";
    String shellClass = (!isSimple) ? "rich-progress-bar-shell-dig "
        : "rich-progress-bar-shell ";
    writer.startElement("div", component);
    getUtils().writeAttribute(
        writer,
        "class",
        "rich-progress-bar-block rich-progress-bar-width " + shellClass
            + (styleClass != null ? styleClass : ""));
    getUtils().writeAttribute(writer, HTML.id_ATTRIBUTE,
        (isAjaxMode) ? clientId : clientId + ":progressState");
    getUtils().writeAttribute(
        writer,
        "style",
        style + (!isAjaxMode ? "display: none" : ""));
    getUtils().encodePassThruWithExclusions(context, component, "onsubmit");
    encodeProgressBar(context, component, isSimple);
    if (isAjaxMode) {
      startScript(writer, component);
      encodeInitialScript(context, component, "progressState");
      encodeLabelScript(context, component);
      encodePollScript(context, component);
      endScript(writer, component);
    }
    writer.endElement("div");
  }

  /**
   * Encodes html of component
   *
   * @param context -
   *            faces context
   * @param component -
   *            component instance
   * @throws IOException
   */
  public void encodeProgressBar(FacesContext context, UIComponent component,
      boolean isSimple) throws IOException {
    ResponseWriter writer = context.getResponseWriter();
    String clientId = component.getClientId(context);
    ComponentVariables variables = ComponentsVariableResolver.getVariables(
        this, component);

    Number value = (Number) variables.getVariable("percent");

    String width = String.valueOf(value.intValue());
    String style = (String) component.getAttributes().get("style");
    if (null==style) style="";

    String completeClass = (String) component.getAttributes().get(
        "completeClass");

    String remainClass = (String) component.getAttributes().get(
        "remainClass");

    if (!isSimple) {
      // <div class='remainClass' id='clientId:remain'
      // style='style'></div>
      writer.startElement("div", component);
      getUtils().writeAttribute(
          writer,
          "class",
          "rich-progress-bar-width rich-progress-bar-remained rich-progress-bar-padding "
              + remainClass);
      getUtils().writeAttribute(writer, "id", clientId + ":remain");
      getUtils().writeAttribute(writer, "style", style);
      writer.endElement("div");

      // <div class='rich-progress-bar-uploaded-dig' id='clientId:upload'
      // style='style'>
      writer.startElement("div", component);
      getUtils().writeAttribute(writer, "class",
          "rich-progress-bar-uploaded-dig");
      getUtils().writeAttribute(writer, "id", clientId + ":upload");
      getUtils().writeAttribute(
          writer,
          "style",
          (style != null ? style + ";" : "") + " width: " + width
              + "%;");

      // <div class='completeClass' id='clientId:complete'
      // style='style'></div>
      writer.startElement("div", component);
      getUtils()
          .writeAttribute(
              writer,
              "class",
              "rich-progress-bar-height-dig rich-progress-bar-width rich-progress-bar-completed rich-progress-bar-padding "
                  + completeClass);
      getUtils().writeAttribute(writer, "id", clientId + ":complete");
      getUtils().writeAttribute(writer, "style", style);
      writer.endElement("div");

      // </div>
      writer.endElement("div");
    } else {
      writer.startElement("div", component);
      getUtils().writeAttribute(
          writer,
          "class",
          "rich-progress-bar-height rich-progress-bar-uploaded "
              + completeClass);
      getUtils().writeAttribute(writer, "id", clientId + ":upload");
      getUtils().writeAttribute(
          writer,
          "style",
          (style != null ? style + ";" : "") + " width: " + width
              + "%;");
      writer.write(" ");
      writer.endElement("div");
    }

  }

  /**
   * Returns parameters attr
   *
   * @param component
   * @param renderer
   * @param percent
   * @return
   */
  public String getParameters(UIComponent component) {
    String parameters = (String) component.getAttributes()
        .get("parameters");
    return parameters;
  }

  /**
   * Writes start script element
   *
   * @param writer
   * @param component
   * @throws IOException
   */
  private void startScript(ResponseWriter writer, UIComponent component)
      throws IOException {
    writer.startElement(HTML.SPAN_ELEM, component);
    writer.writeAttribute(HTML.style_ATTRIBUTE, "display: none;", null);
    writer.startElement(HTML.SCRIPT_ELEM, component);
    writer.writeAttribute(HTML.TYPE_ATTR, "text/javascript", null);
  }

  /**
   * Writes end script element
   *
   * @param writer
   * @param component
   * @throws IOException
   */
  private void endScript(ResponseWriter writer, UIComponent component)
      throws IOException {
    writer.endElement(HTML.SCRIPT_ELEM);
    writer.endElement(HTML.SPAN_ELEM);
  }

  /**
   * Returns context for macrosubstitution
   *
   * @param component
   * @return
   */
  private JSLiteral getContext(UIComponent component) {
    StringBuffer buffer = new StringBuffer();
    String parameters = getParameters(component);
    JSLiteral literal = null;
    if (parameters != null) {
      buffer.append("{").append(parameters).append("}");
      literal = new JSLiteral(buffer.toString());
    } else {
      literal = new JSLiteral("null");
    }
    return literal;
  }

  /**
   * Return true if component has children components
   *
   * @param component
   * @return
   */
  private boolean hasChildren(UIComponent component) {
    return (component.getChildCount() != 0);
  }

  /**
   * Returns true if markup should rendered as simple 2 divs
   *
   * @param component
   * @return
   */
  public boolean isSimpleMarkup(UIComponent component) {
    if (hasChildren(component)) {
      return false;
    } else {
      if (component.getAttributes().get("label") != null) {
        return false;
      }
    }
    return true;
  }

  /**
   * Methods encodes finish facet of progress bar component
   *
   * @param context -
   *            faces context
   * @param component -
   *            component instance
   * @throws IOException -
   *             IOException
   */
  public void encodeCompletedState(FacesContext context,
      UIComponent component, boolean isAjaxMode) throws IOException {
    String clientId = component.getClientId(context);
    String finishClass = (String) component.getAttributes().get(
        "finishClass");
    String style = (String) component.getAttributes().get("style");
    if (null==style) style="";
    ResponseWriter writer = context.getResponseWriter();
    writer.startElement(HTML.DIV_ELEM, component);
    writer.writeAttribute(HTML.id_ATTRIBUTE, (isAjaxMode) ? clientId
        : clientId + ":completeState", null);
    getUtils().writeAttribute(writer, HTML.class_ATTRIBUTE, finishClass);
    getUtils().writeAttribute(writer, "style",
        style + (!isAjaxMode ? "display: none" : ""));

    UIComponent completed = component.getFacet("complete");
    if (completed != null) {
      renderChild(context, completed);
    }
    if (isAjaxMode) {
      startScript(writer, component);
      encodeInitialScript(context, component, "completeState");
      writer.write(getStopPollScript(clientId).toString());
      endScript(writer, component);
    }
    writer.endElement(HTML.DIV_ELEM);

  }

  /**
   * Converts value attr to number value
   *
   * @param v -
   *            value attr
   * @return result
   */
  public Number getNumber(Object v) {
    Number result = null;
    if (v != null) {
      try {
        if (v instanceof String) {
          result = Double.parseDouble((String) v);
        } else {
          Number n = (Number) v;
          if (n instanceof BigDecimal || n instanceof Double
              || n instanceof Float) {
            result = n.floatValue();
          } else if (n instanceof Integer || n instanceof Long) {
            result = n.longValue();
          }
        }
      } catch (Exception e) {
        // no action
      }
      return result;
    }
    return new Integer(0);
  }

  /**
   * Calculates percent value according to min & max value
   *
   * @param value
   * @param minValue
   * @param maxValue
   * @return
   */
  public Number calculatePercent(Number value, Number minValue,
      Number maxValue) {
    if (minValue.doubleValue() < value.doubleValue()
        && value.doubleValue() < maxValue.doubleValue()) {
      return (Number) ((value.doubleValue() - minValue.doubleValue()) * 100.0 / (maxValue
          .doubleValue() - minValue.doubleValue()));
    } else if (value.doubleValue() <= minValue.doubleValue()) {
      return 0;
    } else if (value.doubleValue() >= maxValue.doubleValue()) {
      return 100;
    }
    return 0;
  }

  /**
   * Returns JS script to stop polling
   *
   * @param clientId
   * @return
   */
  private StringBuffer getStopPollScript(String clientId) {
    StringBuffer buffer = new StringBuffer();
    buffer.append("A4J.AJAX.StopPoll('").append(clientId).append("');\n");
    return buffer;
  }

  /*
   * (non-Javadoc)
   *
   * @see org.ajax4jsf.renderkit.RendererBase#getComponentClass()
   */
  protected Class getComponentClass() {
    // only poll component is allowed.
    return UIProgressBar.class;
  }

  /*
   * (non-Javadoc)
   *
   * @see org.richfaces.renderkit.TemplateEncoderRendererBase#encodeChildren(javax.faces.context.FacesContext,
   *      javax.faces.component.UIComponent)
   */
  @Override
  public void encodeChildren(FacesContext context, UIComponent component)
      throws IOException {
    ; // We should not render children
  }

  /*
   * (non-Javadoc)
   *
   * @see org.ajax4jsf.renderkit.RendererBase#doEncodeChildren(javax.faces.context.ResponseWriter,
   *      javax.faces.context.FacesContext, javax.faces.component.UIComponent)
   */
  @Override
  public void doEncodeChildren(ResponseWriter writer, FacesContext context,
      UIComponent component) throws IOException {
    ; // We should not render children
  }

}
TOP

Related Classes of org.richfaces.renderkit.AbstractProgressBarRenderer

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.