Package org.richfaces.renderkit

Source Code of org.richfaces.renderkit.Context

/**
* License Agreement.
*
*  JBoss RichFaces - Ajax4jsf Component Library
*
* 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
*/

package org.richfaces.renderkit;

import java.io.IOException;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;

import javax.faces.FacesException;
import javax.faces.component.NamingContainer;
import javax.faces.component.UIComponent;
import javax.faces.context.ExternalContext;
import javax.faces.context.FacesContext;
import javax.faces.context.ResponseWriter;
import javax.faces.el.MethodBinding;

import org.ajax4jsf.javascript.JSFunction;
import org.ajax4jsf.javascript.JSReference;
import org.ajax4jsf.javascript.ScriptUtils;
import org.ajax4jsf.model.DataVisitor;
import org.ajax4jsf.renderkit.AjaxRendererUtils;
import org.ajax4jsf.renderkit.ComponentsVariableResolver;
import org.richfaces.component.UITree;
import org.richfaces.component.UITreeNode;
import org.richfaces.component.nsutils.NSUtils;
import org.richfaces.component.state.TreeState;
import org.richfaces.component.state.TreeStateAdvisor;
import org.richfaces.model.LastElementAware;
import org.richfaces.model.TreeRange;
import org.richfaces.model.TreeRowKey;

public abstract class TreeRendererBase extends CompositeRenderer {

  protected final static Comparator treeRowKeyComparator = new Comparator() {

    public int compare(Object key1, Object key2) {
      TreeRowKey treeRowKey1 = (TreeRowKey) key1;
      TreeRowKey treeRowKey2 = (TreeRowKey) key2;

      if (treeRowKey1 == null) {
        if (treeRowKey2 == null) {
          return 0;
        } else {
          return -1;
        }
      } else {
        if (treeRowKey2 == null) {
          return 1;
        }
      }

      Iterator iterator1 = treeRowKey1.iterator();
      Iterator iterator2 = treeRowKey2.iterator();

      while (iterator1.hasNext() && iterator2.hasNext()) {
        String id1 = iterator1.next().toString();
        String id2 = iterator2.next().toString();

        int cr = id1.compareTo(id2);
        if (cr != 0) {
          return cr;
        }
      }

      if (iterator1.hasNext()) {
        return 1;
      } else if (iterator2.hasNext()) {
        return -1;
      } else {
        return 0;
      }
    }
  };

