org.openxdata.sharedlib.client.widget.RuntimeGroupWidget.java Source code

Java tutorial

Introduction

Here is the source code for org.openxdata.sharedlib.client.widget.RuntimeGroupWidget.java

Source

package org.openxdata.sharedlib.client.widget;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;

import org.openxdata.sharedlib.client.controller.OpenFileDialogEventListener;
import org.openxdata.sharedlib.client.controller.QuestionChangeListener;
import org.openxdata.sharedlib.client.locale.FormsConstants;
import org.openxdata.sharedlib.client.model.FormDef;
import org.openxdata.sharedlib.client.model.OptionDef;
import org.openxdata.sharedlib.client.model.QuestionDef;
import org.openxdata.sharedlib.client.model.RepeatQtnsDef;
import org.openxdata.sharedlib.client.model.ValidationRule;
import org.openxdata.sharedlib.client.util.FormUtil;
import org.openxdata.sharedlib.client.view.FormRunnerView;
import org.openxdata.sharedlib.client.view.FormRunnerView.Images;
import org.openxdata.sharedlib.client.view.OpenFileDialog;
import org.openxdata.sharedlib.client.xforms.XformConstants;
import org.openxdata.sharedlib.client.xforms.XmlUtil;

import com.google.gwt.core.client.GWT;
import com.google.gwt.core.client.Scheduler;
import com.google.gwt.core.client.Scheduler.ScheduledCommand;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.http.client.URL;
import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.ui.AbsolutePanel;
import com.google.gwt.user.client.ui.Button;
import com.google.gwt.user.client.ui.CheckBox;
import com.google.gwt.user.client.ui.Composite;
import com.google.gwt.user.client.ui.FlexTable;
import com.google.gwt.user.client.ui.HTML;
import com.google.gwt.user.client.ui.HorizontalPanel;
import com.google.gwt.user.client.ui.Image;
import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.ListBox;
import com.google.gwt.user.client.ui.PushButton;
import com.google.gwt.user.client.ui.RadioButton;
import com.google.gwt.user.client.ui.TextArea;
import com.google.gwt.user.client.ui.TextBox;
import com.google.gwt.user.client.ui.VerticalPanel;
import com.google.gwt.user.client.ui.Widget;
import com.google.gwt.xml.client.Element;
import com.google.gwt.xml.client.Node;
import com.google.gwt.xml.client.NodeList;
import org.openxdata.sharedlib.client.model.QuestionType;

/**
 * 
 *  www.openxdata.org - Licensed as written in license.txt and original sources of this file and its authors are found in sources.txt.
 *
 */
public class RuntimeGroupWidget extends Composite implements OpenFileDialogEventListener, QuestionChangeListener {

    private FormsConstants constants = GWT.create(FormsConstants.class);

    private final Images images;
    private RepeatQtnsDef repeatQtnsDef;
    private HashMap<String, RuntimeWidgetWrapper> widgetMap = new HashMap<String, RuntimeWidgetWrapper>();
    private EditListener editListener;
    private FlexTable table;
    private List<RuntimeWidgetWrapper> buttons = new ArrayList<RuntimeWidgetWrapper>();
    private List<RuntimeWidgetWrapper> widgets = new ArrayList<RuntimeWidgetWrapper>();
    private VerticalPanel verticalPanel = new VerticalPanel();
    private List<Element> dataNodes = new ArrayList<Element>();
    private AbsolutePanel selectedPanel = new AbsolutePanel();
    private boolean isRepeated = false;
    private Image image;
    private HTML html;
    private FormDef formDef;
    private Button btnAdd;
    private RuntimeWidgetWrapper firstInvalidWidget;

    protected HashMap<QuestionDef, List<Label>> labelMap = new HashMap<QuestionDef, List<Label>>();;
    protected HashMap<Label, String> labelText = new HashMap<Label, String>();
    protected HashMap<Label, String> labelReplaceText = new HashMap<Label, String>();

    protected HashMap<QuestionDef, List<CheckBox>> checkBoxGroupMap = new HashMap<QuestionDef, List<CheckBox>>();

    protected HashMap<QuestionDef, List<RuntimeWidgetWrapper>> calcWidgetMap = new HashMap<QuestionDef, List<RuntimeWidgetWrapper>>();

    /**
     * A map of filtered single select dynamic questions and their corresponding 
     * non label widgets. Only questions of single select dynamic which have the
     * widget filter property set are put in this list
     */
    protected HashMap<QuestionDef, RuntimeWidgetWrapper> filtDynOptWidgetMap = new HashMap<QuestionDef, RuntimeWidgetWrapper>();

    public RuntimeGroupWidget(Images images, FormDef formDef, RepeatQtnsDef repeatQtnsDef,
            EditListener editListener, boolean isRepeated) {
        this.images = images;
        this.formDef = formDef;
        this.repeatQtnsDef = repeatQtnsDef;
        this.editListener = editListener;
        this.isRepeated = isRepeated;

        if (isRepeated) {
            table = new FlexTable();
            FormUtil.maximizeWidget(table);
            verticalPanel.add(table);
            initWidget(verticalPanel);
        } else {
            //FormUtil.maximizeWidget(selectedPanel);   
            initWidget(selectedPanel);
        }
        //setupEventListeners();

        //table.setStyleName("cw-FlexTable");
        this.addStyleName("formtools-repeat-border");
    }

    //TODO The code below needs great refactoring together with PreviewView
    private RuntimeWidgetWrapper getParentWrapper(Widget widget, Element node, String parentBinding) {
        RuntimeWidgetWrapper parentWrapper = widgetMap.get(parentBinding);
        if (parentWrapper == null) {
            QuestionDef qtn = null;
            if (repeatQtnsDef != null)
                qtn = repeatQtnsDef.getQuestion(parentBinding);
            else
                qtn = formDef.getQuestion(parentBinding);

            if (qtn != null) {
                parentWrapper = new RuntimeWidgetWrapper(widget, images.error(), editListener);
                parentWrapper.setQuestionDef(qtn, true);
                widgetMap.put(parentBinding, parentWrapper);

                qtn.addChangeListener(this);
                List<CheckBox> list = new ArrayList<CheckBox>();
                list.add((CheckBox) widget);
                checkBoxGroupMap.put(qtn, list);
            }
        } else
            checkBoxGroupMap.get(parentWrapper.getQuestionDef()).add((CheckBox) widget);

        return parentWrapper;
    }

