zktest/src/main/java/org/zkoss/zktest/zats/zuti/composer/DebuggerComposer.java

Summary

Maintainability
F
4 days
Test Coverage
/** DebuggerComposer.java.

    Purpose:
        
    Description:
        
    History:
        5:23:04 PM Oct 29, 2014, Created by jumperchen

Copyright (C) 2014 Potix Corporation. All Rights Reserved.
*/
package org.zkoss.zktest.zats.zuti.composer;

import static org.zkoss.zk.ui.util.Clients.log;

import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;

import org.zkoss.json.JSONArray;
import org.zkoss.json.JSONObject;
import org.zkoss.json.JSONValue;
import org.zkoss.zk.ui.AbstractComponent;
import org.zkoss.zk.ui.Component;
import org.zkoss.zk.ui.HtmlShadowElement;
import org.zkoss.zk.ui.ShadowElement;
import org.zkoss.zk.ui.select.SelectorComposer;
import org.zkoss.zk.ui.select.annotation.Listen;
import org.zkoss.zk.ui.select.annotation.Wire;
import org.zkoss.zk.ui.sys.ComponentCtrl;
import org.zkoss.zk.ui.util.Clients;
import org.zkoss.zul.Button;
import org.zkoss.zul.Div;

/**
 * @author jumperchen
 *
 */
public class DebuggerComposer extends SelectorComposer<Div> {
    private Component host;
    @Wire Button printTree;
    
    private void logTree(HtmlShadowElement root) {
        // log("=================================================");
        // log0(root, 0);
        JSONObject rootData = new JSONObject();
        if (root != null)
            log1(root, rootData);
        Clients.evalJavaScript("DrawTree(" + rootData.toJSONString() + ",'" + host.getId()+ "')");
    }
    
    private JSONObject fillShadowHost(Component host) {
        JSONObject rootData = fillComponentOnly(host);
        JSONArray childrenArray = new JSONArray();
        rootData.put("children", childrenArray);
        List<AbstractComponent> children = host.getChildren();
        List<HtmlShadowElement> seChildren = ((ComponentCtrl)host).getShadowRoots();
        Iterator<HtmlShadowElement> sit = seChildren.iterator();
        HtmlShadowElement seNext = sit.hasNext() ? sit.next() : null;
        if (children.isEmpty()) {
            if (seNext != null)
                childrenArray.add(fillShadowElement(seNext));
        } else {
            for (ListIterator<AbstractComponent> cit = children.listIterator(); cit.hasNext();) {
                AbstractComponent next = cit.next();
                if (seNext != null) {
                    switch(HtmlShadowElement.inRange(seNext, next)) {
                    case AFTER_NEXT:
                    case NEXT:
                        cit.previous(); // go back
                        childrenArray.add(fillShadowElement(seNext));
                        if (sit.hasNext())
                            seNext = sit.next();
                        else
                            seNext = null;
                        break;
                    case FIRST:
                    case IN_RANGE:
                    case LAST:
                        childrenArray.add(fillShadowElement(seNext, next, cit));
                        if (sit.hasNext())
                            seNext = sit.next();
                        else
                            seNext = null;
                        break;
                    case UNKNOWN:
                        childrenArray.add(fillShadowElement(seNext));
                        if (sit.hasNext())
                            seNext = sit.next();
                        else {
                            seNext = null; // not in the range
                        }
                        cit.previous(); // go back
                        break;
                    default:
                        childrenArray.add(fillComponent(next));
                    }
                } else {
                    childrenArray.add(fillComponent(next));
                }
            }
            if (seNext != null) {
                childrenArray.add(fillShadowElement(seNext));
            }
        }
        return rootData;
    }
    private void logWholeTree(Component host) {
        Clients.evalJavaScript("DrawTree(" + fillShadowHost(host).toJSONString() + ",'" + host.getId() + "')");
    }
    private JSONObject fillShadowElement(HtmlShadowElement se, AbstractComponent current, ListIterator<AbstractComponent> cit) {
        String name = se.toString();
        int index = name.lastIndexOf("->");
        if (index > 0)
            name = name.substring(index + 2);
        List<HtmlShadowElement> children = se.getChildren();
        JSONObject data = new JSONObject();
        data.put("name", name);
        data.put("allChildren", JSONValue.toJSONString(se.getDistributedChildren()));
        data.put("prev", JSONValue.toJSONString(se.getPreviousInsertion()));
        data.put("first", JSONValue.toJSONString(se.getFirstInsertion()));
        data.put("last", JSONValue.toJSONString(se.getLastInsertion()));
        data.put("next", JSONValue.toJSONString(se.getNextInsertion()));
        JSONArray childrenArray = new JSONArray();
        data.put("children", childrenArray);
        AbstractComponent next = current;
        ListIterator<HtmlShadowElement> sit = children.listIterator();
        if (sit.hasNext()) {
            HtmlShadowElement seNext = sit.next();
            boolean first = true;
            do {
                if (!first) { // avoid first time to invoke
                    next = cit.next();
                }
                first = false;
                if (seNext != null) {
                    switch(HtmlShadowElement.inRange(seNext, next)) {
                    case NEXT:
                    case AFTER_NEXT:
                        childrenArray.add(fillShadowElement(seNext));
                        cit.previous(); // go back
                        if (sit.hasNext())
                            seNext = sit.next();
                        else {
                            seNext = null; // not in the range
                        }
                        break;
                    case IN_RANGE:
                    case FIRST:
                    case LAST:
                        childrenArray.add(fillShadowElement(seNext, next, cit));
                        if (sit.hasNext()) {
                            seNext = sit.next();
                            if (!cit.hasNext()) // draw the rest
                                sit.previous();
                        } else {
                            seNext = null; // not in the range
                        }
                        break;
                    case UNKNOWN:
                        childrenArray.add(fillShadowElement(seNext));
                        if (sit.hasNext())
                            seNext = sit.next();
                        else {
                            seNext = null; // not in the range
                        }
                        cit.previous(); // go back
                        break;
                    default:
                        childrenArray.add(fillComponent(next));
                        
                        // draw the reset shadows
                        if (!cit.hasNext()) {
                            sit.previous();
                            while (sit.hasNext()) {
                                childrenArray.add(fillShadowElement(sit.next()));
                            }
                        }
                    }
                } else {
                    switch(HtmlShadowElement.inRange(se, next)) { // in parent range
                    case IN_RANGE:
                    case FIRST:
                    case LAST:
                        childrenArray.add(fillComponent(next));
                        break;
                    default:
                        cit.previous(); // go back

                        return data; // out of parent range;
                    }
                }
            } while (cit.hasNext());
            
            // draw the reset shadows
            while (sit.hasNext()) {
                childrenArray.add(fillShadowElement(sit.next()));
            }
        } else {
            cit.previous();
            do {
                next = cit.next();
                switch(HtmlShadowElement.inRange(se, next)) { // in parent range
                case IN_RANGE:
                case FIRST:
                case LAST:
                    childrenArray.add(fillComponent(next));
                    break;
                default:
                    cit.previous(); // go back

                    return data; // out of parent range;
                }
            } while (cit.hasNext());
        }
        return data;
    }
    private JSONObject fillShadowElement(HtmlShadowElement se) {
        String name = se.toString();
        int index = name.lastIndexOf("->");
        if (index > 0)
            name = name.substring(index + 2);
        List<HtmlShadowElement> children = se.getChildren();
        JSONObject data = new JSONObject();
        data.put("name", name);
        data.put("allChildren", JSONValue.toJSONString(se.getDistributedChildren()));
        data.put("prev", JSONValue.toJSONString(se.getPreviousInsertion()));
        data.put("first", JSONValue.toJSONString(se.getFirstInsertion()));
        data.put("last", JSONValue.toJSONString(se.getLastInsertion()));
        data.put("next", JSONValue.toJSONString(se.getNextInsertion()));
        JSONArray childrenArray = new JSONArray();
        data.put("children", childrenArray);
        for (Iterator<HtmlShadowElement> sit = children.iterator();    sit.hasNext();) {
            childrenArray.add(fillShadowElement(sit.next()));
        }
        return data;
    }
    