  private final class RendererDataModelEventNavigator extends
  TreeDataModelEventNavigator {
    private final FacesContext context;
    private final UITree tree;
    private final Flag droppedDownToLevelFlag;
    private final ResponseWriter writer;

    private String clientId;
    private boolean expanded;
    private boolean showLines;

    private RendererDataModelEventNavigator(UITree tree,
        TreeRowKey floatingKey, FacesContext context, Flag droppedDownToLevelFlag) {
      super(tree, floatingKey);
      this.context = context;
      this.tree = tree;
      this.droppedDownToLevelFlag = droppedDownToLevelFlag;
      this.writer = context.getResponseWriter();

      this.expanded = this.tree.isExpanded();
      this.showLines = this.tree.isShowConnectingLines();
      this.clientId = getClientId();
    }

    public void followRowKey(FacesContext context, TreeRowKey newRowKey) throws IOException {
      super.followRowKey(context, newRowKey);

      this.expanded = this.tree.isExpanded();
      this.clientId = getClientId();
    }

    private String getClientId() {
      Object rowKey = tree.getRowKey();
      String id;
      if (rowKey == null) {
        id = tree.getClientId(context)
        + NamingContainer.SEPARATOR_CHAR;
      } else {
        id = tree.getNodeFacet().getClientId(context)
        + NamingContainer.SEPARATOR_CHAR;
      }
      return id;
    }

    public void afterUp(int levels) throws IOException {
      Context c = droppedDownToLevelFlag.getContext();
      if (c != null) {
        c.setHasChildren(false);
        openDiv(c);
        closeDiv();
        droppedDownToLevelFlag.setContext(null);
      }

      //writer.write("** afterUp **");
      for (int i = 0; i < levels; i++) {
        closeDiv();
      }

      //if (!isLastElement) closeDiv();
    }

    public void afterDown() throws IOException {
    }   

    public void beforeDown() throws IOException {
      Context c = droppedDownToLevelFlag.getContext();
      droppedDownToLevelFlag.setContext(null);
      openDiv(c);
      //writer.write("** beforeDown **");

      //if (this.getRowKey()==null ) openDiv();

    }

    public void beforeUp(int levels) throws IOException {
    }

    public void openDiv(Context context) throws IOException {
      writer.startElement("div", tree);

      if (context == null) {
        context = new Context();
        context.setLast(this.actualLast);
        context.setClientId(this.clientId);
        context.setExpanded(this.expanded);
        context.setRowKey(this.getRowKey());
      }

      getUtils().writeAttribute(writer, "id", context.getClientId() + "childs");

      if (!context.isExpanded() || !context.isHasChildren()) {
        getUtils().writeAttribute(writer, "style", "display: none;");
      } else {
        if (tree.isShowConnectingLines()) {
          TreeRowKey floatingKey = getFloatingKey();
          //need the expression only for AJAX update root
          if (floatingKey != null && floatingKey.equals(context.getRowKey())) {
            String expression = "background-image:expression(this.nextSibling ? '' : 'none')";
            getUtils().writeAttribute(writer, "style", expression);
          }
        }
      }

      String styleClasses = "";
      if (context.getRowKey() != null) {
        styleClasses = "dr-tree-layout-on dr-tree-h-ic-div rich-tree-node-children rich-tree-node-cildren";
        if (!context.isLast() && showLines) styleClasses += " dr-tree-h-ic-line";
      }
      if (styleClasses!="") getUtils().writeAttribute(writer, "class", styleClasses);
    }

    public void closeDiv() throws IOException {
      writer.endElement("div");
    }
  }