    public void loadWidgets(FormDef formDef, NodeList nodes, List<RuntimeWidgetWrapper> externalSourceWidgets,
            HashMap<QuestionDef, List<QuestionDef>> calcQtnMappings,
            HashMap<QuestionDef, List<RuntimeWidgetWrapper>> calcWidgetMap,
            HashMap<QuestionDef, RuntimeWidgetWrapper> filtDynOptWidgetMap) {

        HashMap<Integer, RuntimeWidgetWrapper> widgetMap = new HashMap<Integer, RuntimeWidgetWrapper>();
        int maxTabIndex = 0;

        for (int i = 0; i < nodes.getLength(); i++) {
            if (nodes.item(i).getNodeType() != Node.ELEMENT_NODE)
                continue;
            try {
                Element node = (Element) nodes.item(i);
                int index = loadWidget(formDef, node, widgetMap, externalSourceWidgets, calcQtnMappings,
                        calcWidgetMap, filtDynOptWidgetMap);
                if (index > maxTabIndex)
                    maxTabIndex = index;
            } catch (Exception ex) {
                ex.printStackTrace();
            }
        }

        //We are adding widgets to the panel according to the tab index.
        for (int index = 0; index <= maxTabIndex; index++) {
            RuntimeWidgetWrapper widget = widgetMap.get(new Integer(index));
            if (widget != null)
                addWidget(widget);
        }

        if (isRepeated) {

            Scheduler.get().scheduleDeferred(new ScheduledCommand() {
                public void execute() {
                    RuntimeWidgetWrapper widget = widgets.get(0);
                    if (!(widget.getQuestionDef() == null || widget.getQuestionDef().getDataNode() == null)) {

                        Element repeatDataNode = getParentNode(widget.getQuestionDef().getDataNode(),
                                (widget.getWrappedWidget() instanceof CheckBox) ? widget.getParentBinding()
                                        : widget.getBinding());
                        Element parent = (Element) repeatDataNode.getParentNode();
                        NodeList nodeList = parent.getElementsByTagName(repeatDataNode.getNodeName());

                        RuntimeWidgetWrapper wrapper = (RuntimeWidgetWrapper) getParent().getParent();
                        int y = getHeightInt();

                        for (int index = 1; index < nodeList.getLength(); index++)
                            addNewRow((Element) nodeList.item(index));

                        editListener.onRowAdded(wrapper, getHeightInt() - y);

                    }
                }
            });
        }

        //Now add the button widgets, if any.
        if (isRepeated) {
            HorizontalPanel panel = new HorizontalPanel();
            panel.setSpacing(5);
            for (int index = 0; index < buttons.size(); index++)
                panel.add(buttons.get(index));
            verticalPanel.add(panel);

            addDeleteButton(0);

            FormUtil.maximizeWidget(panel);
        } else {
            for (int index = 0; index < buttons.size(); index++) {
                RuntimeWidgetWrapper widget = buttons.get(index);
                selectedPanel.add(widget);
                FormUtil.setWidgetPosition(widget, widget.getLeft(), widget.getTop());
                //FormUtil.setWidgetPosition(selectedPanel,widget,widget.getLeft(),widget.getTop());
            }
        }
    }

    private void addDeleteButton(int row) {
        PushButton btn = new PushButton(constants.deleteItem());
        btn.addClickHandler(new ClickHandler() {
            public void onClick(ClickEvent event) {
                removeRow((Widget) event.getSource());
            }
        });
        table.setWidget(row, widgets.size(), btn);
    }

    private void removeRow(Widget sender) {
        if (table.getRowCount() == 1) {//There should be atleast one row{
            clearValue();
            return;
        }

        for (int row = 1; row < table.getRowCount(); row++) {
            if (sender == table.getWidget(row, widgets.size())) {

                RuntimeWidgetWrapper wrapper = (RuntimeWidgetWrapper) getParent().getParent();
                int y = getHeightInt();

                table.removeRow(row);
                Element node = dataNodes.get(row - 1);
                node.getParentNode().removeChild(node);
                dataNodes.remove(node);
                if (btnAdd != null)
                    btnAdd.setEnabled(true);

                editListener.onRowRemoved(wrapper, y - getHeightInt());

                RuntimeWidgetWrapper parent = (RuntimeWidgetWrapper) getParent().getParent();
                ValidationRule validationRule = parent.getValidationRule();
                if (validationRule != null)
                    parent.getQuestionDef().setAnswer(table.getRowCount() + "");
            }
        }
    }