    private JSONObject fillComponent(Component child) {
        if (child instanceof ComponentCtrl) {
            ComponentCtrl childCtrl = (ComponentCtrl) child;
            if (!childCtrl.getShadowRoots().isEmpty()) {
                return fillShadowHost(child);
            }
        }
        JSONObject cmpData = new JSONObject();
        cmpData.put("name", child.toString());
        cmpData.put("real", true);
        return cmpData;
    }
    private JSONObject fillComponentOnly(Component child) {
        JSONObject cmpData = new JSONObject();
        cmpData.put("name", child.toString());
        cmpData.put("real", true);
        return cmpData;
    }
    private void log1(HtmlShadowElement se, JSONObject data) {
        String name = se.toString();
        int index = name.lastIndexOf("->");
        if (index > 0)
            name = name.substring(index + 2);
        data.put("name", name);
        data.put("allChildren", JSONValue.toJSONString(se.getDistributedChildren()));
        data.put("prev", JSONValue.toJSONString(se.getPreviousInsertion()));
        data.put("first", JSONValue.toJSONString(se.getFirstInsertion()));
        data.put("last", JSONValue.toJSONString(se.getLastInsertion()));
        data.put("next", JSONValue.toJSONString(se.getNextInsertion()));
        JSONArray children = new JSONArray();
        for (Iterator<Component> it = se.getChildren().iterator(); it.hasNext();) {
            JSONObject child = new JSONObject();
            log1((HtmlShadowElement) it.next(), child);
            children.add(child);
        }
        if (!children.isEmpty())
            data.put("children", children);
    }
    private void log0(HtmlShadowElement se, int depth) {
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < depth; i++)
            sb.append("\t");
        log(se.toString());
        log(sb + "AllChlidren: " + se.getDistributedChildren());
        log(sb + "Previous Sibling: " + se.getPreviousInsertion());
        log(sb + "FirstChild: " + se.getFirstInsertion());
        log(sb + "LastChild: " + se.getLastInsertion());
        log(sb + "Next Sibling: " + se.getNextInsertion());
        log("");
        for (Iterator<Component> it = se.getChildren().iterator(); it.hasNext();) {
            log0((HtmlShadowElement) it.next(), depth+1);
        }
    }
    @Listen("onClick=#printShadowTree")
    public void doPrintTree() {
        List<ShadowElement> roots = ((ComponentCtrl)host).getShadowRoots();
        if (!roots.isEmpty()) {
            HtmlShadowElement se = (HtmlShadowElement)roots.get(0);
            logTree(se);
        } else {
            logTree(null);
        }
    }
    @Listen("onClick=#printWholeTree")
    public void doPrintAllTree() {
        logWholeTree(host);
    }
    
    public void doAfterCompose(Div comp) throws Exception {
        // TODO Auto-generated method stub
        super.doAfterCompose(comp);
        Object attribute = comp.getAttribute("rootId");
        Object idspace = comp.getAttribute("idspace");
        if (idspace != null)
            host = comp.getFellow((String)idspace).getFellowIfAny(attribute.toString());
        else
            host = comp.getFellowIfAny(attribute.toString());
    }
}