  private class DataVisitorWithLastElement implements DataVisitor,
  LastElementAware {

    private boolean isLastElement = false;

    private final Flag flag;

    private final UITree tree;

    private final RendererDataModelEventNavigator navigator;

    private TreeStateAdvisor methodBindingAdvisor = null;

    private Object floatingKey;

    private DataVisitorWithLastElement(Flag flag, UITree tree,
        RendererDataModelEventNavigator navigator, Object rowKey) {
      this.flag = flag;
      this.tree = tree;
      this.navigator = navigator;
      this.floatingKey = rowKey;
    }

    public void process(FacesContext context, Object rowKey, Object argument)
    throws IOException {
      TreeRowKey<?> treeRowKey = (TreeRowKey<?>) rowKey;

      processAdvisors(context, treeRowKey);

      navigator.followRowKey(context, treeRowKey);

      Context c = flag.getContext();
      if (c != null) {
        c.setHasChildren(false);
        navigator.openDiv(c);
        navigator.closeDiv();
      }

      UITreeNode nodeFacet = tree.getNodeFacet();
      Object oldAttrValue = nodeFacet.getAttributes().get("isLastElement");
      Object oldAjaxRootAttrValue = nodeFacet.getAttributes().get("isAjaxUpdateRoot");
      try {
        nodeFacet.getAttributes().put("isLastElement", new Boolean(isLastElement));
        nodeFacet.getAttributes().put("isAjaxUpdateRoot", new Boolean(floatingKey != null && floatingKey.equals(rowKey)));
        ResponseWriter writer = context.getResponseWriter();
        if (isLastElement && this.navigator.showLines) {
          writer.startElement("p", tree);
          writer.writeAttribute("class", "dr-tree-last-node-marker", null);
          writer.endElement("p");
        }

        renderChild(context, nodeFacet);


        c = new Context();
        c.setClientId(nodeFacet.getClientId(context) + NamingContainer.SEPARATOR_CHAR);
        c.setLast(this.isLastElement);
        c.setExpanded(tree.isExpanded());
        c.setRowKey(tree.getRowKey());
        flag.setContext(c);

        //writer.write("** after renderChild **");
        //navigator.openDiv();
      } finally {
        if (oldAttrValue != null) {
          nodeFacet.getAttributes().put("isLastElement", oldAttrValue);
        } else {
          nodeFacet.getAttributes().remove("isLastElement");
        }

        if (oldAjaxRootAttrValue != null) {
          nodeFacet.getAttributes().put("isAjaxUpdateRoot", oldAjaxRootAttrValue);
        } else {
          nodeFacet.getAttributes().remove("isAjaxUpdateRoot");
        }
      }
    }

    public void setLastElement() {
      isLastElement = true;
      navigator.setLastElement();
    }

    public void resetLastElement() {
      isLastElement = false;
      navigator.resetLastElement();
    }

    public void processAdvisors(FacesContext context, TreeRowKey rowKey) throws IOException {
      TreeState state = (TreeState) tree.getComponentState();
      TreeStateAdvisor stateAdvisor = (TreeStateAdvisor)tree.getStateAdvisor();

      if (null == stateAdvisor) {
        if (null == methodBindingAdvisor) {
          methodBindingAdvisor = new TreeStateAdvisor() {
            public Boolean adviseNodeOpened(UITree tree) {
              MethodBinding adviseNodeOpened = tree.getAdviseNodeOpened();
              if (null != adviseNodeOpened) {
                return (Boolean) adviseNodeOpened.invoke(FacesContext.getCurrentInstance(), new Object[] {tree});
              }
              return null;
            }

            public Boolean adviseNodeSelected(UITree tree) {
              MethodBinding adviseNodeSelected = tree.getAdviseNodeSelected();
              if (null != adviseNodeSelected) {
                return (Boolean) adviseNodeSelected.invoke(FacesContext.getCurrentInstance(), new Object [] {tree});
              }
              return null;
            }
          };
        }
        stateAdvisor = methodBindingAdvisor;
      }

      Boolean adviseOpened = stateAdvisor.adviseNodeOpened(tree);
      if (null != adviseOpened) {
        if (adviseOpened.booleanValue()) {
          state.makeExpanded(rowKey);
        } else {
          state.makeCollapsed(rowKey);
        }
      }
     
      Boolean adviseSelected = stateAdvisor.adviseNodeSelected(tree);
      if (null != adviseSelected) {
        if (adviseSelected.booleanValue()) {
          if (!state.isSelected(rowKey)) {
            state.setSelected(rowKey);
          }
        }
        else {
          if (state.isSelected(rowKey)) {
            state.setSelected(null);
          }
        }
      }
    }
  }

  public TreeRendererBase() {
    super();
    addContributor(DraggableRendererContributor.getInstance());
    addContributor(DropzoneRendererContributor.getInstance());

    addParameterEncoder(DnDParametersEncoder.getInstance());
  }

  public void writeNamespace(FacesContext context, UIComponent component) throws IOException {
    NSUtils.writeNameSpace(context, component);
  }