    private int loadWidget(FormDef formDef, Element node, HashMap<Integer, RuntimeWidgetWrapper> widgets,
            List<RuntimeWidgetWrapper> externalSourceWidgets,
            HashMap<QuestionDef, List<QuestionDef>> calcQtnMappings,
            HashMap<QuestionDef, List<RuntimeWidgetWrapper>> calcWidgetMap,
            HashMap<QuestionDef, RuntimeWidgetWrapper> filtDynOptWidgetMap) {

        RuntimeWidgetWrapper parentWrapper = null;

        String s = node.getAttribute(WidgetEx.WIDGET_PROPERTY_WIDGETTYPE);
        int tabIndex = (node.getAttribute(WidgetEx.WIDGET_PROPERTY_TABINDEX) != null
                ? Integer.parseInt(node.getAttribute(WidgetEx.WIDGET_PROPERTY_TABINDEX))
                : 0);

        QuestionDef questionDef = null;
        String binding = node.getAttribute(WidgetEx.WIDGET_PROPERTY_BINDING);
        String parentBinding = node.getAttribute(WidgetEx.WIDGET_PROPERTY_PARENTBINDING);

        if (isRepeated) {
            if (binding != null && binding.trim().length() > 0 && repeatQtnsDef != null) {
                questionDef = repeatQtnsDef.getQuestion(binding);
                if (questionDef != null)
                    questionDef.setAnswer(questionDef.getDefaultValue()); //Just incase we are refreshing and had already set the answer
            }
        } else {
            if (binding != null && binding.trim().length() > 0) {
                questionDef = formDef.getQuestion(binding);
                if (questionDef != null)
                    questionDef.setAnswer(questionDef.getDefaultValue()); //Just incase we are refreshing and had already set the answer
            }
        }

        RuntimeWidgetWrapper wrapper = null;
        boolean wrapperSet = false;
        Widget widget = null;
        if (s.equalsIgnoreCase(WidgetEx.WIDGET_TYPE_RADIOBUTTON)) {
            /*widget = new RadioButton(parentBinding,node.getAttribute(WidgetEx.WIDGET_PROPERTY_TEXT));
            parentWrapper = getParentWrapper(widget,node);
            ((RadioButton)widget).setTabIndex(tabIndex);*/

            widget = new RadioButtonWidget(parentBinding, node.getAttribute(WidgetEx.WIDGET_PROPERTY_TEXT));

            if (widgetMap.get(parentBinding) == null)
                wrapperSet = true;

            parentWrapper = getParentWrapper(widget, node, parentBinding);
            ((RadioButton) widget).setTabIndex(tabIndex);

            if (wrapperSet) {
                wrapper = parentWrapper;
                questionDef = formDef.getQuestion(parentBinding);
            }
        } else if (s.equalsIgnoreCase(WidgetEx.WIDGET_TYPE_CHECKBOX)) {
            /*widget = new CheckBox(node.getAttribute(WidgetEx.WIDGET_PROPERTY_TEXT));
            parentWrapper = getParentWrapper(widget,node);
            ((CheckBox)widget).setTabIndex(tabIndex);*/

            widget = new CheckBoxWidget(node.getAttribute(WidgetEx.WIDGET_PROPERTY_TEXT));
            if (widgetMap.get(parentBinding) == null)
                wrapperSet = true;

            parentWrapper = getParentWrapper(widget, node, parentBinding);
            ((CheckBox) widget).setTabIndex(tabIndex);

            String defaultValue = parentWrapper.getQuestionDef().getDefaultValue();
            if (defaultValue != null && defaultValue.contains(binding))
                ((CheckBox) widget).setValue(true);

            if (wrapperSet) {
                wrapper = parentWrapper;
                questionDef = formDef.getQuestion(parentBinding);
            }
        } else if (s.equalsIgnoreCase(WidgetEx.WIDGET_TYPE_BUTTON)) {
            widget = new Button(node.getAttribute(WidgetEx.WIDGET_PROPERTY_TEXT));
            ((Button) widget).setTabIndex(tabIndex);
        } else if (s.equalsIgnoreCase(WidgetEx.WIDGET_TYPE_LISTBOX)) {
            widget = new ListBoxWidget(false);
            ((ListBox) widget).setTabIndex(tabIndex);
        } else if (s.equalsIgnoreCase(WidgetEx.WIDGET_TYPE_TEXTAREA)) {
            widget = new TextArea();
            ((TextArea) widget).setTabIndex(tabIndex);
        } else if (s.equalsIgnoreCase(WidgetEx.WIDGET_TYPE_DATEPICKER)) {
            widget = new DatePickerWidget();
            ((DatePickerEx) widget).setTabIndex(tabIndex);
        } else if (s.equalsIgnoreCase(WidgetEx.WIDGET_TYPE_DATETIME)) {
            widget = new DateTimeWidget();
            ((DateTimeWidget) widget).setTabIndex(tabIndex);
        } else if (s.equalsIgnoreCase(WidgetEx.WIDGET_TYPE_TIME)) {
            widget = new TimeWidget();
            ((TimeWidget) widget).setTabIndex(tabIndex);
        } else if (s.equalsIgnoreCase(WidgetEx.WIDGET_TYPE_TEXTBOX)) {
            widget = new TextBox();
            if (questionDef != null && (questionDef.getDataType() == QuestionType.NUMERIC
                    || questionDef.getDataType() == QuestionType.DECIMAL))
                FormUtil.allowNumericOnly((TextBox) widget, questionDef.getDataType() == QuestionType.DECIMAL);
            ((TextBox) widget).setTabIndex(tabIndex);
        } else if (s.equalsIgnoreCase(WidgetEx.WIDGET_TYPE_LABEL)) {
            String text = node.getAttribute(WidgetEx.WIDGET_PROPERTY_TEXT);
            if (text == null)
                text = "No Label Text";
            widget = new Label(text);

            int pos1 = text.indexOf("${");
            int pos2 = text.indexOf("}$");
            if (pos1 > -1 && pos2 > -1 && (pos2 > pos1)) {
                String varname = text.substring(pos1 + 2, pos2);
                labelText.put((Label) widget, text);
                labelReplaceText.put((Label) widget, "${" + varname + "}$");

                ((Label) widget).setText(text.replace("${" + varname + "}$", ""));
                if (varname.startsWith("/" + formDef.getBinding() + "/"))
                    varname = varname.substring(("/" + formDef.getBinding() + "/").length(), varname.length());

                QuestionDef qtnDef = formDef.getQuestion(varname);
                List<Label> labels = labelMap.get(qtnDef);
                if (labels == null) {
                    labels = new ArrayList<Label>();
                    labelMap.put(qtnDef, labels);
                }
                labels.add((Label) widget);
            }
        } else if (s.equalsIgnoreCase(WidgetEx.WIDGET_TYPE_IMAGE)) {
            widget = new Image();
            String xpath = binding;
            if (!xpath.startsWith(formDef.getBinding()))
                xpath = "/" + formDef.getBinding() + "/" + binding;
            ((Image) widget).setUrl(URL.encode(FormUtil.getMultimediaUrl() + "?formId=" + formDef.getId()
                    + "&xpath=" + xpath + "&time=" + new java.util.Date().getTime()));
        } else if (s.equalsIgnoreCase(WidgetEx.WIDGET_TYPE_VIDEO_AUDIO) && questionDef != null) {
            widget = new HTML();
            String xpath = binding;
            if (!xpath.startsWith(formDef.getBinding()))
                xpath = "/" + formDef.getBinding() + "/" + binding;

            String extension = "";//.3gp ".mpeg";
            String contentType = "&contentType=video/3gpp";
            if (questionDef.getDataType() == QuestionType.AUDIO)
                contentType = "&contentType=audio/3gpp"; //"&contentType=audio/x-wav";
            //extension = ".wav";

            contentType += "&name=" + questionDef.getBinding() + ".3gp";

            ((HTML) widget).setHTML("<a href="
                    + URL.encode(FormUtil.getMultimediaUrl() + extension + "?formId=" + formDef.getId() + "&xpath="
                            + xpath + contentType + "&time=" + new java.util.Date().getTime())
                    + ">" + node.getAttribute(WidgetEx.WIDGET_PROPERTY_TEXT) + "</a>");

            String answer = questionDef.getAnswer();
            if (answer == null || answer.trim().length() == 0)
                ((HTML) widget).setVisible(false);
        } else if (s.equalsIgnoreCase(WidgetEx.WIDGET_TYPE_GROUPBOX)
                || s.equalsIgnoreCase(WidgetEx.WIDGET_TYPE_REPEATSECTION)) {
            RepeatQtnsDef repeatQtnsDef = null;
            if (questionDef != null)
                repeatQtnsDef = questionDef.getRepeatQtnsDef();

            boolean repeated = false;
            String value = node.getAttribute(WidgetEx.WIDGET_PROPERTY_REPEATED);
            if (value != null && value.trim().length() > 0)
                repeated = (value.equals(WidgetEx.REPEATED_TRUE_VALUE));

            widget = new RuntimeGroupWidget(images, formDef, repeatQtnsDef, editListener, repeated);
            ((RuntimeGroupWidget) widget).loadWidgets(formDef, node.getChildNodes(), externalSourceWidgets,
                    calcQtnMappings, calcWidgetMap, filtDynOptWidgetMap);
            /*getLabelMap(((RuntimeGroupWidget)widget).getLabelMap());
            getLabelText(((RuntimeGroupWidget)widget).getLabelText());
            getLabelReplaceText(((RuntimeGroupWidget)widget).getLabelReplaceText());
            getCheckBoxGroupMap(((RuntimeGroupWidget)widget).getCheckBoxGroupMap());*/
        }

        /*else if(s.equalsIgnoreCase(WidgetEx.WIDGET_TYPE_REPEATSECTION)){
           //Not dealing with nested repeats
           //widget = new RunTimeGroupWidget();
           //((RunTimeGroupWidget)widget).setTabIndex(tabIndex);
        }*/
        else
            return tabIndex;

        if (!wrapperSet) {
            wrapper = new RuntimeWidgetWrapper(widget, images.error(), editListener);

            if (parentWrapper != null) { //Check box or radio button
                if (!parentWrapper.getQuestionDef().isVisible())
                    wrapper.setVisible(false);
                if (!parentWrapper.getQuestionDef().isEnabled())
                    wrapper.setEnabled(false);
                if (parentWrapper.getQuestionDef().isLocked())
                    wrapper.setLocked(true);
            }
        }

        //RuntimeWidgetWrapper wrapper = new RuntimeWidgetWrapper(widget,images.error(),editListener);
        boolean loadWidget = true;

        String value = node.getAttribute(WidgetEx.WIDGET_PROPERTY_HELPTEXT);
        if (value != null && value.trim().length() > 0)
            wrapper.setTitle(value);

        value = node.getAttribute(WidgetEx.WIDGET_PROPERTY_WIDTH);
        if (value != null && value.trim().length() > 0)
            wrapper.setWidth(value);

        value = node.getAttribute(WidgetEx.WIDGET_PROPERTY_HEIGHT);
        if (value != null && value.trim().length() > 0)
            wrapper.setHeight(value);

        value = node.getAttribute(WidgetEx.WIDGET_PROPERTY_EXTERNALSOURCE);
        if (value != null && value.trim().length() > 0)
            wrapper.setExternalSource(value);

        value = node.getAttribute(WidgetEx.WIDGET_PROPERTY_DISPLAYFIELD);
        if (value != null && value.trim().length() > 0)
            wrapper.setDisplayField(value);

        value = node.getAttribute(WidgetEx.WIDGET_PROPERTY_FILTERFIELD);
        if (value != null && value.trim().length() > 0)
            wrapper.setFilterField(value);

        value = node.getAttribute(WidgetEx.WIDGET_PROPERTY_ID);
        if (value != null && value.trim().length() > 0)
            wrapper.setId(value);

        if (s.equalsIgnoreCase(WidgetEx.WIDGET_TYPE_VIDEO_AUDIO)
                || s.equalsIgnoreCase(WidgetEx.WIDGET_TYPE_IMAGE)) {
            if (binding != null && binding.trim().length() > 0) {
                questionDef = formDef.getQuestion(binding);
                if (questionDef != null)
                    questionDef.setAnswer(questionDef.getDefaultValue()); //Just incase we are refreshing and had already set the answer
            }
        }

        if (questionDef != null) {
            if (questionDef.getDataType() == QuestionType.LIST_EXCLUSIVE_DYNAMIC) {
                questionDef.setOptions(null); //may have been set by the preview
                //if(wrapper.getWrappedWidget() instanceof ListBox || wrapper.getWrappedWidget() instanceof TextBox)
                if (wrapper.getFilterField() != null && wrapper.getFilterField().trim().length() > 0)
                    filtDynOptWidgetMap.put(questionDef, wrapper);
            }

            wrapper.setQuestionDef(questionDef, false);
            ValidationRule validationRule = formDef.getValidationRule(questionDef);
            wrapper.setValidationRule(validationRule);
        }

        if (parentBinding != null)
            wrapper.setParentBinding(parentBinding);

        if (binding != null)
            wrapper.setBinding(binding);

        if (parentWrapper != null)
            parentWrapper.addChildWidget(wrapper);

        value = node.getAttribute(WidgetEx.WIDGET_PROPERTY_VALUEFIELD);
        if (value != null && value.trim().length() > 0) {
            wrapper.setValueField(value);

            if (externalSourceWidgets != null && wrapper.getExternalSource() != null
                    && wrapper.getDisplayField() != null
                    && (wrapper.getWrappedWidget() instanceof TextBox
                            || wrapper.getWrappedWidget() instanceof ListBox)
                    && questionDef != null && (wrapper.getQuestionDef().getDataType() == QuestionType.LIST_EXCLUSIVE
                            || wrapper.getQuestionDef().getDataType() == QuestionType.LIST_MULTIPLE)) {
                externalSourceWidgets.add(wrapper);
                loadWidget = false;
            }
        }

        if (loadWidget)
            wrapper.loadQuestion();

        wrapper.setExternalSourceDisplayValue();

        value = node.getAttribute(WidgetEx.WIDGET_PROPERTY_HEIGHT);
        if (value != null && value.trim().length() > 0)
            wrapper.setHeight(value);

        String left = node.getAttribute(WidgetEx.WIDGET_PROPERTY_LEFT);
        if (left != null && left.trim().length() > 0)
            wrapper.setLeft(left);

        String top = node.getAttribute(WidgetEx.WIDGET_PROPERTY_TOP);
        if (top != null && top.trim().length() > 0)
            wrapper.setTop(top);

        //if(wrapper.getWrappedWidget() instanceof Label)
        WidgetEx.loadLabelProperties(node, wrapper);

        wrapper.setTabIndex(tabIndex);
        //wrapper.setParentBinding(parentBinding);

        if (tabIndex > 0 && !(wrapper.getWrappedWidget() instanceof Button))
            widgets.put(new Integer(tabIndex), wrapper);
        else
            addWidget(wrapper);

        if (wrapperSet)
            ;//FormUtil.setWidgetPosition(wrapper,left,top);

        if (widget instanceof Button && binding != null) {
            //wrapper.setParentBinding(parentBinding);

            if (binding.equals("addnew") || binding.equals("remove") || binding.equals("submit")
                    || binding.equals("browse") || binding.equals("clear") || binding.equals("cancel")
                    || binding.equals("search")) {
                ((Button) widget).addClickHandler(new ClickHandler() {
                    public void onClick(ClickEvent event) {
                        execute((Widget) event.getSource());
                    }
                });
            }
        }

        if (wrapper.isEditable() && questionDef != null)
            FormRunnerView.updateCalcWidgetMapping(wrapper, calcQtnMappings, calcWidgetMap);

        return tabIndex;
    }

