/*
        // 01/16/2006 Paul.  If we disable the validator, it will hide it's error message.
        // The solution may be to always require server-side validation (disable EnableClientScript).
        public static void DisableValidationEditViewFields(string sEDIT_NAME, Control parent)
        {
            DataTable dtFields = SplendidCache.EditViewFields(sEDIT_NAME);
            DataView dvFields = new DataView(dtFields);
            dvFields.RowFilter = "UI_REQUIRED = 1";
            foreach(DataRowView row in dvFields)
            {
                string sFIELD_TYPE        = Sql.ToString (row["FIELD_TYPE"       ]);
                string sDATA_FIELD        = Sql.ToString (row["DATA_FIELD"       ]);
                bool   bUI_REQUIRED       = Sql.ToBoolean(row["UI_REQUIRED"      ]);
                if ( bUI_REQUIRED && !Sql.IsEmptyString(sDATA_FIELD) )
                {
                    if ( String.Compare(sFIELD_TYPE, "DatePicker", true) == 0 )
                    {
                        DatePicker ctlDate = parent.FindControl(sDATA_FIELD) as DatePicker;
                        if ( ctlDate != null )
                            ctlDate.DisableValidation();
                    }
                    else if ( String.Compare(sFIELD_TYPE, "DateTimePicker", true) == 0 )
                    {
                        DateTimePicker ctlDate = parent.FindControl(sDATA_FIELD) as DateTimePicker;
                        if ( ctlDate != null )
                            ctlDate.DisableValidation();
                    }
                    else if ( String.Compare(sFIELD_TYPE, "DateTimeEdit", true) == 0 )
                    {
                        DateTimeEdit ctlDate = parent.FindControl(sDATA_FIELD) as DateTimeEdit;
                        if ( ctlDate != null )
                            ctlDate.DisableValidation();
                    }
                    else
                    {
                        BaseValidator req = parent.FindControl(sDATA_FIELD + "_REQUIRED") as BaseValidator;
                        if ( req != null )
                        {
                            // 01/16/2006 Paul.  Enable validator before validating page.
                            // If we leave the validator control enabled, then it may block an alternate action, like Cancel.
                            req.Enabled = false;
                        }
                    }
                }
            }
        }
        */
        public static void AppendEditViewFields(DataView dvFields, HtmlTable tbl, IDataReader rdr, L10N L10n, TimeZone T10n, CommandEventHandler Page_Command, bool bLayoutMode)
        {
            HtmlTableRow tr = null;
            // 11/28/2005 Paul.  Start row index using the existing count so that headers can be specified.
            int nRowIndex = tbl.Rows.Count - 1;
            int nColIndex = 0;
            HtmlTableCell tdLabel = null;
            HtmlTableCell tdField = null;
            // 01/07/2006 Paul.  Show table borders in layout mode. This will help distinguish blank lines from wrapped lines.
            if ( bLayoutMode )
                tbl.Border = 1;
            HttpSessionState Session = HttpContext.Current.Session;
            foreach(DataRowView row in dvFields)
            {
                Guid   gID                = Sql.ToGuid   (row["ID"               ]);
                int    nFIELD_INDEX       = Sql.ToInteger(row["FIELD_INDEX"      ]);
                string sFIELD_TYPE        = Sql.ToString (row["FIELD_TYPE"       ]);
                string sDATA_LABEL        = Sql.ToString (row["DATA_LABEL"       ]);
                string sDATA_FIELD        = Sql.ToString (row["DATA_FIELD"       ]);
                string sDISPLAY_FIELD     = Sql.ToString (row["DISPLAY_FIELD"    ]);
                string sCACHE_NAME        = Sql.ToString (row["CACHE_NAME"       ]);
                bool   bDATA_REQUIRED     = Sql.ToBoolean(row["DATA_REQUIRED"    ]);
                bool   bUI_REQUIRED       = Sql.ToBoolean(row["UI_REQUIRED"      ]);
                string sONCLICK_SCRIPT    = Sql.ToString (row["ONCLICK_SCRIPT"   ]);
                string sFORMAT_SCRIPT     = Sql.ToString (row["FORMAT_SCRIPT"    ]);
                short  nFORMAT_TAB_INDEX  = Sql.ToShort  (row["FORMAT_TAB_INDEX" ]);
                int    nFORMAT_MAX_LENGTH = Sql.ToInteger(row["FORMAT_MAX_LENGTH"]);
                int    nFORMAT_SIZE       = Sql.ToInteger(row["FORMAT_SIZE"      ]);
                int    nFORMAT_ROWS       = Sql.ToInteger(row["FORMAT_ROWS"      ]);
                int    nFORMAT_COLUMNS    = Sql.ToInteger(row["FORMAT_COLUMNS"   ]);
                int    nCOLSPAN           = Sql.ToInteger(row["COLSPAN"          ]);
                int    nROWSPAN           = Sql.ToInteger(row["ROWSPAN"          ]);
                string sLABEL_WIDTH       = Sql.ToString (row["LABEL_WIDTH"      ]);
                string sFIELD_WIDTH       = Sql.ToString (row["FIELD_WIDTH"      ]);
                // 12/02/2005 Paul. COLSPAN == -1 means that a new column should not be created.
                if ( (nCOLSPAN >= 0 && nColIndex == 0) || tr == null )
                {
                    // 11/25/2005 Paul.  Don't pre-create a row as we don't want a blank
                    // row at the bottom.  Add rows just before they are needed.
                    nRowIndex++;
                    tr = new HtmlTableRow();
                    tbl.Rows.Insert(nRowIndex, tr);
                }
                if ( bLayoutMode )
                {
                    HtmlTableCell tdAction = new HtmlTableCell();
                    tr.Cells.Add(tdAction);
                    tdAction.Attributes.Add("class", "tabDetailViewDL");
                    tdAction.NoWrap = true;

                    Literal litIndex = new Literal();
                    tdAction.Controls.Add(litIndex);
                    litIndex.Text = " " + nFIELD_INDEX.ToString() + " ";

                    ImageButton btnMoveUp   = CreateLayoutImageButton(gID, "Layout.MoveUp"  , nFIELD_INDEX, L10n.Term(".LNK_UP"    ), Sql.ToString(Session["themeURL"]) + "images/uparrow_inline.gif"  , Page_Command);
                    ImageButton btnMoveDown = CreateLayoutImageButton(gID, "Layout.MoveDown", nFIELD_INDEX, L10n.Term(".LNK_DOWN"  ), Sql.ToString(Session["themeURL"]) + "images/downarrow_inline.gif", Page_Command);
                    ImageButton btnInsert   = CreateLayoutImageButton(gID, "Layout.Insert"  , nFIELD_INDEX, L10n.Term(".LNK_INS"   ), Sql.ToString(Session["themeURL"]) + "images/plus_inline.gif"     , Page_Command);
                    ImageButton btnEdit     = CreateLayoutImageButton(gID, "Layout.Edit"    , nFIELD_INDEX, L10n.Term(".LNK_EDIT"  ), Sql.ToString(Session["themeURL"]) + "images/edit_inline.gif"     , Page_Command);
                    ImageButton btnDelete   = CreateLayoutImageButton(gID, "Layout.Delete"  , nFIELD_INDEX, L10n.Term(".LNK_DELETE"), Sql.ToString(Session["themeURL"]) + "images/delete_inline.gif"   , Page_Command);
                    tdAction.Controls.Add(btnMoveUp  );
                    tdAction.Controls.Add(btnMoveDown);
                    tdAction.Controls.Add(btnInsert  );
                    tdAction.Controls.Add(btnEdit    );
                    tdAction.Controls.Add(btnDelete  );
                }
                if ( nCOLSPAN >= 0 || tdLabel == null || tdField == null )
                {
                    tdLabel = new HtmlTableCell();
                    tdField = new HtmlTableCell();
                    tr.Cells.Add(tdLabel);
                    tr.Cells.Add(tdField);
                    if ( nCOLSPAN > 0 )
                    {
                        tdField.ColSpan = nCOLSPAN;
                        if ( bLayoutMode )
                            tdField.ColSpan++;
                    }
                    tdLabel.Attributes.Add("class", "dataLabel");
                    tdLabel.VAlign = "top";
                    tdLabel.Width  = sLABEL_WIDTH;
                    tdField.Attributes.Add("class", "dataField");
                    tdField.VAlign = "top";
                    // 11/28/2005 Paul.  Don't use the field width if COLSPAN is specified as we want it to take the rest of the table.  The label width will be sufficient.
                    if ( nCOLSPAN == 0 )
                        tdField.Width  = sFIELD_WIDTH;

                    Literal   litLabel = new Literal();
                    tdLabel.Controls.Add(litLabel);
                    //litLabel.Text = nFIELD_INDEX.ToString() + " (" + nRowIndex.ToString() + "," + nColIndex.ToString() + ")";
                    try
                    {
                        if ( bLayoutMode )
                        {
                            if ( String.Compare(sFIELD_TYPE, "Blank", true) == 0 )
                                litLabel.Text = "*** BLANK ***";
                            else
                                litLabel.Text = sDATA_LABEL;
                        }
                        else if ( sDATA_LABEL.IndexOf(".") >= 0 )
                            litLabel.Text = L10n.Term(sDATA_LABEL);
                        else if ( !Sql.IsEmptyString(sDATA_LABEL) && rdr != null )
                            litLabel.Text = Sql.ToString(rdr[sDATA_LABEL]) + L10n.Term("Calls.LBL_COLON");
                        // 07/15/2006 Paul.  Always put something for the label so that table borders will look right.
                        else
                            litLabel.Text = " ";
                    }
                    catch(Exception ex)
                    {
                        SplendidError.SystemWarning(new StackTrace(true).GetFrame(0), ex.Message);
                        litLabel.Text = ex.Message;
                    }
                    if ( !bLayoutMode && bUI_REQUIRED )
                    {
                        Label lblRequired = new Label();
                        tdLabel.Controls.Add(lblRequired);
                        lblRequired.CssClass = "required";
                        lblRequired.Text = L10n.Term(".LBL_REQUIRED_SYMBOL");
                    }
                }

                if ( String.Compare(sFIELD_TYPE, "Blank", true) == 0 )
                {
                    Literal litField = new Literal();
                    tdField.Controls.Add(litField);
                    if ( bLayoutMode )
                        litField.Text = "*** BLANK ***";
                    else
                        litField.Text = " ";
                }
                else if ( String.Compare(sFIELD_TYPE, "Label", true) == 0 )
                {
                    if ( !Sql.IsEmptyString(sDATA_FIELD) )
                    {
                        Literal litField = new Literal();
                        tdField.Controls.Add(litField);
                        // 07/25/2006 Paul.  Align label values to the middle so the line-up with the label.
                        tdField.VAlign = "middle";
                        // 07/24/2006 Paul.  Set the ID so that the literal control can be accessed.
                        litField.ID = sDATA_FIELD;
                        try
                        {
                            if ( bLayoutMode )
                                litField.Text = sDATA_FIELD;
                            else if ( sDATA_FIELD.IndexOf(".") >= 0 )
                                litField.Text = L10n.Term(sDATA_FIELD);
                            else if ( rdr != null )
                                litField.Text = Sql.ToString(rdr[sDATA_FIELD]);
                        }
                        catch(Exception ex)
                        {
                            SplendidError.SystemWarning(new StackTrace(true).GetFrame(0), ex.Message);
                            litField.Text = ex.Message;
                        }
                    }
                }
                else if ( String.Compare(sFIELD_TYPE, "ListBox", true) == 0 )
                {
                    if ( !Sql.IsEmptyString(sDATA_FIELD) )
                    {
                        DropDownList lstField = new DropDownList();
                        tdField.Controls.Add(lstField);
                        lstField.ID       = sDATA_FIELD;
                        lstField.TabIndex = nFORMAT_TAB_INDEX;
                        try
                        {
                            if ( !Sql.IsEmptyString(sDATA_FIELD) )
                            {
                                // 12/04/2005 Paul.  Don't populate list if this is a post back.
                                if ( !Sql.IsEmptyString(sCACHE_NAME) && (bLayoutMode || !tbl.Page.IsPostBack) )
                                {
                                    switch ( sCACHE_NAME )
                                    {
                                        case "AssignedUser":
                                            lstField.DataValueField = "ID"       ;
                                            lstField.DataTextField  = "USER_NAME";
                                            lstField.DataSource     = SplendidCache.AssignedUser();
                                            break;
                                        case "Currencies":
                                            lstField.DataValueField = "ID"         ;
                                            lstField.DataTextField  = "NAME_SYMBOL";
                                            lstField.DataSource     = SplendidCache.Currencies();
                                            break;
                                        case "Release":
                                            lstField.DataValueField = "ID"  ;
                                            lstField.DataTextField  = "NAME";
                                            lstField.DataSource     = SplendidCache.Release();
                                            break;
                                        case "Manufacturers":
                                            lstField.DataValueField = "ID"  ;
                                            lstField.DataTextField  = "NAME";
                                            lstField.DataSource     = SplendidCache.Manufacturers();
                                            break;
                                        case "Shippers":
                                            lstField.DataValueField = "ID"  ;
                                            lstField.DataTextField  = "NAME";
                                            lstField.DataSource     = SplendidCache.Shippers();
                                            break;
                                        case "ProductTypes":
                                            lstField.DataValueField = "ID"  ;
                                            lstField.DataTextField  = "NAME";
                                            lstField.DataSource     = SplendidCache.ProductTypes();
                                            break;
                                        case "ProductCategories":
                                            lstField.DataValueField = "ID"  ;
                                            lstField.DataTextField  = "NAME";
                                            lstField.DataSource     = SplendidCache.ProductCategories();
                                            break;
                                        case "ContractTypes":
                                            lstField.DataValueField = "ID"  ;
                                            lstField.DataTextField  = "NAME";
                                            lstField.DataSource     = SplendidCache.ContractTypes();
                                            break;
                                        default:
                                            lstField.DataValueField = "NAME"        ;
                                            lstField.DataTextField  = "DISPLAY_NAME";
                                            lstField.DataSource     = SplendidCache.List(sCACHE_NAME);
                                            break;
                                    }
                                    lstField.DataBind();
                                    // 08/08/2006 Paul.  Allow onchange code to be stored in the database.
                                    // ListBoxes do not have a useful onclick event, so there should be no problem overloading this field.
                                    if ( !Sql.IsEmptyString(sONCLICK_SCRIPT) )
                                        lstField.Attributes.Add("onchange" , sONCLICK_SCRIPT);
                                    // 02/21/2006 Paul.  Move the NONE item inside the !IsPostBack code.
                                    if ( !bUI_REQUIRED )
                                        lstField.Items.Insert(0, new ListItem(L10n.Term(".LBL_NONE"), ""));
                                }
                                if ( rdr != null )
                                {
                                    try
                                    {
                                        // 02/21/2006 Paul.  All the DropDownLists in the Calls and Meetings edit views were not getting set.
                                        // The problem was a Page.DataBind in the SchedulingGrid and in the InviteesView. Both binds needed to be removed.
                                        lstField.SelectedValue = Sql.ToString(rdr[sDATA_FIELD]);
                                    }
                                    catch(Exception ex)
                                    {
                                        SplendidError.SystemWarning(new StackTrace(true).GetFrame(0), ex.Message);
                                    }
                                }
                                    // 12/04/2005 Paul.  Assigned To field will always default to the current user.
                                else if ( rdr == null && !tbl.Page.IsPostBack && sCACHE_NAME == "AssignedUser")
                                {
                                    try
                                    {
                                        lstField.SelectedValue = Security.USER_ID.ToString();
                                    }
                                    catch(Exception ex)
                                    {
                                        SplendidError.SystemWarning(new StackTrace(true).GetFrame(0), ex.Message);
                                    }
                                }
                            }
                        }
                        catch(Exception ex)
                        {
                            SplendidError.SystemWarning(new StackTrace(true).GetFrame(0), ex.Message);
                        }
                        if ( bLayoutMode )
                        {
                            Literal litField = new Literal();
                            litField.Text = sDATA_FIELD;
                            tdField.Controls.Add(litField);
                        }
                    }
                }
                else if ( String.Compare(sFIELD_TYPE, "CheckBox", true) == 0 )
                {
                    if ( !Sql.IsEmptyString(sDATA_FIELD) )
                    {
                        CheckBox chkField = new CheckBox();
                        tdField.Controls.Add(chkField);
                        chkField.ID = sDATA_FIELD;
                        chkField.CssClass = "checkbox";
                        chkField.TabIndex = nFORMAT_TAB_INDEX;
                        try
                        {
                            if ( rdr != null )
                                chkField.Checked = Sql.ToBoolean(rdr[sDATA_FIELD]);
                        }
                        catch(Exception ex)
                        {
                            SplendidError.SystemWarning(new StackTrace(true).GetFrame(0), ex.Message);
                        }
                        if ( bLayoutMode )
                        {
                            Literal litField = new Literal();
                            litField.Text = sDATA_FIELD;
                            tdField.Controls.Add(litField);
                            chkField.Enabled  = false     ;
                        }
                    }
                }
                else if ( String.Compare(sFIELD_TYPE, "ChangeButton", true) == 0 )
                {
                    if ( !Sql.IsEmptyString(sDATA_FIELD) )
                    {
                        // 12/04/2005 Paul.  If the label is PARENT_TYPE, then change the label to a DropDownList.
                        if ( sDATA_LABEL == "PARENT_TYPE" )
                        {
                            tdLabel.Controls.Clear();
                            DropDownList lstField = new DropDownList();
                            tdLabel.Controls.Add(lstField);
                            lstField.ID       = sDATA_LABEL;
                            lstField.TabIndex = nFORMAT_TAB_INDEX;
                            lstField.Attributes.Add("onChange", "ChangeParentType();");
                            if ( bLayoutMode || !tbl.Page.IsPostBack )
                            {
                                // 07/29/2005 Paul.  SugarCRM 3.0 does not allow the NONE option.
                                lstField.DataValueField = "NAME"        ;
                                lstField.DataTextField  = "DISPLAY_NAME";
                                lstField.DataSource     = SplendidCache.List("record_type_display");
                                lstField.DataBind();
                                if ( rdr != null )
                                {
                                    try
                                    {
                                        lstField.SelectedValue = Sql.ToString(rdr[sDATA_LABEL]);
                                    }
                                    catch(Exception ex)
                                    {
                                        SplendidError.SystemWarning(new StackTrace(true).GetFrame(0), ex.Message);
                                    }
                                }
                            }
                        }
                        TextBox txtNAME = new TextBox();
                        tdField.Controls.Add(txtNAME);
                        txtNAME.ID       = sDISPLAY_FIELD;
                        txtNAME.ReadOnly = true;
                        txtNAME.TabIndex = nFORMAT_TAB_INDEX;
                        try
                        {
                            if ( bLayoutMode )
                            {
                                txtNAME.Text    = sDISPLAY_FIELD;
                                txtNAME.Enabled = false         ;
                            }
                            else if ( !Sql.IsEmptyString(sDISPLAY_FIELD) && rdr != null )
                                txtNAME.Text = Sql.ToString(rdr[sDISPLAY_FIELD]);
                        }
                        catch(Exception ex)
                        {
                            SplendidError.SystemWarning(new StackTrace(true).GetFrame(0), ex.Message);
                            txtNAME.Text = ex.Message;
                        }
                        HtmlInputHidden hidID = new HtmlInputHidden();
                        tdField.Controls.Add(hidID);
                        hidID.ID = sDATA_FIELD;
                        try
                        {
                            if ( !Sql.IsEmptyString(sDATA_FIELD) && rdr != null )
                                hidID.Value = Sql.ToString(rdr[sDATA_FIELD]);
                        }
                        catch(Exception ex)
                        {
                            SplendidError.SystemWarning(new StackTrace(true).GetFrame(0), ex.Message);
                            txtNAME.Text = ex.Message;
                        }

                        Literal litNBSP = new Literal();
                        tdField.Controls.Add(litNBSP);
                        litNBSP.Text = " ";

                        HtmlInputButton btnChange = new HtmlInputButton("button");
                        tdField.Controls.Add(btnChange);
                        // 05/07/2006 Paul.  Specify a name for the check button so that it can be referenced by SplendidTest.
                        btnChange.ID = sDATA_FIELD + "_btnChange";
                        btnChange.Attributes.Add("class", "button");
                        if ( !Sql.IsEmptyString(sONCLICK_SCRIPT) )
                            btnChange.Attributes.Add("onclick"  , sONCLICK_SCRIPT);
                        btnChange.Attributes.Add("title"    , L10n.Term(".LBL_CHANGE_BUTTON_TITLE"));
                        // 07/31/2006 Paul.  Stop using VisualBasic library to increase compatibility with Mono.
                        btnChange.Attributes.Add("accessKey", L10n.Term(".LBL_CHANGE_BUTTON_KEY").Substring(0, 1));
                        btnChange.Value = L10n.Term(".LBL_CHANGE_BUTTON_LABEL");
                        if ( !bLayoutMode && bUI_REQUIRED && !Sql.IsEmptyString(sDATA_FIELD) )
                        {
                            RequiredFieldValidatorForHiddenInputs reqID = new RequiredFieldValidatorForHiddenInputs();
                            reqID.ID                 = sDATA_FIELD + "_REQUIRED";
                            reqID.ControlToValidate  = hidID.ID;
                            reqID.ErrorMessage       = L10n.Term(".ERR_REQUIRED_FIELD");
                            reqID.CssClass           = "required";
                            reqID.EnableViewState    = false;
                            // 01/16/2006 Paul.  We don't enable required fields until we attempt to save.
                            // This is to allow unrelated form actions; the Cancel button is a good example.
                            reqID.EnableClientScript = false;
                            reqID.Enabled            = false;
                            tdField.Controls.Add(reqID);
                        }
                    }
                }
                else if ( String.Compare(sFIELD_TYPE, "TextBox", true) == 0 || String.Compare(sFIELD_TYPE, "Password", true) == 0 )
                {
                    if ( !Sql.IsEmptyString(sDATA_FIELD) )
                    {
                        TextBox txtField = new TextBox();
                        tdField.Controls.Add(txtField);
                        txtField.ID       = sDATA_FIELD;
                        txtField.TabIndex = nFORMAT_TAB_INDEX;
                        try
                        {
                            if ( nFORMAT_ROWS > 0 && nFORMAT_COLUMNS > 0 )
                            {
                                txtField.Rows     = nFORMAT_ROWS   ;
                                txtField.Columns  = nFORMAT_COLUMNS;
                                txtField.TextMode = TextBoxMode.MultiLine;
                            }
                            else
                            {
                                txtField.MaxLength = nFORMAT_MAX_LENGTH   ;
                                txtField.Attributes.Add("size", nFORMAT_SIZE.ToString());
                                txtField.TextMode  = TextBoxMode.SingleLine;
                            }
                            if ( bLayoutMode )
                            {
                                txtField.Text     = sDATA_FIELD;
                                txtField.ReadOnly = true       ;
                            }
                            else if ( !Sql.IsEmptyString(sDATA_FIELD) && rdr != null )
                            {
                                int    nOrdinal  = rdr.GetOrdinal(sDATA_FIELD);
                                string sTypeName = rdr.GetDataTypeName(nOrdinal);
                                // 03/04/2006 Paul.  Display currency in the proper format.
                                // Only SQL Server is likely to return the money type, so also include the decimal type.
                                if ( sTypeName == "money" || rdr[sDATA_FIELD].GetType() == typeof(System.Decimal) )
                                    txtField.Text = Sql.ToDecimal(rdr[sDATA_FIELD]).ToString("#,##0.00");
                                else
                                    txtField.Text = Sql.ToString(rdr[sDATA_FIELD]);
                            }
                        }
                        catch(Exception ex)
                        {
                            SplendidError.SystemWarning(new StackTrace(true).GetFrame(0), ex.Message);
                            txtField.Text = ex.Message;
                        }
                        if ( String.Compare(sFIELD_TYPE, "Password", true) == 0 )
                            txtField.TextMode = TextBoxMode.Password;
                        if ( !bLayoutMode && bUI_REQUIRED && !Sql.IsEmptyString(sDATA_FIELD) )
                        {
                            RequiredFieldValidator reqNAME = new RequiredFieldValidator();
                            reqNAME.ID                 = sDATA_FIELD + "_REQUIRED";
                            reqNAME.ControlToValidate  = txtField.ID;
                            reqNAME.ErrorMessage       = L10n.Term(".ERR_REQUIRED_FIELD");
                            reqNAME.CssClass           = "required";
                            reqNAME.EnableViewState    = false;
                            // 01/16/2006 Paul.  We don't enable required fields until we attempt to save.
                            // This is to allow unrelated form actions; the Cancel button is a good example.
                            reqNAME.EnableClientScript = false;
                            reqNAME.Enabled            = false;
                            tdField.Controls.Add(reqNAME);
                        }
                    }
                }
                else if ( String.Compare(sFIELD_TYPE, "DatePicker", true) == 0 )
                {
                    if ( !Sql.IsEmptyString(sDATA_FIELD) )
                    {
                        // 12/03/2005 Paul.  UserControls must be loaded.
                        DatePicker ctlDate = tbl.Page.LoadControl("~/_controls/DatePicker.ascx") as DatePicker;
                        tdField.Controls.Add(ctlDate);
                        ctlDate.ID = sDATA_FIELD;
                        // 05/10/2006 Paul.  Set the tab index.
                        ctlDate.TabIndex = nFORMAT_TAB_INDEX;
                        try
                        {
                            if ( rdr != null )
                                ctlDate.Value = T10n.FromServerTime(rdr[sDATA_FIELD]);
                        }
                        catch(Exception ex)
                        {
                            SplendidError.SystemWarning(new StackTrace(true).GetFrame(0), ex.Message);
                        }
                        // 01/16/2006 Paul.  We validate elsewhere.
                        /*
                        if ( !bLayoutMode && bUI_REQUIRED && !Sql.IsEmptyString(sDATA_FIELD) )
                        {
                            ctlDate.Required = true;
                        }
                        */
                        if ( bLayoutMode )
                        {
                            Literal litField = new Literal();
                            litField.Text = sDATA_FIELD;
                            tdField.Controls.Add(litField);
                        }
                    }
                }
                else if ( String.Compare(sFIELD_TYPE, "DateTimePicker", true) == 0 )
                {
                    if ( !Sql.IsEmptyString(sDATA_FIELD) )
                    {
                        // 12/03/2005 Paul.  UserControls must be loaded.
                        DateTimePicker ctlDate = tbl.Page.LoadControl("~/_controls/DateTimePicker.ascx") as DateTimePicker;
                        tdField.Controls.Add(ctlDate);
                        ctlDate.ID = sDATA_FIELD;
                        // 05/10/2006 Paul.  Set the tab index.
                        ctlDate.TabIndex = nFORMAT_TAB_INDEX;
                        try
                        {
                            if ( rdr != null )
                                ctlDate.Value = T10n.FromServerTime(rdr[sDATA_FIELD]);
                        }
                        catch(Exception ex)
                        {
                            SplendidError.SystemWarning(new StackTrace(true).GetFrame(0), ex.Message);
                        }
                        if ( bLayoutMode )
                        {
                            Literal litField = new Literal();
                            litField.Text = sDATA_FIELD;
                            tdField.Controls.Add(litField);
                        }
                    }
                }
                else if ( String.Compare(sFIELD_TYPE, "DateTimeEdit", true) == 0 )
                {
                    if ( !Sql.IsEmptyString(sDATA_FIELD) )
                    {
                        // 12/03/2005 Paul.  UserControls must be loaded.
                        DateTimeEdit ctlDate = tbl.Page.LoadControl("~/_controls/DateTimeEdit.ascx") as DateTimeEdit;
                        tdField.Controls.Add(ctlDate);
                        ctlDate.ID = sDATA_FIELD;
                        // 05/10/2006 Paul.  Set the tab index.
                        ctlDate.TabIndex = nFORMAT_TAB_INDEX;
                        try
                        {
                            if ( rdr != null )
                                ctlDate.Value = T10n.FromServerTime(rdr[sDATA_FIELD]);
                        }
                        catch(Exception ex)
                        {
                            SplendidError.SystemWarning(new StackTrace(true).GetFrame(0), ex.Message);
                        }
                        if ( !bLayoutMode && bUI_REQUIRED )
                        {
                            ctlDate.EnableNone = false;
                        }
                        if ( bLayoutMode )
                        {
                            Literal litField = new Literal();
                            litField.Text = sDATA_FIELD;
                            tdField.Controls.Add(litField);
                        }
                    }
                }
                else if ( String.Compare(sFIELD_TYPE, "File", true) == 0 )
                {
                    if ( !Sql.IsEmptyString(sDATA_FIELD) )
                    {
                        HtmlInputFile ctlField = new HtmlInputFile();
                        tdField.Controls.Add(ctlField);
                        ctlField.ID        = sDATA_FIELD;
                        ctlField.MaxLength = nFORMAT_MAX_LENGTH;
                        ctlField.Size      = nFORMAT_SIZE;
                        ctlField.Attributes.Add("TabIndex", nFORMAT_TAB_INDEX.ToString());
                        if ( !bLayoutMode && bUI_REQUIRED )
                        {
                            RequiredFieldValidator reqNAME = new RequiredFieldValidator();
                            reqNAME.ID                 = sDATA_FIELD + "_REQUIRED";
                            reqNAME.ControlToValidate  = ctlField.ID;
                            reqNAME.ErrorMessage       = L10n.Term(".ERR_REQUIRED_FIELD");
                            reqNAME.CssClass           = "required";
                            reqNAME.EnableViewState    = false;
                            // 01/16/2006 Paul.  We don't enable required fields until we attempt to save.
                            // This is to allow unrelated form actions; the Cancel button is a good example.
                            reqNAME.EnableClientScript = false;
                            reqNAME.Enabled            = false;
                            tdField.Controls.Add(reqNAME);
                        }
                    }
                }
                else if ( String.Compare(sFIELD_TYPE, "Image", true) == 0 )
                {
                    if ( !Sql.IsEmptyString(sDATA_FIELD) )
                    {
                        HtmlInputHidden ctlHidden = new HtmlInputHidden();
                        if ( !bLayoutMode )
                        {
                            tdField.Controls.Add(ctlHidden);
                            ctlHidden.ID = sDATA_FIELD;

                            HtmlInputFile ctlField = new HtmlInputFile();
                            tdField.Controls.Add(ctlField);
                            // 04/17/2006 Paul.  The image needs to reference the file control.
                            ctlField.ID = sDATA_FIELD + "_File";

                            Literal litBR = new Literal();
                            litBR.Text = "<br />";
                            tdField.Controls.Add(litBR);
                        }

                        Image imgField = new Image();
                        // 04/13/2006 Paul.  Give the image a name so that it can be validated with SplendidTest.
                        imgField.ID = "img" + sDATA_FIELD;
                        try
                        {
                            if ( bLayoutMode )
                            {
                                Literal litField = new Literal();
                                litField.Text = sDATA_FIELD;
                                tdField.Controls.Add(litField);
                            }
                            else if ( rdr != null )
                            {
                                if ( !Sql.IsEmptyString(rdr[sDATA_FIELD]) )
                                {
                                    ctlHidden.Value = Sql.ToString(rdr[sDATA_FIELD]);
                                    imgField.ImageUrl = "~/Images/Image.aspx?ID=" + ctlHidden.Value;
                                    // 04/13/2006 Paul.  Only add the image if it exists.
                                    tdField.Controls.Add(imgField);

                                    // 04/17/2006 Paul.  Provide a clear button.
                                    Literal litClear = new Literal();
                                    litClear.Text = "<br /><input type=\"button\" class=\"button\" onclick=\"form." + ctlHidden.ClientID + ".value='';form." + imgField.ClientID + ".src='';" + "\"  value='" + "  " + L10n.Term(".LBL_CLEAR_BUTTON_LABEL" ) + "  " + "' title='" + L10n.Term(".LBL_CLEAR_BUTTON_TITLE" ) + "' />";
                                    tdField.Controls.Add(litClear);
                                }
                            }
                        }
                        catch(Exception ex)
                        {
                            SplendidError.SystemWarning(new StackTrace(true).GetFrame(0), ex.Message);
                            Literal litField = new Literal();
                            litField.Text = ex.Message;
                            tdField.Controls.Add(litField);
                        }
                    }
                }
                else if ( String.Compare(sFIELD_TYPE, "AddressButtons", true) == 0 )
                {
                    tr.Cells.Remove(tdField);
                    tdLabel.Width = "10%";
                    tdLabel.RowSpan = nROWSPAN;
                    tdLabel.VAlign  = "middle";
                    tdLabel.Align   = "center";
                    tdLabel.Attributes.Remove("class");
                    tdLabel.Attributes.Add("class", "tabFormAddDel");
                    HtmlInputButton btnCopyRight = new HtmlInputButton("button");
                    Literal         litSpacer    = new Literal();
                    HtmlInputButton btnCopyLeft  = new HtmlInputButton("button");
                    tdLabel.Controls.Add(btnCopyRight);
                    tdLabel.Controls.Add(litSpacer   );
                    tdLabel.Controls.Add(btnCopyLeft );
                    btnCopyRight.Attributes.Add("title"  , L10n.Term("Accounts.NTC_COPY_BILLING_ADDRESS" ));
                    btnCopyRight.Attributes.Add("onclick", "return copyAddressRight()");
                    btnCopyRight.Value = ">>";
                    litSpacer.Text = "<br><br>";
                    btnCopyLeft .Attributes.Add("title"  , L10n.Term("Accounts.NTC_COPY_SHIPPING_ADDRESS" ));
                    btnCopyLeft .Attributes.Add("onclick", "return copyAddressLeft()");
                    btnCopyLeft .Value = "<<";
                    nColIndex = 0;
                }
                else
                {
                    Literal litField = new Literal();
                    tdField.Controls.Add(litField);
                    litField.Text = "Unknown field type " + sFIELD_TYPE;
                    SplendidError.SystemWarning(new StackTrace(true).GetFrame(0), "Unknown field type " + sFIELD_TYPE);
                }
                if ( nCOLSPAN > 0 )
                    nColIndex = 0;
                else if ( nCOLSPAN == 0 )
                {
                    nColIndex++;
                    if ( nColIndex > 1 )
                        nColIndex = 0;
                }
            }
        }
        public static void AppendEditViewFields(DataView dvFields, HtmlTable tbl, IDataReader rdr, L10N L10n, TimeZone T10n, CommandEventHandler Page_Command, bool bLayoutMode)
        {
            bool bIsMobile = false;
            SplendidPage Page = tbl.Page as SplendidPage;
            if ( Page != null )
                bIsMobile = Page.IsMobile;

            HtmlTableRow tr = null;
            // 11/28/2005 Paul.  Start row index using the existing count so that headers can be specified.
            int nRowIndex = tbl.Rows.Count - 1;
            int nColIndex = 0;
            HtmlTableCell tdLabel = null;
            HtmlTableCell tdField = null;
            // 01/07/2006 Paul.  Show table borders in layout mode. This will help distinguish blank lines from wrapped lines.
            if ( bLayoutMode )
                tbl.Border = 1;
            // 11/15/2007 Paul.  If there are no fields in the detail view, then hide the entire table.
            // This allows us to hide the table by removing all detail view fields.
            if ( dvFields.Count == 0 && tbl.Rows.Count <= 1 )
                tbl.Visible = false;

            // 01/27/2008 Paul.  We need the schema table to determine if the data label is free-form text.
            DataTable tblSchema = null;
            if ( rdr != null )
                tblSchema = rdr.GetSchemaTable();
            // 01/01/2008 Paul.  Pull config flag outside the loop.
            bool bEnableTeamManagement  = Crm.Config.enable_team_management();
            bool bRequireTeamManagement = Crm.Config.require_team_management();
            // 01/01/2008 Paul.  We need a quick way to require user assignments across the system.
            bool bRequireUserAssignment = Crm.Config.require_user_assignment();
            HttpSessionState Session = HttpContext.Current.Session;
            foreach(DataRowView row in dvFields)
            {
                Guid   gID                = Sql.ToGuid   (row["ID"               ]);
                int    nFIELD_INDEX       = Sql.ToInteger(row["FIELD_INDEX"      ]);
                string sFIELD_TYPE        = Sql.ToString (row["FIELD_TYPE"       ]);
                string sDATA_LABEL        = Sql.ToString (row["DATA_LABEL"       ]);
                string sDATA_FIELD        = Sql.ToString (row["DATA_FIELD"       ]);
                string sDISPLAY_FIELD     = Sql.ToString (row["DISPLAY_FIELD"    ]);
                string sCACHE_NAME        = Sql.ToString (row["CACHE_NAME"       ]);
                bool   bDATA_REQUIRED     = Sql.ToBoolean(row["DATA_REQUIRED"    ]);
                bool   bUI_REQUIRED       = Sql.ToBoolean(row["UI_REQUIRED"      ]);
                string sONCLICK_SCRIPT    = Sql.ToString (row["ONCLICK_SCRIPT"   ]);
                string sFORMAT_SCRIPT     = Sql.ToString (row["FORMAT_SCRIPT"    ]);
                short  nFORMAT_TAB_INDEX  = Sql.ToShort  (row["FORMAT_TAB_INDEX" ]);
                int    nFORMAT_MAX_LENGTH = Sql.ToInteger(row["FORMAT_MAX_LENGTH"]);
                int    nFORMAT_SIZE       = Sql.ToInteger(row["FORMAT_SIZE"      ]);
                int    nFORMAT_ROWS       = Sql.ToInteger(row["FORMAT_ROWS"      ]);
                int    nFORMAT_COLUMNS    = Sql.ToInteger(row["FORMAT_COLUMNS"   ]);
                int    nCOLSPAN           = Sql.ToInteger(row["COLSPAN"          ]);
                int    nROWSPAN           = Sql.ToInteger(row["ROWSPAN"          ]);
                string sLABEL_WIDTH       = Sql.ToString (row["LABEL_WIDTH"      ]);
                string sFIELD_WIDTH       = Sql.ToString (row["FIELD_WIDTH"      ]);
                int    nDATA_COLUMNS      = Sql.ToInteger(row["DATA_COLUMNS"     ]);
                // 12/02/2007 Paul.  Each view can now have its own number of data columns.
                // This was needed so that search forms can have 4 data columns. The default is 2 columns.
                if ( nDATA_COLUMNS == 0 )
                    nDATA_COLUMNS = 2;
                // 11/25/2006 Paul.  If Team Management has been disabled, then convert the field to a blank.
                // Keep the field, but treat it as blank so that field indexes will still be valid.
                // 12/03/2006 Paul.  Allow the team field to be visible during layout.
                if ( !bLayoutMode && sDATA_FIELD == "TEAM_ID" )
                {
                    if ( !bEnableTeamManagement )
                    {
                        sFIELD_TYPE = "Blank";
                        bUI_REQUIRED = false;
                    }
                    else
                    {
                        // 11/25/2006 Paul.  Override the required flag with the system value.
                        // 01/01/2008 Paul.  If Team Management is not required, then let the admin decide.
                        if ( bRequireTeamManagement )
                            bUI_REQUIRED = true;
                    }
                }
                if ( !bLayoutMode && sDATA_FIELD == "ASSIGNED_USER_ID" )
                {
                    // 01/01/2008 Paul.  We need a quick way to require user assignments across the system.
                    if ( bRequireUserAssignment )
                        bUI_REQUIRED = true;
                }
                if ( bIsMobile && String.Compare(sFIELD_TYPE, "AddressButtons", true) == 0 )
                {
                    // 11/17/2007 Paul.  Skip the address buttons on a mobile device.
                    continue;
                }
                // 11/17/2007 Paul.  On a mobile device, each new field is on a new row.
                // 12/02/2005 Paul. COLSPAN == -1 means that a new column should not be created.
                if ( (nCOLSPAN >= 0 && nColIndex == 0) || tr == null || bIsMobile )
                {
                    // 11/25/2005 Paul.  Don't pre-create a row as we don't want a blank
                    // row at the bottom.  Add rows just before they are needed.
                    nRowIndex++;
                    tr = new HtmlTableRow();
                    tbl.Rows.Insert(nRowIndex, tr);
                }
                if ( bLayoutMode )
                {
                    HtmlTableCell tdAction = new HtmlTableCell();
                    tr.Cells.Add(tdAction);
                    tdAction.Attributes.Add("class", "tabDetailViewDL");
                    tdAction.NoWrap = true;

                    Literal litIndex = new Literal();
                    tdAction.Controls.Add(litIndex);
                    litIndex.Text = " " + nFIELD_INDEX.ToString() + " ";

                    // 05/26/2007 Paul.  Fix the terms. The are in the Dropdown module.
                    ImageButton btnMoveUp   = CreateLayoutImageButton(gID, "Layout.MoveUp"  , nFIELD_INDEX, L10n.Term("Dropdown.LNK_UP"    ), Sql.ToString(Session["themeURL"]) + "images/uparrow_inline.gif"  , Page_Command);
                    ImageButton btnMoveDown = CreateLayoutImageButton(gID, "Layout.MoveDown", nFIELD_INDEX, L10n.Term("Dropdown.LNK_DOWN"  ), Sql.ToString(Session["themeURL"]) + "images/downarrow_inline.gif", Page_Command);
                    ImageButton btnInsert   = CreateLayoutImageButton(gID, "Layout.Insert"  , nFIELD_INDEX, L10n.Term("Dropdown.LNK_INS"   ), Sql.ToString(Session["themeURL"]) + "images/plus_inline.gif"     , Page_Command);
                    ImageButton btnEdit     = CreateLayoutImageButton(gID, "Layout.Edit"    , nFIELD_INDEX, L10n.Term("Dropdown.LNK_EDIT"  ), Sql.ToString(Session["themeURL"]) + "images/edit_inline.gif"     , Page_Command);
                    ImageButton btnDelete   = CreateLayoutImageButton(gID, "Layout.Delete"  , nFIELD_INDEX, L10n.Term("Dropdown.LNK_DELETE"), Sql.ToString(Session["themeURL"]) + "images/delete_inline.gif"   , Page_Command);
                    tdAction.Controls.Add(btnMoveUp  );
                    tdAction.Controls.Add(btnMoveDown);
                    tdAction.Controls.Add(btnInsert  );
                    tdAction.Controls.Add(btnEdit    );
                    tdAction.Controls.Add(btnDelete  );
                }
                // 12/03/2006 Paul.  Move literal label up so that it can be accessed when processing a blank.
                Literal litLabel = new Literal();
                if ( nCOLSPAN >= 0 || tdLabel == null || tdField == null )
                {
                    tdLabel = new HtmlTableCell();
                    tdField = new HtmlTableCell();
                    tr.Cells.Add(tdLabel);
                    tr.Cells.Add(tdField);
                    if ( nCOLSPAN > 0 )
                    {
                        tdField.ColSpan = nCOLSPAN;
                        if ( bLayoutMode )
                            tdField.ColSpan++;
                    }
                    tdLabel.Attributes.Add("class", "dataLabel");
                    tdLabel.VAlign = "top";
                    tdLabel.Width  = sLABEL_WIDTH;
                    tdField.Attributes.Add("class", "dataField");
                    tdField.VAlign = "top";
                    // 11/28/2005 Paul.  Don't use the field width if COLSPAN is specified as we want it to take the rest of the table.  The label width will be sufficient.
                    if ( nCOLSPAN == 0 )
                        tdField.Width  = sFIELD_WIDTH;

                    tdLabel.Controls.Add(litLabel);
                    //litLabel.Text = nFIELD_INDEX.ToString() + " (" + nRowIndex.ToString() + "," + nColIndex.ToString() + ")";
                    try
                    {
                        // 12/03/2006 Paul.  Move code to blank able in layout mode to blank section below.
                        if ( bLayoutMode )
                            litLabel.Text = sDATA_LABEL;
                        else if ( sDATA_LABEL.IndexOf(".") >= 0 )
                            litLabel.Text = L10n.Term(sDATA_LABEL);
                        else if ( !Sql.IsEmptyString(sDATA_LABEL) && rdr != null )
                        {
                            // 01/27/2008 Paul.  If the data label is not in the schema table, then it must be free-form text.
                            // It is not used often, but we allow the label to come from the result set.  For example,
                            // when the parent is stored in the record, we need to pull the module name from the record.
                            if ( tblSchema != null && tblSchema.Columns.Contains(sDATA_LABEL) )
                                litLabel.Text = Sql.ToString(rdr[sDATA_LABEL]) + L10n.Term("Calls.LBL_COLON");
                            else
                                litLabel.Text = sDATA_LABEL;
                        }
                        // 07/15/2006 Paul.  Always put something for the label so that table borders will look right.
                        // 07/20/2007 Vandalo.  Skip the requirement to create a terminology entry and just so the label.
                        else
                            litLabel.Text = sDATA_LABEL;  // "&nbsp;";
                    }
                    catch(Exception ex)
                    {
                        SplendidError.SystemWarning(new StackTrace(true).GetFrame(0), ex);
                        litLabel.Text = ex.Message;
                    }
                    if ( !bLayoutMode && bUI_REQUIRED )
                    {
                        Label lblRequired = new Label();
                        tdLabel.Controls.Add(lblRequired);
                        lblRequired.CssClass = "required";
                        lblRequired.Text = L10n.Term(".LBL_REQUIRED_SYMBOL");
                    }
                }

                if ( String.Compare(sFIELD_TYPE, "Blank", true) == 0 )
                {
                    Literal litField = new Literal();
                    tdField.Controls.Add(litField);
                    if ( bLayoutMode )
                    {
                        litLabel.Text = "*** BLANK ***";
                        litField.Text = "*** BLANK ***";
                    }
                    else
                    {
                        // 12/03/2006 Paul.  Make sure to clear the label.  This is necessary to convert a TEAM to blank when disabled.
                        litLabel.Text = "&nbsp;";
                        litField.Text = "&nbsp;";
                    }
                }
                else if ( String.Compare(sFIELD_TYPE, "Label", true) == 0 )
                {
                    if ( !Sql.IsEmptyString(sDATA_FIELD) )
                    {
                        Literal litField = new Literal();
                        tdField.Controls.Add(litField);
                        // 07/25/2006 Paul.  Align label values to the middle so the line-up with the label.
                        tdField.VAlign = "middle";
                        // 07/24/2006 Paul.  Set the ID so that the literal control can be accessed.
                        litField.ID = sDATA_FIELD;
                        try
                        {
                            if ( bLayoutMode )
                                litField.Text = sDATA_FIELD;
                            else if ( sDATA_FIELD.IndexOf(".") >= 0 )
                                litField.Text = L10n.Term(sDATA_FIELD);
                            else if ( rdr != null )
                                litField.Text = Sql.ToString(rdr[sDATA_FIELD]);
                        }
                        catch(Exception ex)
                        {
                            SplendidError.SystemWarning(new StackTrace(true).GetFrame(0), ex);
                            litField.Text = ex.Message;
                        }
                    }
                }
                else if ( String.Compare(sFIELD_TYPE, "ListBox", true) == 0 )
                {
                    if ( !Sql.IsEmptyString(sDATA_FIELD) )
                    {
                        // 12/02/2007 Paul.  If format rows > 0 then this is a list box and not a drop down list.
                        ListControl lstField = null;
                        if ( nFORMAT_ROWS > 0 )
                        {
                            ListBox lb = new ListBox();
                            lb.SelectionMode = ListSelectionMode.Multiple;
                            lb.Rows          = nFORMAT_ROWS;
                            lstField = lb;
                        }
                        else
                        {
                            lstField = new DropDownList();
                        }
                        tdField.Controls.Add(lstField);
                        lstField.ID       = sDATA_FIELD;
                        lstField.TabIndex = nFORMAT_TAB_INDEX;
                        try
                        {
                            if ( !Sql.IsEmptyString(sDATA_FIELD) )
                            {
                                // 12/04/2005 Paul.  Don't populate list if this is a post back.
                                if ( !Sql.IsEmptyString(sCACHE_NAME) && (bLayoutMode || !tbl.Page.IsPostBack) )
                                {
                                    // 12/24/2007 Paul.  Use an array to define the custom caches so that list is in the Cache module.
                                    // This should reduce the number of times that we have to edit the SplendidDynamic module.
                                    bool bCustomCache = false;
                                    SplendidCacheReference[] arrCustomCaches = SplendidCache.CustomCaches;
                                    foreach ( SplendidCacheReference cache in arrCustomCaches )
                                    {
                                        if ( cache.Name == sCACHE_NAME )
                                        {
                                            lstField.DataValueField = cache.DataValueField;
                                            lstField.DataTextField  = cache.DataTextField ;
                                            SplendidCacheCallback cbkDataSource = cache.DataSource;
                                            lstField.DataSource     = cbkDataSource();
                                            bCustomCache = true;
                                        }
                                    }
                                    if ( !bCustomCache )
                                    {
                                        lstField.DataValueField = "NAME"        ;
                                        lstField.DataTextField  = "DISPLAY_NAME";
                                        lstField.DataSource     = SplendidCache.List(sCACHE_NAME);
                                    }
                                    lstField.DataBind();
                                    // 08/08/2006 Paul.  Allow onchange code to be stored in the database.
                                    // ListBoxes do not have a useful onclick event, so there should be no problem overloading this field.
                                    if ( !Sql.IsEmptyString(sONCLICK_SCRIPT) )
                                        lstField.Attributes.Add("onchange" , sONCLICK_SCRIPT);
                                    // 02/21/2006 Paul.  Move the NONE item inside the !IsPostBack code.
                                    // 12/02/2007 Paul.  We don't need a NONE record when using multi-selection.
                                    // 12/03/2007 Paul.  We do want the NONE record when using multi-selection.
                                    // This will allow searching of fields that are null instead of using the unassigned only checkbox.
                                    if ( !bUI_REQUIRED )
                                    {
                                        lstField.Items.Insert(0, new ListItem(L10n.Term(".LBL_NONE"), ""));
                                        // 12/02/2007 Paul.  AppendEditViewFields should be called inside Page_Load when not a postback,
                                        // and in InitializeComponent when it is a postback. If done wrong,
                                        // the page will bind after the list is populated, causing the list to populate again.
                                        // This event will cause the NONE entry to be cleared.  Add a handler to catch this problem,
                                        // but the real solution is to call AppendEditViewFields at the appropriate times based on the postback event.
                                        lstField.DataBound += new EventHandler(ListControl_DataBound_AllowNull);
                                    }
                                }
                                if ( rdr != null )
                                {
                                    try
                                    {
                                        // 02/21/2006 Paul.  All the DropDownLists in the Calls and Meetings edit views were not getting set.
                                        // The problem was a Page.DataBind in the SchedulingGrid and in the InviteesView. Both binds needed to be removed.
                                        // 12/30/2007 Paul.  A customer needed the ability to save and restore the multiple selection.
                                        // 12/30/2007 Paul.  Require the XML declaration in the data before trying to treat as XML.
                                        string sVALUE = Sql.ToString(rdr[sDATA_FIELD]);
                                        if ( nFORMAT_ROWS > 0 && sVALUE.StartsWith("<?xml") )
                                        {
                                            XmlDocument xml = new XmlDocument();
                                            xml.LoadXml(sVALUE);
                                            XmlNodeList nlValues = xml.DocumentElement.SelectNodes("Value");
                                            foreach ( XmlNode xValue in nlValues )
                                            {
                                                foreach ( ListItem item in lstField.Items )
                                                {
                                                    if ( item.Value == xValue.InnerText )
                                                        item.Selected = true;
                                                }
                                            }
                                        }
                                        else
                                        {
                                            lstField.SelectedValue = sVALUE;
                                        }
                                    }
                                    catch(Exception ex)
                                    {
                                        SplendidError.SystemWarning(new StackTrace(true).GetFrame(0), ex);
                                    }
                                }
                                // 12/04/2005 Paul.  Assigned To field will always default to the current user.
                                else if ( rdr == null && !tbl.Page.IsPostBack && sCACHE_NAME == "AssignedUser")
                                {
                                    try
                                    {
                                        // 12/02/2007 Paul.  We don't default the user when using multi-selection.
                                        // This is because this mode is typically used for searching.
                                        if ( nFORMAT_ROWS == 0 )
                                            lstField.SelectedValue = Security.USER_ID.ToString();
                                    }
                                    catch(Exception ex)
                                    {
                                        SplendidError.SystemWarning(new StackTrace(true).GetFrame(0), ex);
                                    }
                                }
                            }
                        }
                        catch(Exception ex)
                        {
                            SplendidError.SystemWarning(new StackTrace(true).GetFrame(0), ex);
                        }
                        if ( bLayoutMode )
                        {
                            Literal litField = new Literal();
                            litField.Text = sDATA_FIELD;
                            tdField.Controls.Add(litField);
                        }
                    }
                }
                else if ( String.Compare(sFIELD_TYPE, "CheckBox", true) == 0 )
                {
                    if ( !Sql.IsEmptyString(sDATA_FIELD) )
                    {
                        CheckBox chkField = new CheckBox();
                        tdField.Controls.Add(chkField);
                        chkField.ID = sDATA_FIELD;
                        chkField.CssClass = "checkbox";
                        chkField.TabIndex = nFORMAT_TAB_INDEX;
                        try
                        {
                            if ( rdr != null )
                                chkField.Checked = Sql.ToBoolean(rdr[sDATA_FIELD]);
                        }
                        catch(Exception ex)
                        {
                            SplendidError.SystemWarning(new StackTrace(true).GetFrame(0), ex);
                        }
                        // 07/11/2007 Paul.  A checkbox can have a click event.
                        if ( !Sql.IsEmptyString(sONCLICK_SCRIPT) )
                            chkField.Attributes.Add("onclick", sONCLICK_SCRIPT);
                        if ( bLayoutMode )
                        {
                            Literal litField = new Literal();
                            litField.Text = sDATA_FIELD;
                            tdField.Controls.Add(litField);
                            chkField.Enabled  = false     ;
                        }
                    }
                }
                else if ( String.Compare(sFIELD_TYPE, "ChangeButton", true) == 0 )
                {
                    if ( !Sql.IsEmptyString(sDATA_FIELD) )
                    {
                        // 12/04/2005 Paul.  If the label is PARENT_TYPE, then change the label to a DropDownList.
                        if ( sDATA_LABEL == "PARENT_TYPE" )
                        {
                            tdLabel.Controls.Clear();
                            DropDownList lstField = new DropDownList();
                            tdLabel.Controls.Add(lstField);
                            lstField.ID       = sDATA_LABEL;
                            lstField.TabIndex = nFORMAT_TAB_INDEX;
                            lstField.Attributes.Add("onChange", "ChangeParentType();");
                            if ( bLayoutMode || !tbl.Page.IsPostBack )
                            {
                                // 07/29/2005 Paul.  SugarCRM 3.0 does not allow the NONE option.
                                lstField.DataValueField = "NAME"        ;
                                lstField.DataTextField  = "DISPLAY_NAME";
                                lstField.DataSource     = SplendidCache.List("record_type_display");
                                lstField.DataBind();
                                if ( rdr != null )
                                {
                                    try
                                    {
                                        lstField.SelectedValue = Sql.ToString(rdr[sDATA_LABEL]);
                                    }
                                    catch(Exception ex)
                                    {
                                        SplendidError.SystemWarning(new StackTrace(true).GetFrame(0), ex);
                                    }
                                }
                            }
                        }
                        TextBox txtNAME = new TextBox();
                        tdField.Controls.Add(txtNAME);
                        txtNAME.ID       = sDISPLAY_FIELD;
                        txtNAME.ReadOnly = true;
                        txtNAME.TabIndex = nFORMAT_TAB_INDEX;
                        // 11/25/2006 Paul.   Turn off viewstate so that we can fix the text on postback.
                        txtNAME.EnableViewState = false;
                        try
                        {
                            if ( bLayoutMode )
                            {
                                txtNAME.Text    = sDISPLAY_FIELD;
                                txtNAME.Enabled = false         ;
                            }
                            // 11/25/2006 Paul.  The Change text field is losing its value during a postback error.
                            else if ( tbl.Page.IsPostBack )
                            {
                                // 11/25/2006 Paul.  In order for this posback fix to work, viewstate must be disabled for this field.
                                if ( tbl.Page.Request[txtNAME.UniqueID] != null )
                                    txtNAME.Text = Sql.ToString(tbl.Page.Request[txtNAME.UniqueID]);
                            }
                            else if ( !Sql.IsEmptyString(sDISPLAY_FIELD) && rdr != null )
                                txtNAME.Text = Sql.ToString(rdr[sDISPLAY_FIELD]);
                            // 11/25/2006 Paul.  The team name should always default to the current user's private team.
                            // Make sure not to overwrite the value if this is a postback.
                            else if ( sDATA_FIELD == "TEAM_ID" && rdr == null && !tbl.Page.IsPostBack )
                                txtNAME.Text = Security.TEAM_NAME;
                            // 01/15/2007 Paul.  Assigned To field will always default to the current user.
                            else if ( sDATA_FIELD == "ASSIGNED_USER_ID" && rdr == null && !tbl.Page.IsPostBack )
                                txtNAME.Text = Security.USER_NAME;
                        }
                        catch(Exception ex)
                        {
                            SplendidError.SystemWarning(new StackTrace(true).GetFrame(0), ex);
                            txtNAME.Text = ex.Message;
                        }
                        HtmlInputHidden hidID = new HtmlInputHidden();
                        tdField.Controls.Add(hidID);
                        hidID.ID = sDATA_FIELD;
                        try
                        {
                            if ( !bLayoutMode )
                            {
                                if ( !Sql.IsEmptyString(sDATA_FIELD) && rdr != null )
                                    hidID.Value = Sql.ToString(rdr[sDATA_FIELD]);
                                // 11/25/2006 Paul.  The team name should always default to the current user's private team.
                                // Make sure not to overwrite the value if this is a postback.
                                // The hidden field does not require the same viewstate fix as the txtNAME field.
                                else if ( sDATA_FIELD == "TEAM_ID" && rdr == null && !tbl.Page.IsPostBack )
                                    hidID.Value = Security.TEAM_ID.ToString();
                                // 01/15/2007 Paul.  Assigned To field will always default to the current user.
                                else if ( sDATA_FIELD == "ASSIGNED_USER_ID" && rdr == null && !tbl.Page.IsPostBack )
                                    hidID.Value = Security.USER_ID.ToString();
                            }
                        }
                        catch(Exception ex)
                        {
                            SplendidError.SystemWarning(new StackTrace(true).GetFrame(0), ex);
                            txtNAME.Text = ex.Message;
                        }

                        Literal litNBSP = new Literal();
                        tdField.Controls.Add(litNBSP);
                        litNBSP.Text = "&nbsp;";

                        HtmlInputButton btnChange = new HtmlInputButton("button");
                        tdField.Controls.Add(btnChange);
                        // 05/07/2006 Paul.  Specify a name for the check button so that it can be referenced by SplendidTest.
                        btnChange.ID = sDATA_FIELD + "_btnChange";
                        btnChange.Attributes.Add("class", "button");
                        if ( !Sql.IsEmptyString(sONCLICK_SCRIPT) )
                            btnChange.Attributes.Add("onclick"  , sONCLICK_SCRIPT);
                        // 03/31/2007 Paul.  SugarCRM now uses Select instead of Change.
                        btnChange.Attributes.Add("title"    , L10n.Term(".LBL_SELECT_BUTTON_TITLE"));
                        // 07/31/2006 Paul.  Stop using VisualBasic library to increase compatibility with Mono.
                        // 03/31/2007 Paul.  Stop using AccessKey for change button.
                        //btnChange.Attributes.Add("accessKey", L10n.Term(".LBL_SELECT_BUTTON_KEY").Substring(0, 1));
                        btnChange.Value = L10n.Term(".LBL_SELECT_BUTTON_LABEL");

                        // 12/03/2007 Paul.  Also create a Clear button.
                        if ( sONCLICK_SCRIPT.IndexOf("Popup();") > 0 )
                        {
                            litNBSP = new Literal();
                            tdField.Controls.Add(litNBSP);
                            litNBSP.Text = "&nbsp;";

                            HtmlInputButton btnClear = new HtmlInputButton("button");
                            tdField.Controls.Add(btnClear);
                            btnClear.ID = sDATA_FIELD + "_btnClear";
                            btnClear.Attributes.Add("class", "button");
                            btnClear.Attributes.Add("onclick"  , sONCLICK_SCRIPT.Replace("Popup();", "('', '');").Replace("return ", "return Change"));
                            btnClear.Attributes.Add("title"    , L10n.Term(".LBL_CLEAR_BUTTON_TITLE"));
                            btnClear.Value = L10n.Term(".LBL_CLEAR_BUTTON_LABEL");
                        }
                        if ( !bLayoutMode && bUI_REQUIRED && !Sql.IsEmptyString(sDATA_FIELD) )
                        {
                            RequiredFieldValidatorForHiddenInputs reqID = new RequiredFieldValidatorForHiddenInputs();
                            reqID.ID                 = sDATA_FIELD + "_REQUIRED";
                            reqID.ControlToValidate  = hidID.ID;
                            reqID.ErrorMessage       = L10n.Term(".ERR_REQUIRED_FIELD");
                            reqID.CssClass           = "required";
                            reqID.EnableViewState    = false;
                            // 01/16/2006 Paul.  We don't enable required fields until we attempt to save.
                            // This is to allow unrelated form actions; the Cancel button is a good example.
                            reqID.EnableClientScript = false;
                            reqID.Enabled            = false;
                            tdField.Controls.Add(reqID);
                        }
                    }
                }
                else if ( String.Compare(sFIELD_TYPE, "TextBox", true) == 0 || String.Compare(sFIELD_TYPE, "Password", true) == 0 )
                {
                    if ( !Sql.IsEmptyString(sDATA_FIELD) )
                    {
                        TextBox txtField = new TextBox();
                        tdField.Controls.Add(txtField);
                        txtField.ID       = sDATA_FIELD;
                        txtField.TabIndex = nFORMAT_TAB_INDEX;
                        try
                        {
                            if ( nFORMAT_ROWS > 0 && nFORMAT_COLUMNS > 0 )
                            {
                                txtField.Rows     = nFORMAT_ROWS   ;
                                txtField.Columns  = nFORMAT_COLUMNS;
                                txtField.TextMode = TextBoxMode.MultiLine;
                            }
                            else
                            {
                                txtField.MaxLength = nFORMAT_MAX_LENGTH   ;
                                txtField.Attributes.Add("size", nFORMAT_SIZE.ToString());
                                txtField.TextMode  = TextBoxMode.SingleLine;
                            }
                            if ( bLayoutMode )
                            {
                                txtField.Text     = sDATA_FIELD;
                                txtField.ReadOnly = true       ;
                            }
                            else if ( !Sql.IsEmptyString(sDATA_FIELD) && rdr != null )
                            {
                                int    nOrdinal  = rdr.GetOrdinal(sDATA_FIELD);
                                string sTypeName = rdr.GetDataTypeName(nOrdinal);
                                // 03/04/2006 Paul.  Display currency in the proper format.
                                // Only SQL Server is likely to return the money type, so also include the decimal type.
                                if ( sTypeName == "money" || rdr[sDATA_FIELD].GetType() == typeof(System.Decimal) )
                                    txtField.Text = Sql.ToDecimal(rdr[sDATA_FIELD]).ToString("#,##0.00");
                                else
                                    txtField.Text = Sql.ToString(rdr[sDATA_FIELD]);
                            }
                        }
                        catch(Exception ex)
                        {
                            SplendidError.SystemWarning(new StackTrace(true).GetFrame(0), ex);
                            txtField.Text = ex.Message;
                        }
                        if ( String.Compare(sFIELD_TYPE, "Password", true) == 0 )
                            txtField.TextMode = TextBoxMode.Password;
                        if ( !bLayoutMode && bUI_REQUIRED && !Sql.IsEmptyString(sDATA_FIELD) )
                        {
                            RequiredFieldValidator reqNAME = new RequiredFieldValidator();
                            reqNAME.ID                 = sDATA_FIELD + "_REQUIRED";
                            reqNAME.ControlToValidate  = txtField.ID;
                            reqNAME.ErrorMessage       = L10n.Term(".ERR_REQUIRED_FIELD");
                            reqNAME.CssClass           = "required";
                            reqNAME.EnableViewState    = false;
                            // 01/16/2006 Paul.  We don't enable required fields until we attempt to save.
                            // This is to allow unrelated form actions; the Cancel button is a good example.
                            reqNAME.EnableClientScript = false;
                            reqNAME.Enabled            = false;
                            tdField.Controls.Add(reqNAME);
                        }
                    }
                }
                else if ( String.Compare(sFIELD_TYPE, "DatePicker", true) == 0 )
                {
                    if ( !Sql.IsEmptyString(sDATA_FIELD) )
                    {
                        // 12/03/2005 Paul.  UserControls must be loaded.
                        DatePicker ctlDate = tbl.Page.LoadControl("~/_controls/DatePicker.ascx") as DatePicker;
                        tdField.Controls.Add(ctlDate);
                        ctlDate.ID = sDATA_FIELD;
                        // 05/10/2006 Paul.  Set the tab index.
                        ctlDate.TabIndex = nFORMAT_TAB_INDEX;
                        try
                        {
                            if ( rdr != null )
                                ctlDate.Value = T10n.FromServerTime(rdr[sDATA_FIELD]);
                        }
                        catch(Exception ex)
                        {
                            SplendidError.SystemWarning(new StackTrace(true).GetFrame(0), ex);
                        }
                        // 01/16/2006 Paul.  We validate elsewhere.
                        /*
                        if ( !bLayoutMode && bUI_REQUIRED && !Sql.IsEmptyString(sDATA_FIELD) )
                        {
                            ctlDate.Required = true;
                        }
                        */
                        if ( bLayoutMode )
                        {
                            Literal litField = new Literal();
                            litField.Text = sDATA_FIELD;
                            tdField.Controls.Add(litField);
                        }
                    }
                }
                else if ( String.Compare(sFIELD_TYPE, "DateRange", true) == 0 )
                {
                    if ( !Sql.IsEmptyString(sDATA_FIELD) )
                    {
                        // 12/17/2007 Paul.  Use table to align before and after labels.
                        Table tblDateRange = new Table();
                        tdField.Controls.Add(tblDateRange);
                        TableRow trAfter = new TableRow();
                        TableRow trBefore = new TableRow();
                        tblDateRange.Rows.Add(trAfter);
                        tblDateRange.Rows.Add(trBefore);
                        TableCell tdAfterLabel  = new TableCell();
                        TableCell tdAfterData   = new TableCell();
                        TableCell tdBeforeLabel = new TableCell();
                        TableCell tdBeforeData  = new TableCell();
                        trAfter .Cells.Add(tdAfterLabel );
                        trAfter .Cells.Add(tdAfterData  );
                        trBefore.Cells.Add(tdBeforeLabel);
                        trBefore.Cells.Add(tdBeforeData );

                        // 12/03/2005 Paul.  UserControls must be loaded.
                        DatePicker ctlDateStart = tbl.Page.LoadControl("~/_controls/DatePicker.ascx") as DatePicker;
                        DatePicker ctlDateEnd   = tbl.Page.LoadControl("~/_controls/DatePicker.ascx") as DatePicker;
                        Literal litAfterLabel  = new Literal();
                        Literal litBeforeLabel = new Literal();
                        litAfterLabel .Text = L10n.Term("SavedSearch.LBL_SEARCH_AFTER" );
                        litBeforeLabel.Text = L10n.Term("SavedSearch.LBL_SEARCH_BEFORE");
                        //tdField.Controls.Add(litAfterLabel );
                        //tdField.Controls.Add(ctlDateStart  );
                        //tdField.Controls.Add(litBeforeLabel);
                        //tdField.Controls.Add(ctlDateEnd    );
                        tdAfterLabel .Controls.Add(litAfterLabel );
                        tdAfterData  .Controls.Add(ctlDateStart  );
                        tdBeforeLabel.Controls.Add(litBeforeLabel);
                        tdBeforeData .Controls.Add(ctlDateEnd    );

                        ctlDateStart.ID = sDATA_FIELD + "_AFTER";
                        ctlDateEnd  .ID = sDATA_FIELD + "_BEFORE";
                        // 05/10/2006 Paul.  Set the tab index.
                        ctlDateStart.TabIndex = nFORMAT_TAB_INDEX;
                        ctlDateEnd  .TabIndex = nFORMAT_TAB_INDEX;
                        try
                        {
                            if ( rdr != null )
                            {
                                ctlDateStart.Value = T10n.FromServerTime(rdr[sDATA_FIELD]);
                                ctlDateEnd  .Value = T10n.FromServerTime(rdr[sDATA_FIELD]);
                            }
                        }
                        catch(Exception ex)
                        {
                            SplendidError.SystemWarning(new StackTrace(true).GetFrame(0), ex);
                        }
                        // 01/16/2006 Paul.  We validate elsewhere.
                        /*
                        if ( !bLayoutMode && bUI_REQUIRED && !Sql.IsEmptyString(sDATA_FIELD) )
                        {
                            ctlDateStart.Required = true;
                            ctlDateEnd  .Required = true;
                        }
                        */
                        if ( bLayoutMode )
                        {
                            Literal litField = new Literal();
                            litField.Text = sDATA_FIELD;
                            tdField.Controls.Add(litField);
                        }
                    }
                }
                else if ( String.Compare(sFIELD_TYPE, "DateTimePicker", true) == 0 )
                {
                    if ( !Sql.IsEmptyString(sDATA_FIELD) )
                    {
                        // 12/03/2005 Paul.  UserControls must be loaded.
                        DateTimePicker ctlDate = tbl.Page.LoadControl("~/_controls/DateTimePicker.ascx") as DateTimePicker;
                        tdField.Controls.Add(ctlDate);
                        ctlDate.ID = sDATA_FIELD;
                        // 05/10/2006 Paul.  Set the tab index.
                        ctlDate.TabIndex = nFORMAT_TAB_INDEX;
                        try
                        {
                            if ( rdr != null )
                                ctlDate.Value = T10n.FromServerTime(rdr[sDATA_FIELD]);
                        }
                        catch(Exception ex)
                        {
                            SplendidError.SystemWarning(new StackTrace(true).GetFrame(0), ex);
                        }
                        if ( bLayoutMode )
                        {
                            Literal litField = new Literal();
                            litField.Text = sDATA_FIELD;
                            tdField.Controls.Add(litField);
                        }
                    }
                }
                else if ( String.Compare(sFIELD_TYPE, "DateTimeEdit", true) == 0 )
                {
                    if ( !Sql.IsEmptyString(sDATA_FIELD) )
                    {
                        // 12/03/2005 Paul.  UserControls must be loaded.
                        DateTimeEdit ctlDate = tbl.Page.LoadControl("~/_controls/DateTimeEdit.ascx") as DateTimeEdit;
                        tdField.Controls.Add(ctlDate);
                        ctlDate.ID = sDATA_FIELD;
                        // 05/10/2006 Paul.  Set the tab index.
                        ctlDate.TabIndex = nFORMAT_TAB_INDEX;
                        try
                        {
                            if ( rdr != null )
                                ctlDate.Value = T10n.FromServerTime(rdr[sDATA_FIELD]);
                        }
                        catch(Exception ex)
                        {
                            SplendidError.SystemWarning(new StackTrace(true).GetFrame(0), ex);
                        }
                        if ( !bLayoutMode && bUI_REQUIRED )
                        {
                            ctlDate.EnableNone = false;
                        }
                        if ( bLayoutMode )
                        {
                            Literal litField = new Literal();
                            litField.Text = sDATA_FIELD;
                            tdField.Controls.Add(litField);
                        }
                    }
                }
                else if ( String.Compare(sFIELD_TYPE, "File", true) == 0 )
                {
                    if ( !Sql.IsEmptyString(sDATA_FIELD) )
                    {
                        HtmlInputFile ctlField = new HtmlInputFile();
                        tdField.Controls.Add(ctlField);
                        ctlField.ID        = sDATA_FIELD;
                        ctlField.MaxLength = nFORMAT_MAX_LENGTH;
                        ctlField.Size      = nFORMAT_SIZE;
                        ctlField.Attributes.Add("TabIndex", nFORMAT_TAB_INDEX.ToString());
                        if ( !bLayoutMode && bUI_REQUIRED )
                        {
                            RequiredFieldValidator reqNAME = new RequiredFieldValidator();
                            reqNAME.ID                 = sDATA_FIELD + "_REQUIRED";
                            reqNAME.ControlToValidate  = ctlField.ID;
                            reqNAME.ErrorMessage       = L10n.Term(".ERR_REQUIRED_FIELD");
                            reqNAME.CssClass           = "required";
                            reqNAME.EnableViewState    = false;
                            // 01/16/2006 Paul.  We don't enable required fields until we attempt to save.
                            // This is to allow unrelated form actions; the Cancel button is a good example.
                            reqNAME.EnableClientScript = false;
                            reqNAME.Enabled            = false;
                            tdField.Controls.Add(reqNAME);
                        }
                    }
                }
                else if ( String.Compare(sFIELD_TYPE, "Image", true) == 0 )
                {
                    if ( !Sql.IsEmptyString(sDATA_FIELD) )
                    {
                        HtmlInputHidden ctlHidden = new HtmlInputHidden();
                        if ( !bLayoutMode )
                        {
                            tdField.Controls.Add(ctlHidden);
                            ctlHidden.ID = sDATA_FIELD;

                            HtmlInputFile ctlField = new HtmlInputFile();
                            tdField.Controls.Add(ctlField);
                            // 04/17/2006 Paul.  The image needs to reference the file control.
                            ctlField.ID = sDATA_FIELD + "_File";

                            Literal litBR = new Literal();
                            litBR.Text = "<br />";
                            tdField.Controls.Add(litBR);
                        }

                        Image imgField = new Image();
                        // 04/13/2006 Paul.  Give the image a name so that it can be validated with SplendidTest.
                        imgField.ID = "img" + sDATA_FIELD;
                        try
                        {
                            if ( bLayoutMode )
                            {
                                Literal litField = new Literal();
                                litField.Text = sDATA_FIELD;
                                tdField.Controls.Add(litField);
                            }
                            else if ( rdr != null )
                            {
                                if ( !Sql.IsEmptyString(rdr[sDATA_FIELD]) )
                                {
                                    ctlHidden.Value = Sql.ToString(rdr[sDATA_FIELD]);
                                    imgField.ImageUrl = "~/Images/Image.aspx?ID=" + ctlHidden.Value;
                                    // 04/13/2006 Paul.  Only add the image if it exists.
                                    tdField.Controls.Add(imgField);

                                    // 04/17/2006 Paul.  Provide a clear button.
                                    Literal litClear = new Literal();
                                    litClear.Text = "<br /><input type=\"button\" class=\"button\" onclick=\"form." + ctlHidden.ClientID + ".value='';form." + imgField.ClientID + ".src='';" + "\"  value='" + "  " + L10n.Term(".LBL_CLEAR_BUTTON_LABEL" ) + "  " + "' title='" + L10n.Term(".LBL_CLEAR_BUTTON_TITLE" ) + "' />";
                                    tdField.Controls.Add(litClear);
                                }
                            }
                        }
                        catch(Exception ex)
                        {
                            SplendidError.SystemWarning(new StackTrace(true).GetFrame(0), ex);
                            Literal litField = new Literal();
                            litField.Text = ex.Message;
                            tdField.Controls.Add(litField);
                        }
                    }
                }
                else if ( String.Compare(sFIELD_TYPE, "AddressButtons", true) == 0 )
                {
                    tr.Cells.Remove(tdField);
                    tdLabel.Width = "10%";
                    tdLabel.RowSpan = nROWSPAN;
                    tdLabel.VAlign  = "middle";
                    tdLabel.Align   = "center";
                    tdLabel.Attributes.Remove("class");
                    tdLabel.Attributes.Add("class", "tabFormAddDel");
                    HtmlInputButton btnCopyRight = new HtmlInputButton("button");
                    Literal         litSpacer    = new Literal();
                    HtmlInputButton btnCopyLeft  = new HtmlInputButton("button");
                    tdLabel.Controls.Add(btnCopyRight);
                    tdLabel.Controls.Add(litSpacer   );
                    tdLabel.Controls.Add(btnCopyLeft );
                    btnCopyRight.Attributes.Add("title"  , L10n.Term("Accounts.NTC_COPY_BILLING_ADDRESS" ));
                    btnCopyRight.Attributes.Add("onclick", "return copyAddressRight()");
                    btnCopyRight.Value = ">>";
                    litSpacer.Text = "<br><br>";
                    btnCopyLeft .Attributes.Add("title"  , L10n.Term("Accounts.NTC_COPY_SHIPPING_ADDRESS" ));
                    btnCopyLeft .Attributes.Add("onclick", "return copyAddressLeft()");
                    btnCopyLeft .Value = "<<";
                    nColIndex = 0;
                }
                else
                {
                    Literal litField = new Literal();
                    tdField.Controls.Add(litField);
                    litField.Text = "Unknown field type " + sFIELD_TYPE;
                    SplendidError.SystemWarning(new StackTrace(true).GetFrame(0), "Unknown field type " + sFIELD_TYPE);
                }
                // 12/02/2007 Paul.  Each view can now have its own number of data columns.
                // This was needed so that search forms can have 4 data columns. The default is 2 columns.
                if ( nCOLSPAN > 0 )
                    nColIndex += nCOLSPAN;
                else if ( nCOLSPAN == 0 )
                    nColIndex++;
                if ( nColIndex >= nDATA_COLUMNS )
                    nColIndex = 0;
            }
        }