  public void encodeAjaxChildren(FacesContext context, UIComponent component,
      String path, Set ids, Set renderedAreas) throws IOException {
    super.encodeAjaxChildren(context, component, path, ids, renderedAreas);

    try {
      if (component instanceof UITree) {
        UITree tree = (UITree) component;

        String id = path + tree.getId();

        tree.captureOrigValue();
        //Object rowKey = tree.getRowKey();

        boolean encodeScripts = false;

        tree.setRowKey(context, null);

        //we should add xmlns to AJAX response
        //we'll write neutral inner element and add xmlns there
        ResponseWriter responseWriter = context.getResponseWriter();
        responseWriter.startElement("div", tree);
        writeNamespace(context, component);

        List encodedAreaIds = new ArrayList();

        try {
          Set ajaxKeys = tree.getAllAjaxKeys();
          if (ajaxKeys != null) {
            List sortedKeys = new ArrayList(ajaxKeys.size());
            sortedKeys.addAll(ajaxKeys);
            Collections.sort(sortedKeys, treeRowKeyComparator);
            Iterator ajaxKeysItr = sortedKeys.iterator();
            TreeRowKey lastKey = null;
            boolean nullRoot = false;

            while (!nullRoot && ajaxKeysItr.hasNext()) {
              TreeRowKey key = (TreeRowKey) ajaxKeysItr.next();

              if (lastKey == null) {
                lastKey = key;
              } else {
                if (!lastKey.isSubKey(key)) {
                  lastKey = key;
                } else {
                  //skip nodes that's parent nodes have been rendered
                  continue;
                }
              }

              if (key == null || key.depth() == 0) {
                nullRoot = true;
                key = null;
              }

              tree.setRowKey(context, key);

              if (key == null || tree.isRowAvailable()) {
                String treeClientId;
                if (key == null) {
                  treeClientId = tree.getClientId(context);
                } else {
                  treeClientId = tree.getNodeFacet().getClientId(context);
                }

                String treeChildrenId = treeClientId + NamingContainer.SEPARATOR_CHAR + "childs";
               
                writeContent(context, tree, key);
                encodeScripts = true;
                renderedAreas.add(treeClientId);
                encodedAreaIds.add(treeClientId);

                renderedAreas.add(treeChildrenId);
                //encodedAreaIds.add(id+":childs");
              } else {
                String cid = tree.getClientId(context);
                String message = MessageFormat.format(
                    "Failed to re-render tree node: {0} due to model data unavailability! " +
                    "Maybe parent node should be re-rendered instead?",
                    new Object[] { cid });
               
                ExternalContext externalContext = context.getExternalContext();
                externalContext.log(message);
              }
            }
            //ajaxKeys.clear();
          }
        } catch (Exception e) {
          throw new FacesException(e);
        } finally {
          try {
            tree.setRowKey(context, null);
            tree.restoreOrigValue();
          } catch (Exception e) {
            context.getExternalContext().log(e.getMessage(), e);
          }
        }
        if (encodeScripts) {
          writeScript(context, tree, encodedAreaIds, renderedAreas);

          String inputId = encodeSelectionStateInput(context, tree);
          if (inputId != null) {
            renderedAreas.add(inputId);
          }
        }

        responseWriter.endElement("div");
        tree.clearRequestKeysSet();
      }
    } finally {
      try {
        ComponentsVariableResolver.removeVariables(this, component);
      } catch (Exception e) {
        context.getExternalContext().log(e.getMessage(), e);
      }
    }
  }

  public String encodeSelectionStateInput(FacesContext context, UITree tree) throws IOException {
    String result = "";
    TreeState treeState = (TreeState) tree.getComponentState();
    TreeRowKey selectedNodeKey = treeState.getSelectedNode();
    if (selectedNodeKey != null) {
      Object rowKey = tree.getRowKey();
      try {
        tree.setRowKey(selectedNodeKey);
        if (tree.isRowAvailable()) {
          result = tree.getNodeFacet().getClientId(context);
        }
      } finally {
        try {
          tree.setRowKey(rowKey);
        } catch (Exception e) {
          context.getExternalContext().log(e.getMessage(), e);
        }
      }
    }

    ResponseWriter writer = context.getResponseWriter();
    writer.startElement("input", tree);
    writer.writeAttribute("type", "hidden", null);
    String selectionHolderInputId = tree.getSelectionStateInputName(context);
    writer.writeAttribute("id", selectionHolderInputId, null);
    writer.writeAttribute("name", selectionHolderInputId, null);

    writer.writeAttribute("value", result, null);
    writer.endElement("input");

    return selectionHolderInputId;
  }

  protected String getAjaxScript(FacesContext context, UITree tree) {
    String id = tree.getBaseClientId(context);
    JSFunction function = AjaxRendererUtils
    .buildAjaxFunction(tree, context);
    Map eventOptions = AjaxRendererUtils.buildEventOptions(context, tree);
    Map parameters = (Map) eventOptions.get("parameters");
    parameters.remove(id);
    parameters.put(id + UITree.SELECTED_NODE_PARAMETER_NAME,
        new JSReference("event.selectedNode"));
    function.addParameter(eventOptions);
    StringBuffer buffer = new StringBuffer();
    function.appendScript(buffer);
    buffer.append("; return false;");
    return buffer.toString();
  }

  protected String getScriptContributions(FacesContext context, UITree tree) {
    return super.getScriptContributions(getJavaScriptVarName(context, tree), context, tree);
  }