    /**
     * Just adds the first row. Other runtime rows are added using addNewRow
     * @param wrapper
     */
    private void addWidget(RuntimeWidgetWrapper wrapper) {
        String binding = wrapper.getBinding();
        if (wrapper.getWrappedWidget() instanceof Button
                && !("browse".equals(binding) || "clear".equals(binding))) {

            //Ensure that the Add New and Remove buttons are displayed according to tab index
            if (buttons.size() == 0 || (buttons.get(0).getTabIndex() <= wrapper.getTabIndex()))
                buttons.add(wrapper);
            else {
                RuntimeWidgetWrapper w = buttons.remove(0);
                buttons.add(wrapper);
                buttons.add(w);
            }
            return;
        }

        if (isRepeated) {
            //widgets.add(new RuntimeWidgetWrapper(wrapper));
            widgets.add(wrapper);

            int row = 0, col = 0;
            if (table.getRowCount() > 0)
                col = table.getCellCount(row);

            table.setWidget(row, col, wrapper);
        } else {
            selectedPanel.add(wrapper);
            FormUtil.setWidgetPosition(wrapper, wrapper.getLeft(), wrapper.getTop());
            //FormUtil.setWidgetPosition(selectedPanel,wrapper,wrapper.getLeft(),wrapper.getTop());
        }
    }