  protected String getJavaScriptVarName(FacesContext context, UITree tree) {
    String id = tree.getBaseClientId(context);
    return "Richfaces_Tree_" + id.replaceAll("[^A-Za-z0-9_]", "_");
  }

  private void writeScript(FacesContext context, UITree tree, List encodedAreaIds,
      Set renderedAreas) throws IOException {
    final ResponseWriter writer = context.getResponseWriter();
    final String clientId = tree.getBaseClientId(context);

    String scriptId = clientId + NamingContainer.SEPARATOR_CHAR + "script";
    writer.startElement("div", tree);
    getUtils().writeAttribute(writer, "id", scriptId);
    writer.startElement("script", tree);
    getUtils().writeAttribute(writer, "type", "text/javascript");

    String varName = getJavaScriptVarName(context, tree);

    writer.writeText(varName + ".getNodeElements(" +
        ScriptUtils.toScript(encodedAreaIds) + ");", null);


    writer.endElement("script");
    writer.endElement("div");

    renderedAreas.add(tree.getClientId(context)
        + NamingContainer.SEPARATOR_CHAR + "input");

    renderedAreas.add(scriptId);

  }

  public void encodeChildren(FacesContext context, UIComponent component)
  throws IOException {

    writeContent(context, (UITree) component, null);
  }

  public void writeContent(final FacesContext context, final UITree input)
  throws IOException {
    writeContent(context, input, null);
  }

  public void writeContent(final FacesContext context, final UITree input,
      TreeRowKey key) throws IOException {
    // simple flag can be used here because
    // we cannot jump more than one level down until next node
    // when rendering
    Flag droppedDownToLevelFlag = new Flag();

    TreeRowKey rowKey = (TreeRowKey) key;

    //Object savedRowKey = input.getRowKey();
    try {
      input.captureOrigValue();

      input.setRowKey(context, key);

      RendererDataModelEventNavigator levelNavigator = new RendererDataModelEventNavigator(input, rowKey, context,
          droppedDownToLevelFlag);

      final TreeRange stateRange = (TreeRange) input.getComponentState().getRange();
      TreeRange treeRange = new TreeRange() {

        public boolean processChildren(TreeRowKey rowKey) {
          return stateRange.processChildren(rowKey);
        }

        public boolean processNode(TreeRowKey rowKey) {
          Object currentKey = input.getRowKey();

          if (currentKey == null ? rowKey != null : !currentKey.equals(rowKey)) {
            //currentKey NE rowKey
            input.setRowKey(context, rowKey);
          }

          UITreeNode nodeFacet = input.getNodeFacet();
          if (!nodeFacet.isRendered()) {
            return false;
          }

          return stateRange.processNode(rowKey);
        }

      };

      input.transferQueuedNode();
     
      //TODO should render if current node not in range?
      input.walk(context, new DataVisitorWithLastElement(droppedDownToLevelFlag, input,
          levelNavigator, key), treeRange, key, null);

      levelNavigator.followRowKey(context, null);
    } finally {
      input.setRowKey(context, null);
      input.restoreOrigValue();
    }
  }
}

class Flag {
  private Context context;

  public Context getContext() {
    return context;
  }

  public void setContext(Context context) {
    this.context = context;
  }
}

class Context {
  private String clientId;
  private Object rowKey;
  private boolean expanded;
  private boolean last;
  private boolean hasChildren = true;
  public String getClientId() {
    return clientId;
  }
  public void setClientId(String clientId) {
    this.clientId = clientId;
  }
  public Object getRowKey() {
    return rowKey;
  }
  public void setRowKey(Object rowKey) {
    this.rowKey = rowKey;
  }
  public boolean isExpanded() {
    return expanded;
  }
  public void setExpanded(boolean expanded) {
    this.expanded = expanded;
  }
  public boolean isLast() {
    return last;
  }
  public void setLast(boolean last) {
    this.last = last;
  }
  public boolean isHasChildren() {
    return hasChildren;
  }
  public void setHasChildren(boolean hasChildren) {
    this.hasChildren = hasChildren;
  }
}
TOP

Related Classes of org.richfaces.renderkit.Context

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.