    private void execute(Widget sender) {
        String binding = ((RuntimeWidgetWrapper) sender.getParent().getParent()).getBinding();

        if (binding.equalsIgnoreCase("search")) {
            RuntimeWidgetWrapper wrapper = getCurrentMultimediWrapper(sender);
            if (wrapper != null && wrapper.getExternalSource() != null)
                ;//FormUtil.searchExternal(wrapper.getExternalSource(),sender.getElement(),wrapper.getWrappedWidget().getElement(),null);
        } else if (binding.equalsIgnoreCase("submit"))
            ((FormRunnerView) getParent().getParent().getParent().getParent().getParent().getParent().getParent())
                    .onSubmit();
        else if (binding.equalsIgnoreCase("cancel"))
            ((FormRunnerView) getParent().getParent().getParent().getParent().getParent().getParent().getParent())
                    .onCancel();
        else if (repeatQtnsDef != null) {
            if (binding.equalsIgnoreCase("addnew")) {
                RuntimeWidgetWrapper wrapper = (RuntimeWidgetWrapper) getParent().getParent();
                int y = getHeightInt();

                addNewRow(sender);

                editListener.onRowAdded(wrapper, getHeightInt() - y);
            } else if (binding.equalsIgnoreCase("remove")) {
                if (table.getRowCount() > 1) {//There should be atleast one row{
                    RuntimeWidgetWrapper wrapper = (RuntimeWidgetWrapper) getParent().getParent();
                    int y = getHeightInt();

                    table.removeRow(table.getRowCount() - 1);
                    Element node = dataNodes.get(dataNodes.size() - 1);
                    node.getParentNode().removeChild(node);
                    dataNodes.remove(node);
                    if (btnAdd != null)
                        btnAdd.setEnabled(true);

                    editListener.onRowRemoved(wrapper, y - getHeightInt());
                }

                RuntimeWidgetWrapper parent = (RuntimeWidgetWrapper) getParent().getParent();
                ValidationRule validationRule = parent.getValidationRule();
                if (validationRule != null)
                    parent.getQuestionDef().setAnswer(table.getRowCount() + "");
            }
        } else {
            if (binding.equalsIgnoreCase("clear")) {
                RuntimeWidgetWrapper wrapper = getCurrentMultimediWrapper(sender);
                if (wrapper == null)
                    return;

                if (wrapper.getWrappedWidget() instanceof Image
                        && (((Image) wrapper.getWrappedWidget()).getUrl() == null
                                || ((Image) wrapper.getWrappedWidget()).getUrl().trim().length() == 0))
                    return;
                if (wrapper.getWrappedWidget() instanceof HTML && !wrapper.getWrappedWidget().isVisible())
                    return;

                if (!Window.confirm(constants.deleteItemPrompt()))
                    return;

                QuestionDef questionDef = wrapper.getQuestionDef();
                if (questionDef != null)
                    questionDef.setAnswer(null);

                if (wrapper.getWrappedWidget() instanceof Image) {
                    image = (Image) wrapper.getWrappedWidget();
                    image.setUrl(null);
                    html = null;
                } else if (wrapper.getWrappedWidget() instanceof Label)
                    ((Label) wrapper.getWrappedWidget()).setText(constants.noSelection());
                else {
                    html = (HTML) wrapper.getWrappedWidget();
                    html.setHTML(constants.clickToPlay());
                    html.setVisible(false);
                    image = null;
                }
                return;
            } else if (binding.equalsIgnoreCase("browse")) {
                RuntimeWidgetWrapper wrapper = getCurrentMultimediWrapper(sender);
                if (wrapper == null)
                    return;

                if (wrapper.getWrappedWidget() instanceof Image)
                    image = (Image) wrapper.getWrappedWidget();
                else
                    html = (HTML) wrapper.getWrappedWidget();

                String xpath = wrapper.getBinding();
                if (!xpath.startsWith(formDef.getBinding()))
                    xpath = "/" + formDef.getBinding() + "/" + wrapper.getBinding();

                String contentType = "&contentType=video/3gpp";
                contentType += "&name=" + wrapper.getQuestionDef().getBinding() + ".3gp";

                //TODO What if the multimedia url suffix already has a ?
                String url = FormUtil.getMultimediaUrl() + "?formId=" + formDef.getId() + "&xpath=" + xpath
                        + contentType + "&time=" + new java.util.Date().getTime();
                OpenFileDialog dlg = new OpenFileDialog(this, url);
                dlg.center();
            }
        }
    }

    /*private Image getCurrentImage(Widget sender){         
       RuntimeWidgetWrapper wrapper = getCurrentMultimediWrapper(sender);
       if(wrapper != null)
     return (Image)wrapper.getWrappedWidget();
        
       return null;
    }*/

    private RuntimeWidgetWrapper getCurrentMultimediWrapper(Widget sender) {
        RuntimeWidgetWrapper button = (RuntimeWidgetWrapper) sender.getParent().getParent();
        for (int index = 0; index < selectedPanel.getWidgetCount(); index++) {
            RuntimeWidgetWrapper widget = (RuntimeWidgetWrapper) selectedPanel.getWidget(index);
            Widget wrappedWidget = widget.getWrappedWidget();
            if (wrappedWidget instanceof Image
                    || wrappedWidget instanceof HTML /*|| wrappedWidget instanceof Label*/) {
                String binding = widget.getBinding();
                if (binding != null && binding.equalsIgnoreCase(button.getParentBinding()))
                    return widget;
            }
        }
        return null;
    }

    private void addNewRow(Widget sender) {
        HashMap<String, RuntimeWidgetWrapper> widgetMap = new HashMap<String, RuntimeWidgetWrapper>();

        RuntimeWidgetWrapper firstWidget = null;
        Element newRepeatDataNode = null;
        int row = table.getRowCount();
        for (int index = 0; index < widgets.size(); index++) {
            RuntimeWidgetWrapper mainWidget = widgets.get(index);
            RuntimeWidgetWrapper copyWidget = getPreparedWidget(mainWidget, false);

            //table.setWidget(row, index, copyWidget);

            if (index == 0) {
                Element dataNode = mainWidget.getQuestionDef().getDataNode();
                if (dataNode == null) {
                    Window.alert("Please first save the form"); //constants.?????");
                    return; //possibly form not yet saved
                }

                Element repeatDataNode = getParentNode(dataNode,
                        (mainWidget.getWrappedWidget() instanceof CheckBox) ? mainWidget.getParentBinding()
                                : mainWidget.getBinding());
                newRepeatDataNode = (Element) repeatDataNode.cloneNode(true);
                repeatDataNode.getParentNode().appendChild(newRepeatDataNode);
                //workonDefaults(newRepeatDataNode);
                dataNodes.add(newRepeatDataNode);

                firstWidget = copyWidget;
            }

            table.setWidget(row, index, copyWidget);

            setDataNode(copyWidget, newRepeatDataNode, copyWidget.getBinding(), false);

            //For now we do not allow default values for repeat kids to simplify implementation.
            copyWidget.getQuestionDef().setDefaultValue(null);

            //Loading widget from here instead of in getPreparedWidget because setDataNode may clear default values         
            copyWidget.loadQuestion();

            if (copyWidget.getWrappedWidget() instanceof RadioButton)
                ((RadioButton) copyWidget.getWrappedWidget())
                        .setName(((RadioButton) copyWidget.getWrappedWidget()).getName() + row);

            if (copyWidget.getWrappedWidget() instanceof CheckBox) {
                RuntimeWidgetWrapper widget = widgetMap.get(copyWidget.getParentBinding());
                if (widget == null) {
                    widget = copyWidget;
                    widgetMap.put(copyWidget.getParentBinding(), widget);
                }
                widget.addChildWidget(copyWidget);
            }
        }

        addDeleteButton(row);

        btnAdd = (Button) sender;
        RuntimeWidgetWrapper parent = (RuntimeWidgetWrapper) getParent().getParent();
        ValidationRule validationRule = parent.getValidationRule();
        if (validationRule != null) {
            row++;
            parent.getQuestionDef().setAnswer(row + "");
            if (validationRule.getMaxValue(formDef) == row)
                ((Button) sender).setEnabled(false);
        }

        if (firstWidget != null)
            firstWidget.setFocus();

        //byte maxRows = repeatQtnsDef.getMaxRows();
        //if(maxRows > 0 && row == maxRows)
        //   ((Button)sender).setEnabled(false);
    }

    private void addNewRow(Element dataNode) {
        dataNodes.add(dataNode);

        int row = table.getRowCount();
        for (int index = 0; index < widgets.size(); index++) {
            RuntimeWidgetWrapper mainWidget = widgets.get(index);
            RuntimeWidgetWrapper copyWidget = getPreparedWidget(mainWidget, false);

            table.setWidget(row, index, copyWidget);

            setDataNode(copyWidget, dataNode, copyWidget.getBinding(), true);
        }

        addDeleteButton(row);
    }

    private Element getParentNode(Node node, String binding) {
        String name = binding;
        int pos = binding.indexOf('/');
        if (pos > 0) {
            name = binding.substring(0, pos);
            int pos2 = binding.lastIndexOf('/');
            if (pos != pos2)
                return (Element) node.getParentNode(); //name = binding.substring(pos+1, pos2);
        }

        return getParentNodeWithName(node, name);
    }

    private Element getParentNodeWithName(Node node, String name) {
        Element parentNode = (Element) node.getParentNode();
        if (node.getNodeName().equalsIgnoreCase(name))
            return parentNode;
        else if (name.contains("/"))
            return parentNode;
        return getParentNodeWithName(parentNode, name);
    }

    private void setDataNode(RuntimeWidgetWrapper widget, Element parentNode, String binding, boolean loadQtn) {
        if (widget.getQuestionDef() == null)
            return; //for checkboxes, only the first may have reference to the parent questiondef

        String name = (widget.getWrappedWidget() instanceof CheckBox) ? widget.getParentBinding() : binding;
        int pos = name.indexOf('/');
        if (pos > 0) {
            int pos2 = name.lastIndexOf('/');
            if (pos != pos2) {
                name = name.substring(pos2 + 1);
                pos = -1;
            } else
                name = name.substring(0, pos);
        }

        NodeList nodes = parentNode.getChildNodes();
        for (int index = 0; index < nodes.getLength(); index++) {
            Node child = nodes.item(index);
            if (child.getNodeType() != Node.ELEMENT_NODE)
                continue;
            if (name.contains("/"))
                name = name.substring(name.lastIndexOf('/') + 1);
            if (child.getNodeName().equals(
                    name) /*||
                          (child.getParentNode().getNodeName() + "/"+ child.getNodeName()).equals(widget.getBinding())*/) {
                if (pos > 0)
                    setDataNode(widget, (Element) child, binding.substring(pos + 1), loadQtn);
                else {
                    widget.getQuestionDef().setDataNode((Element) child);
                    if (loadQtn) {
                        widget.getQuestionDef().setDefaultValue(XmlUtil.getTextValue((Element) child));
                        widget.loadQuestion();
                    } else {
                        ((Element) child).setAttribute("new", XformConstants.XPATH_VALUE_TRUE);
                        if (XformConstants.XPATH_VALUE_FALSE.equals(((Element) child).getAttribute("default")))
                            widget.getQuestionDef().setDefaultValue(null);
                    }
                    widget.setExternalSourceDisplayValue();
                }
                return;
            }
        }
    }

    private RuntimeWidgetWrapper getPreparedWidget(RuntimeWidgetWrapper w, boolean loadQtn) {
        RuntimeWidgetWrapper widget = new RuntimeWidgetWrapper(w);

        if (loadQtn)
            widget.loadQuestion();

        QuestionDef questionDef = widget.getQuestionDef();
        if (questionDef != null && (questionDef.getDataType() == QuestionType.NUMERIC
                || questionDef.getDataType() == QuestionType.DECIMAL))
            FormUtil.allowNumericOnly((TextBox) widget.getWrappedWidget(),
                    questionDef.getDataType() == QuestionType.DECIMAL);

        widget.refreshSize();
        return widget;
    }

    public void setEnabled(boolean enabled) {
        if (isRepeated) {
            HorizontalPanel panel = (HorizontalPanel) verticalPanel.getWidget(1);
            for (int index = 0; index < panel.getWidgetCount(); index++)
                ((RuntimeWidgetWrapper) panel.getWidget(index)).setEnabled(enabled);

            for (int row = 0; row < table.getRowCount(); row++) {
                for (int col = 0; col < table.getCellCount(row) - 1; col++)
                    ((RuntimeWidgetWrapper) table.getWidget(row, col)).setEnabled(enabled);
            }
        } else {
            for (int index = 0; index < selectedPanel.getWidgetCount(); index++) {
                ((RuntimeWidgetWrapper) selectedPanel.getWidget(index)).setEnabled(enabled);
            }
        }
    }

    public void setLocked(boolean locked) {
        if (isRepeated) {
            HorizontalPanel panel = (HorizontalPanel) verticalPanel.getWidget(1);
            for (int index = 0; index < panel.getWidgetCount(); index++)
                ((RuntimeWidgetWrapper) panel.getWidget(index)).setLocked(locked);

            for (int row = 0; row < table.getRowCount(); row++) {
                for (int col = 0; col < table.getCellCount(row) - 1; col++)
                    ((RuntimeWidgetWrapper) table.getWidget(row, col)).setLocked(locked);
            }
        } else {
            for (int index = 0; index < selectedPanel.getWidgetCount(); index++) {
                ((RuntimeWidgetWrapper) selectedPanel.getWidget(index)).setLocked(locked);
            }
        }
    }

    public void saveValue(FormDef formDef) {
        if (isRepeated) {
            for (int row = 0; row < table.getRowCount(); row++) {
                for (int col = 0; col < table.getCellCount(row) - 1; col++)
                    ((RuntimeWidgetWrapper) table.getWidget(row, col)).saveValue(formDef);
            }
        } else {
            for (int index = 0; index < selectedPanel.getWidgetCount(); index++) {
                ((RuntimeWidgetWrapper) selectedPanel.getWidget(index)).saveValue(formDef);
            }
        }

        if (repeatQtnsDef != null)
            repeatQtnsDef.getQtnDef().setAnswer(getRowCount() + "");
    }

    public int getRowCount() {
        int rows = 0;

        for (int row = 0; row < table.getRowCount(); row++) {
            boolean answerFound = false;
            for (int col = 0; col < table.getCellCount(row) - 1; col++) {
                if (((RuntimeWidgetWrapper) table.getWidget(row, col)).isAnswered()) {
                    answerFound = true;
                    break;
                }
            }

            if (answerFound)
                rows++;
        }

        return rows;
    }

    public void onSetFileContents(String contents) {
        if (contents != null && contents.trim().length() > 0) {
            contents = contents.replace("<pre>", "");
            contents = contents.replace("</pre>", "");
            RuntimeWidgetWrapper widgetWrapper = null;

            if (image != null)
                widgetWrapper = (RuntimeWidgetWrapper) image.getParent().getParent();
            else
                widgetWrapper = (RuntimeWidgetWrapper) html.getParent().getParent();

            String xpath = widgetWrapper.getBinding();
            if (!xpath.startsWith(formDef.getBinding()))
                xpath = "/" + formDef.getBinding() + "/" + widgetWrapper.getBinding();

            if (image != null)
                image.setUrl(FormUtil.getMultimediaUrl() + "?action=recentbinary&time="
                        + new java.util.Date().getTime() + "&formId=" + formDef.getId() + "&xpath=" + xpath);
            else {
                String extension = "";//.3gp ".mpeg";
                String contentType = "&contentType=video/3gpp";
                if (widgetWrapper.getQuestionDef().getDataType() == QuestionType.AUDIO)
                    contentType = "&contentType=audio/3gpp"; //"&contentType=audio/x-wav";
                //extension = ".wav";

                contentType += "&name=" + widgetWrapper.getQuestionDef().getBinding() + ".3gp";

                html.setVisible(true);
                html.setHTML("<a href="
                        + URL.encode(FormUtil.getMultimediaUrl() + extension + "?formId=" + formDef.getId()
                                + "&xpath=" + xpath + contentType + "&time=" + new java.util.Date().getTime())
                        + ">" + html.getText() + "</a>");
            }

            widgetWrapper.getQuestionDef().setAnswer(contents);
        }
    }

    public void clearValue() {
        if (isRepeated) {
            while (table.getRowCount() > 1)
                table.removeRow(1);

            for (int col = 0; col < table.getCellCount(0) - 1; col++)
                ((RuntimeWidgetWrapper) table.getWidget(0, col)).clearValue();
        } else {
            for (int index = 0; index < selectedPanel.getWidgetCount(); index++)
                ((RuntimeWidgetWrapper) selectedPanel.getWidget(index)).clearValue();
        }
    }

    public boolean isValid() {
        firstInvalidWidget = null;

        if (isRepeated) {
            for (int row = 0; row < table.getRowCount(); row++) {
                for (int col = 0; col < table.getCellCount(row) - 1; col++) {
                    boolean valid = ((RuntimeWidgetWrapper) table.getWidget(row, col)).isValid();
                    if (!valid) {
                        firstInvalidWidget = (RuntimeWidgetWrapper) table.getWidget(row, col);
                        return false;
                    }
                }
            }
            return true;
        } else {
            boolean valid = true;
            for (int index = 0; index < selectedPanel.getWidgetCount(); index++) {
                RuntimeWidgetWrapper widget = (RuntimeWidgetWrapper) selectedPanel.getWidget(index);
                if (!widget.isValid()) {
                    valid = false;
                    if (firstInvalidWidget == null && widget.isFocusable())
                        firstInvalidWidget = widget.getInvalidWidget();
                }
            }
            return valid;
        }
    }

    public RuntimeWidgetWrapper getInvalidWidget() {
        if (firstInvalidWidget == null)
            return (RuntimeWidgetWrapper) getParent().getParent();
        return firstInvalidWidget;
    }

    public boolean setFocus() {
        if (isRepeated) {
            for (int row = 0; row < table.getRowCount(); row++) {
                for (int col = 0; col < table.getCellCount(row) - 1; col++) {
                    RuntimeWidgetWrapper widget = (RuntimeWidgetWrapper) table.getWidget(row, col);
                    if (widget.isFocusable()) {
                        widget.setFocus();
                        return true;
                    }
                }
            }
        } else {
            for (int index = 0; index < selectedPanel.getWidgetCount(); index++) {
                RuntimeWidgetWrapper widget = (RuntimeWidgetWrapper) selectedPanel.getWidget(index);
                if (widget.isFocusable()) {
                    widget.setFocus();
                    return true;
                }
            }
        }

        return false;
    }

    public boolean onMoveToNextWidget(Widget widget) {
        int index = selectedPanel.getWidgetIndex(widget);

        if (index == -1) {
            //Handle tabbing for repeats within the flex table
            if (isRepeated) {
                boolean found = false;
                for (int row = 0; row < table.getRowCount(); row++) {
                    for (int col = 0; col < table.getCellCount(row); col++) {
                        if (found) {
                            Widget curWidget = table.getWidget(row, col);
                            if (curWidget instanceof RuntimeWidgetWrapper
                                    && ((RuntimeWidgetWrapper) curWidget).setFocus())
                                return true;
                        }

                        if (table.getWidget(row, col) == widget)
                            found = true;
                    }
                }
            }

            return false;
        }

        return moveToNextWidget(index);
    }

    public boolean onMoveToPrevWidget(Widget widget) {
        int index = selectedPanel.getWidgetIndex(widget);
        while (--index > 0) {
            if (((RuntimeWidgetWrapper) selectedPanel.getWidget(index)).setFocus())
                return true;
        }

        return false;
    }

    protected boolean moveToNextWidget(int index) {
        while (++index < selectedPanel.getWidgetCount())
            if (((RuntimeWidgetWrapper) selectedPanel.getWidget(index)).setFocus()) {
                return true;
            }

        return false;
    }

    public HashMap<QuestionDef, List<Label>> getLabelMap() {
        return labelMap;
    }

    public HashMap<QuestionDef, List<RuntimeWidgetWrapper>> getCalcWidgetMap() {
        return calcWidgetMap;
    }

    public HashMap<QuestionDef, RuntimeWidgetWrapper> getFiltDynOptWidgetMap() {
        return filtDynOptWidgetMap;
    }

    public HashMap<Label, String> getLabelText() {
        return labelText;
    }

    public HashMap<Label, String> getLabelReplaceText() {
        return labelReplaceText;
    }

    public HashMap<QuestionDef, List<CheckBox>> getCheckBoxGroupMap() {
        return checkBoxGroupMap;
    }

    public void onEnabledChanged(QuestionDef sender, boolean enabled) {
        List<CheckBox> list = checkBoxGroupMap.get(sender);
        if (list == null)
            return;

        for (CheckBox checkBox : list) {
            checkBox.setEnabled(enabled);
            if (!enabled)
                checkBox.setValue(false);
        }
    }

    public void onVisibleChanged(QuestionDef sender, boolean visible) {
        List<CheckBox> list = checkBoxGroupMap.get(sender);
        if (list == null)
            return;

        for (CheckBox checkBox : list) {
            checkBox.setVisible(visible);
            if (!visible)
                checkBox.setValue(false);
        }
    }

    public void onRequiredChanged(QuestionDef sender, boolean required) {

    }

    public void onLockedChanged(QuestionDef sender, boolean locked) {

    }

    public void onBindingChanged(QuestionDef sender, String newValue) {

    }

    public void onDataTypeChanged(QuestionDef sender, QuestionType dataType) {

    }

    public void onOptionsChanged(QuestionDef sender, List<OptionDef> optionList) {

    }

    public int getHeightInt() {
        return getElement().getOffsetHeight();
    }

    /*private void workonDefaults(Node repeatDataNode){
       NodeList nodes = repeatDataNode.getChildNodes();
       for(int index = 0; index < nodes.getLength(); index++){
     Node child = nodes.item(index);
     if(child.getNodeType() != Node.ELEMENT_NODE)
        continue;
        
     if(XformConstants.XPATH_VALUE_FALSE.equals(((Element)child).getAttribute("default")))
        XmlUtil.setTextValue((Element)child, "");
        
     workonDefaults(child);
       }
    }*/
}