edu.ku.brc.af.ui.forms.ViewFactory.java Source code

Java tutorial

Introduction

Here is the source code for edu.ku.brc.af.ui.forms.ViewFactory.java

Source

/* Copyright (C) 2015, University of Kansas Center for Research
 * 
 * Specify Software Project, specify@ku.edu, Biodiversity Institute,
 * 1345 Jayhawk Boulevard, Lawrence, Kansas, 66045, USA
 * 
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
*/
package edu.ku.brc.af.ui.forms;

import static edu.ku.brc.af.ui.forms.validation.UIValidator.parseValidationType;
import static edu.ku.brc.ui.UIHelper.createButton;
import static edu.ku.brc.ui.UIHelper.createLabel;
import static edu.ku.brc.ui.UIHelper.createProgressBar;
import static org.apache.commons.lang.StringUtils.isNotEmpty;
import static org.apache.commons.lang.StringUtils.split;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Insets;
import java.awt.event.ActionEvent;
import java.awt.event.InputEvent;
import java.awt.event.KeyEvent;
import java.lang.reflect.Field;
import java.math.BigDecimal;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;

import javax.swing.AbstractAction;
import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JPanel;
import javax.swing.JPopupMenu;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.JTextField;
import javax.swing.KeyStroke;
import javax.swing.ScrollPaneConstants;
import javax.swing.SwingConstants;
import javax.swing.border.BevelBorder;
import javax.swing.border.Border;
import javax.swing.filechooser.FileNameExtensionFilter;

import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;

import edu.ku.brc.af.auth.PermissionSettings;
import edu.ku.brc.af.core.AppContextMgr;
import edu.ku.brc.af.core.TaskMgr;
import edu.ku.brc.af.core.db.DBFieldInfo;
import edu.ku.brc.af.core.db.DBRelationshipInfo;
import edu.ku.brc.af.core.db.DBTableChildIFace;
import edu.ku.brc.af.core.db.DBTableIdMgr;
import edu.ku.brc.af.core.db.DBTableInfo;
import edu.ku.brc.af.prefs.AppPrefsCache;
import edu.ku.brc.af.ui.BrowseBtnPanel;
import edu.ku.brc.af.ui.db.PickListDBAdapterFactory;
import edu.ku.brc.af.ui.db.PickListDBAdapterIFace;
import edu.ku.brc.af.ui.db.TextFieldFromPickListTable;
import edu.ku.brc.af.ui.db.TextFieldWithInfo;
import edu.ku.brc.af.ui.forms.SubViewBtn.DATA_TYPE;
import edu.ku.brc.af.ui.forms.formatters.GenericStringUIFieldFormatter;
import edu.ku.brc.af.ui.forms.formatters.UIFieldFormatterIFace;
import edu.ku.brc.af.ui.forms.formatters.UIFieldFormatterMgr;
import edu.ku.brc.af.ui.forms.persist.AltViewIFace;
import edu.ku.brc.af.ui.forms.persist.FormCellCommand;
import edu.ku.brc.af.ui.forms.persist.FormCellField;
import edu.ku.brc.af.ui.forms.persist.FormCellFieldIFace;
import edu.ku.brc.af.ui.forms.persist.FormCellIFace;
import edu.ku.brc.af.ui.forms.persist.FormCellLabel;
import edu.ku.brc.af.ui.forms.persist.FormCellPanel;
import edu.ku.brc.af.ui.forms.persist.FormCellSeparatorIFace;
import edu.ku.brc.af.ui.forms.persist.FormCellSubView;
import edu.ku.brc.af.ui.forms.persist.FormCellSubViewIFace;
import edu.ku.brc.af.ui.forms.persist.FormDevHelper;
import edu.ku.brc.af.ui.forms.persist.FormRowIFace;
import edu.ku.brc.af.ui.forms.persist.FormViewDef;
import edu.ku.brc.af.ui.forms.persist.FormViewDefIFace;
import edu.ku.brc.af.ui.forms.persist.ViewDefIFace;
import edu.ku.brc.af.ui.forms.persist.ViewIFace;
import edu.ku.brc.af.ui.forms.validation.DataChangeNotifier;
import edu.ku.brc.af.ui.forms.validation.FormValidator;
import edu.ku.brc.af.ui.forms.validation.TypeSearchForQueryFactory;
import edu.ku.brc.af.ui.forms.validation.UIValidatable;
import edu.ku.brc.af.ui.forms.validation.UIValidator;
import edu.ku.brc.af.ui.forms.validation.ValBrowseBtnPanel;
import edu.ku.brc.af.ui.forms.validation.ValCheckBox;
import edu.ku.brc.af.ui.forms.validation.ValComboBox;
import edu.ku.brc.af.ui.forms.validation.ValComboBoxFromQuery;
import edu.ku.brc.af.ui.forms.validation.ValFormattedTextField;
import edu.ku.brc.af.ui.forms.validation.ValFormattedTextFieldIFace;
import edu.ku.brc.af.ui.forms.validation.ValFormattedTextFieldSingle;
import edu.ku.brc.af.ui.forms.validation.ValListBox;
import edu.ku.brc.af.ui.forms.validation.ValPasswordField;
import edu.ku.brc.af.ui.forms.validation.ValPlainTextDocument;
import edu.ku.brc.af.ui.forms.validation.ValSpinner;
import edu.ku.brc.af.ui.forms.validation.ValTextArea;
import edu.ku.brc.af.ui.forms.validation.ValTextAreaBrief;
import edu.ku.brc.af.ui.forms.validation.ValTextField;
import edu.ku.brc.af.ui.forms.validation.ValTristateCheckBox;
import edu.ku.brc.af.ui.forms.validation.ValidatedJPanel;
import edu.ku.brc.af.ui.weblink.WebLinkButton;
import edu.ku.brc.exceptions.ConfigurationException;
import edu.ku.brc.specify.plugins.SeriesProcCatNumPlugin;
import edu.ku.brc.ui.ColorChooser;
import edu.ku.brc.ui.ColorWrapper;
import edu.ku.brc.ui.CommandAction;
import edu.ku.brc.ui.CommandActionWrapper;
import edu.ku.brc.ui.DateWrapper;
import edu.ku.brc.ui.GetSetValueIFace;
import edu.ku.brc.ui.IconButton;
import edu.ku.brc.ui.IconManager;
import edu.ku.brc.ui.ImageDisplay;
import edu.ku.brc.ui.JStatusBar;
import edu.ku.brc.ui.UIHelper;
import edu.ku.brc.ui.UIRegistry;

/**
 * Creates FormViewObj object that implement the Viewable interface.
 *
 * @code_status Complete
 *
 * @author rods
 *
 */
public class ViewFactory {
    public static final String factoryName = "edu.ku.brc.af.ui.forms.ViewFactory"; //$NON-NLS-1$

    // Statics
    private static final Logger log = Logger.getLogger(ViewFactory.class);
    private static final String LF = "\\" + "n";

    private static ViewFactory instance = null;

    // Data Members
    private static ColorWrapper viewFieldColor = null;
    private static boolean doFixLabels = true;
    private static boolean isFormTransparent = false;

    /**
     * Constructor.
     */
    protected ViewFactory() {
        // do nothing
    }

    /**
     * @param doFixLabels the doFixLabels to set
     */
    public static void setDoFixLabels(boolean doFixLabels) {
        ViewFactory.doFixLabels = doFixLabels;
    }

    /**
     * Creates a panel with the "..." icon.
     * @param comp the component to put into the panel
     */
    public JPanel createIconPanel(final JComponent comp) {
        JPanel panel = new JPanel(new BorderLayout());
        JButton btn = createButton("...");
        panel.add(btn, BorderLayout.WEST);
        panel.add(comp, BorderLayout.EAST);
        return panel;
    }

    /**
     * Returns a ViewDef Obj with the form UI built.
     * @param view the view definition
     * @param altView which AltViewIFace to build
     * @param parentView the MultiViw that this view/form will be parented to
     * @param options the options needed for creating the form
     * @param cellName the name of the cell when it is a subview
     * @param dataClass the class of the data that is put into the form
     * @return a Viewable Obj with the form UI built
     */
    public Viewable buildViewable(final ViewIFace view, final AltViewIFace altView, final MultiView parentView,
            final int options, final String cellName, final Color bgColor) {
        if (viewFieldColor == null) {
            viewFieldColor = AppPrefsCache.getColorWrapper("ui", "formatting", "viewfieldcolor");
        }

        ViewDefIFace viewDef = altView.getViewDef();
        if (viewDef == null) {
            // This error is bad enough to have it's own dialog
            String msg = String.format("The ViewDef is null for View '%s' AltView '%s'", view.getName(),
                    altView.getName());
            FormDevHelper.appendFormDevError(msg);
            UIRegistry.showError(msg);
            return null;
        }

        Class<?> dataClass = null;
        DBTableInfo tableInfo = DBTableIdMgr.getInstance().getByClassName(view.getClassName());
        MultiView parentsMV = parentView != null ? parentView.getMultiViewParent() : null;
        if (tableInfo == null && parentsMV != null && cellName != null) {
            tableInfo = DBTableIdMgr.getInstance().getByClassName(parentsMV.getView().getClassName());
            if (tableInfo != null) {
                DBTableChildIFace childInfo = tableInfo.getItemByName(cellName);
                if (childInfo != null) {
                    dataClass = childInfo.getDataClass();
                }
            }
        } else {
            try {
                dataClass = Class.forName(view.getClassName());
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
            }
        }

        if (viewDef.getType() == ViewDefIFace.ViewType.form) {
            Viewable viewable = buildFormViewable(view, altView, parentView, options, cellName, dataClass, bgColor);
            return viewable;

        } else if (viewDef.getType() == ViewDefIFace.ViewType.table
                || viewDef.getType() == ViewDefIFace.ViewType.formtable) {
            Viewable viewable = buildTableViewable(view, altView, parentView, options, cellName, dataClass,
                    bgColor);
            return viewable;

        } else if (viewDef.getType() == ViewDefIFace.ViewType.field) {
            return null;

        } else if (viewDef.getType() == ViewDefIFace.ViewType.iconview) {
            return new IconViewObj(view, altView, parentView, options, cellName, dataClass);
        } else if (viewDef.getType() == ViewDefIFace.ViewType.rstable) {
            return buildRecordSetTableViewable(view, altView, parentView, options, cellName, dataClass, bgColor);

        } else {
            FormDevHelper.appendFormDevError("Form Type not covered by builder [" + viewDef.getType() + "]");
        }
        return null;
    }

    /**
     * Creates a ValTextField.
     * @param validator a validator to hook the control up to (may be null)
     * @param cellField the definition of the cell for this control
     * @return a ValTextField
     */
    public static JTextField createTextField(final FormValidator validator, final FormCellField cellField,
            @SuppressWarnings("unused") final DBFieldInfo fieldInfo, final boolean isRequired,
            final PickListDBAdapterIFace adapter) {
        String validationRule = cellField.getValidationRule();

        JTextField txtField;
        ValTextField valTextField = null;
        if (validator != null && (isRequired || isNotEmpty(validationRule) || cellField.isChangeListenerOnly())) {
            valTextField = new ValTextField(cellField.getTxtCols(), adapter);
            valTextField.setRequired(isRequired);
            valTextField.setViewOnly(cellField.isReadOnly());

            validator.hookupTextField(valTextField, cellField.getIdent(), //+"_text",
                    isRequired, parseValidationType(cellField.getValidationType()), cellField.getValidationRule(),
                    cellField.isChangeListenerOnly() && !isRequired);

            txtField = valTextField;
            valTextField.setEditable(!cellField.isReadOnly());

            if (fieldInfo != null && fieldInfo.getLength() > -1) {
                valTextField.setLimit(fieldInfo.getLength());
            }

        } else if (adapter != null) {
            valTextField = new ValTextField(cellField.getTxtCols(), adapter);
            valTextField.setViewOnly(cellField.isReadOnly());
            if (fieldInfo.getLength() > -1) {
                valTextField.setLimit(fieldInfo.getLength());
            }

            txtField = valTextField;
            valTextField.setEditable(false);

        } else {
            valTextField = new ValTextField(cellField.getTxtCols());
            valTextField.setViewOnly(cellField.isReadOnly());
            if (fieldInfo != null && fieldInfo.getLength() > -1) {
                valTextField.setLimit(fieldInfo.getLength());
            }
            txtField = valTextField;
        }

        addTextFieldPopup(valTextField, valTextField, false);

        return txtField;
    }

    /**
     * Creates a ValPasswordField.
     * @param validator a validator to hook the control up to (may be null)
     * @param cellField the definition of the cell for this control
     * @param isRequired whether the field is required or not
     * @return a ValPasswordField
     */
    public static JTextField createPasswordField(final FormValidator validator, final FormCellField cellField,
            final boolean isRequired) {
        String validationRule = cellField.getValidationRule();
        JTextField txt;
        ValPasswordField textField = null;

        if (validator != null && (isRequired || isNotEmpty(validationRule) || cellField.isChangeListenerOnly())) {
            String maxLenStr = cellField.getProperties().getProperty("maxlen");
            if (StringUtils.isNotEmpty(maxLenStr) && StringUtils.isNumeric(maxLenStr)) {
                int maxlen = Integer.parseInt(maxLenStr);
                textField = new ValPasswordField(new ValPlainTextDocument(maxlen), "", cellField.getTxtCols());
            } else {
                textField = new ValPasswordField(cellField.getTxtCols());
            }
            textField.setRequired(isRequired);
            textField.setEncrypted(cellField.isEncrypted());

            validator.hookupTextField(textField, cellField.getIdent(), isRequired,
                    parseValidationType(cellField.getValidationType()), validationRule,
                    cellField.isChangeListenerOnly());

            txt = textField;

        } else {
            txt = new ValPasswordField(cellField.getTxtCols());
        }

        return txt;
    }

    /**
     * Creates a ValFormattedTextField.
     * @param validator a validator to hook the control up to (may be null)
     * @param cellField the definition of the cell for this control
     * @param isViewOnly whether it is in view mode
     * @param isRequired whether the field is required or not
     * @param allEditOK indicates that all the fields should be editable (event the auto-numbered field)
     * @return ValFormattedTextField
     */
    public static JComponent createFormattedTextField(final FormValidator validator, final FormCellField cellField,
            final Class<?> tableClass, final int len, final String uiFormatterName, final boolean isViewOnly,
            final boolean isRequired, final boolean allEditOK) {
        //log.debug(cellField.getName()+"  "+cellField.getUIFieldFormatter());

        boolean isPartialOK = cellField.getPropertyAsBoolean("ispartial", false);
        boolean isFromUIFmtOverride = cellField.getPropertyAsBoolean("fromuifmt", false);
        Integer suggestedNumCols = cellField.getPropertyAsInteger("cols", null);

        // Because it is formatted we ALWAYS validate it when there is a validator
        if (validator != null) {
            // deliberately ignore "cellField.isChangeListenerOnly()"
            // pass in false instead
            // THis is the OLD way before the UIFieldFormatter was moved into the DBFieldInfo and also the CellField
            UIFieldFormatterIFace formatter = UIFieldFormatterMgr.getInstance().getFormatter(uiFormatterName);
            if (formatter == null) {
                String msg = "Field[" + cellField.getName() + "] is missing formatter by name [" + uiFormatterName
                        + "]";
                log.debug(msg);
                FormDevHelper.appendFormDevError(msg);
                formatter = new GenericStringUIFieldFormatter("Temp", tableClass, cellField.getName(), "", len);
            }

            if (formatter.isDate() || formatter.isNumeric()) {
                final ValFormattedTextFieldSingle textField = new ValFormattedTextFieldSingle(uiFormatterName,
                        isViewOnly, isPartialOK, suggestedNumCols);
                textField.setRequired(isRequired);

                validator.hookupTextField(textField, cellField.getIdent(), isRequired, UIValidator.Type.Changed,
                        cellField.getValidationRule(), false);

                addTextFieldPopup(textField, textField, formatter.isDate());

                if (isViewOnly) {
                    changeTextFieldUIForDisplay(textField, cellField.getPropertyAsBoolean("transparent", false));
                } else {
                    textField.setEditable(!cellField.isReadOnly());
                }

                textField.setFromUIFmtOverride(isFromUIFmtOverride);
                return textField;
            }

            ValFormattedTextField textField = new ValFormattedTextField(formatter, isViewOnly, allEditOK,
                    isPartialOK);
            textField.setRequired(isRequired);
            textField.setFromUIFmtOverride(isFromUIFmtOverride);

            DataChangeNotifier dcn = validator.hookupComponent(textField, cellField.getIdent(),
                    UIValidator.Type.Changed, cellField.getValidationRule(), false);
            if (cellField.isRequired()) {
                textField.addDocumentListener(dcn);
            }

            textField.setChangeListener(dcn);
            return textField;

        }

        if (isViewOnly) {
            ValFormattedTextFieldSingle vtfs;

            UIFieldFormatterIFace formatter = UIFieldFormatterMgr.getInstance().getFormatter(uiFormatterName);
            if (formatter == null) {
                formatter = new GenericStringUIFieldFormatter("Temp", tableClass, cellField.getName(), "", len);
                vtfs = new ValFormattedTextFieldSingle(formatter, isViewOnly, false);

            } else {
                vtfs = new ValFormattedTextFieldSingle(uiFormatterName, isViewOnly, false, suggestedNumCols);
            }
            changeTextFieldUIForDisplay(vtfs, cellField.getPropertyAsBoolean("transparent", false));
            return vtfs;
        }
        // else
        ValFormattedTextField vtf = new ValFormattedTextField(uiFormatterName, isViewOnly, allEditOK, isPartialOK);
        vtf.setEnabled(!cellField.isReadOnly());
        vtf.setRequired(isRequired);
        vtf.setFromUIFmtOverride(isFromUIFmtOverride);
        return vtf;
    }

    /**
     * @param destObj
     * @param textField
     */
    public static void addTextFieldPopup(final GetSetValueIFace destObj, final JTextField textField,
            final boolean doAddDate) {
        if (textField != null) {
            JPopupMenu popupMenu = new JPopupMenu();

            if (doAddDate) {
                AbstractAction aa = new AbstractAction("Clear It") {

                    @Override
                    public void actionPerformed(ActionEvent e) {
                        DateWrapper scrDateFormat = AppPrefsCache.getDateWrapper("ui", "formatting",
                                "scrdateformat");
                        if (scrDateFormat != null) {
                            destObj.setValue(scrDateFormat.format(Calendar.getInstance()), "");
                        } else {
                            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
                            destObj.setValue(sdf.format(Calendar.getInstance()), "");
                        }
                    }
                };

                UIHelper.createLocalizedMenuItem(popupMenu, "ViewFactory.CURR_DATE", "", "", true, aa);

                KeyStroke ctrlShiftT = KeyStroke.getKeyStroke(KeyEvent.VK_T,
                        InputEvent.CTRL_DOWN_MASK | InputEvent.SHIFT_DOWN_MASK);
                textField.getInputMap().put(ctrlShiftT, "SetCurrentDate");
                textField.getActionMap().put("SetCurrentDate", aa);

            }

            String clearField = "ClearField";
            AbstractAction clearAction = new AbstractAction(clearField) {
                @Override
                public void actionPerformed(ActionEvent e) {
                    destObj.setValue("", "");
                }
            };

            UIHelper.createLocalizedMenuItem(popupMenu, "ViewFactory.CLEAR", "", "", true, clearAction);

            textField.getInputMap().put(KeyStroke.getKeyStroke("F3"), clearField);
            textField.getActionMap().put(clearField, clearAction);

            textField.add(popupMenu);
            textField.setComponentPopupMenu(popupMenu);
        }
    }

    /**
     * Creates a ValTextArea.
     * @param validator a validator to hook the control up to (may be null)
     * @param cellField the definition of the cell for this control
     * @return ValTextArea
     */
    public static JTextArea createTextArea(final FormValidator validator, final FormCellField cellField,
            final boolean isRequired, final DBFieldInfo fieldInfo) {
        boolean doValidation = validator != null
                && (isRequired || isNotEmpty(cellField.getValidationRule()) || cellField.isChangeListenerOnly());

        ValTextArea textArea = new ValTextArea(cellField.getTxtRows(), cellField.getTxtCols());
        if (doValidation && fieldInfo != null && fieldInfo.getLength() > 0) {
            textArea.setDocument(new ValPlainTextDocument(fieldInfo.getLength()));
        }
        textArea.setRequired(isRequired);
        textArea.setRows(cellField.getTxtRows());

        if (doValidation && validator != null) {
            validator.hookupTextField(textArea, cellField.getIdent(), isRequired,
                    parseValidationType(cellField.getValidationType()), cellField.getValidationRule(),
                    cellField.isChangeListenerOnly() && !isRequired);
        }
        textArea.setLineWrap(true);
        textArea.setWrapStyleWord(true);

        textArea.setEditable(!cellField.isReadOnly() && validator != null);

        return textArea;
    }

    /**
     * Creates a ValTextAreaBrief.
     * @param validator a validator to hook the control up to (may be null)
     * @param cellField the definition of the cell for this control
     * @return ValTextArea
     */
    public static ValTextAreaBrief createTextAreaBrief(final FormValidator validator, final FormCellField cellField,
            final boolean isRequired, final DBFieldInfo fieldInfo) {
        boolean doValidation = validator != null
                && (isRequired || isNotEmpty(cellField.getValidationRule()) || cellField.isChangeListenerOnly());

        ValTextAreaBrief textArea = new ValTextAreaBrief(cellField.getTxtRows(), cellField.getTxtCols());
        if (doValidation && fieldInfo != null && fieldInfo.getLength() > 0) {
            textArea.setDocument(new ValPlainTextDocument(fieldInfo.getLength()));
        }
        textArea.setRequired(isRequired);
        textArea.initialize(validator != null);
        textArea.setRows(cellField.getTxtRows());

        if (doValidation && validator != null) {
            validator.hookupTextField(textArea, cellField.getIdent(), isRequired,
                    parseValidationType(cellField.getValidationType()), cellField.getValidationRule(),
                    cellField.isChangeListenerOnly() && !isRequired);
        }
        textArea.setLineWrap(true);
        textArea.setWrapStyleWord(true);

        textArea.setEditable(!cellField.isReadOnly() && validator != null);

        return textArea;
    }

    /**
     * Creates a ValListBox.
     * @param validator a validator to hook the control up to (may be null)
     * @param cellField the definition of the cell for this control
     * @param isRequired whether the field is required or not
     * @return ValListBox
     */
    public static JList createList(final FormValidator validator, final FormCellField cellField,
            final boolean isRequired) {
        String[] initArray = null;
        String dataStr = cellField.getProperty("data");
        if (isNotEmpty(dataStr)) {
            initArray = split(dataStr, ",");
            for (int i = 0; i < initArray.length; i++) {
                initArray[i] = initArray[i].trim();
            }
        }

        ValListBox valList = initArray == null ? new ValListBox() : new ValListBox(initArray);
        if (validator != null && (isRequired || isNotEmpty(cellField.getValidationRule()))) {
            DataChangeNotifier dcn = validator.hookupComponent(valList, cellField.getIdent(),
                    parseValidationType(cellField.getValidationType()), cellField.getValidationRule(), false);
            valList.getModel().addListDataListener(dcn);
            valList.addFocusListener(dcn);
        }
        valList.setRequired(isRequired);

        valList.setVisibleRowCount(cellField.getPropertyAsInt("rows", 15));

        return valList;
    }

    /**
     * Creates a ValComboBoxFromQuery.
     * @param validator a validator to hook the control up to (may be null)
     * @param cellField the definition of the cell for this control
     * @param isRequired whether the field is required or not
     * @return ValComboBoxFromQuery
     */
    public static ValComboBoxFromQuery createQueryComboBox(final FormValidator validator,
            final FormCellField cellField, final boolean isRequired, final boolean doAdjustQuery) {
        //String cbxName = cellField.getInitialize();
        String cbxName = cellField.getProperty("name");
        if (isNotEmpty(cbxName)) {
            int btnOpts = 0;
            btnOpts |= cellField.getPropertyAsBoolean("editbtn", true) ? ValComboBoxFromQuery.CREATE_EDIT_BTN : 0;
            btnOpts |= cellField.getPropertyAsBoolean("newbtn", true) ? ValComboBoxFromQuery.CREATE_NEW_BTN : 0;
            btnOpts |= cellField.getPropertyAsBoolean("searchbtn", true) ? ValComboBoxFromQuery.CREATE_SEARCH_BTN
                    : 0;
            btnOpts |= cellField.getPropertyAsBoolean("clonebtn", false) ? ValComboBoxFromQuery.CREATE_CLONE_BTN
                    : 0;

            String helpContext = cellField.getProperty("hc");

            ValComboBoxFromQuery cbx = TypeSearchForQueryFactory.getInstance().createValComboBoxFromQuery(cbxName,
                    btnOpts, cellField.getFormatName(), helpContext);
            if (cbx != null) {
                cbx.setRequired(isRequired);
                cbx.setSearchDlgName(cellField.getProperty("searchdlg"));
                cbx.setDisplayDlgName(cellField.getProperty("displaydlg"));

                if (validator != null)// && (cellField.isRequired() || isNotEmpty(cellField.getValidationRule())))
                {
                    DataChangeNotifier dcn = validator.hookupComponent(cbx, cellField.getIdent(),
                            parseValidationType(cellField.getValidationType()), cellField.getValidationRule(),
                            false);
                    cbx.addListSelectionListener(dcn);

                    //if (dcn.getValidationType() == UIValidator.Type.Focus) // returns None when no Validator
                    //{
                    cbx.addFocusListener(dcn);
                    //}
                }
                cbx.setCellName(cellField.getName());
                cbx.setDoAdjustQuery(doAdjustQuery);
            } else {
                UIRegistry.showLocalizedError("ERR_NEED_SHUTDOWN");
            }

            return cbx;

        }
        // else
        FormDevHelper.appendFormDevError("CBX Name for ValComboBoxFromQuery [" + cbxName + "] is empty!");
        return null;
    }

    /**
     * Creates a ValComboBox.
     * @param validator a validator to hook the control up to (may be null)
     * @param cellField the definition of the cell for this control
     * @param isRequired whether the field is required or not
     * @return ValComboBox
     */
    public static ValComboBox createValComboBox(final FormValidator validator, final FormCellField cellField,
            final PickListDBAdapterIFace adapter, final boolean isRequired) {
        boolean makeEditable = cellField.getPropertyAsBoolean("editable", false);
        ValComboBox cbx = null;
        if (adapter != null) {
            cbx = new ValComboBox(adapter); // false means don't auto-create picklist

        } else {
            String[] initArray = null;
            String data = cellField.getProperty("data");
            if (isNotEmpty(data)) {
                initArray = split(data, ",");
                for (int i = 0; i < initArray.length; i++) {
                    initArray[i] = initArray[i].trim();
                }
            }

            cbx = initArray == null || initArray.length == 0 ? new ValComboBox(makeEditable)
                    : new ValComboBox(initArray, makeEditable);
        }
        cbx.setRequired(isRequired);

        if (validator != null
                && (isRequired || cellField.isChangeListenerOnly() || isNotEmpty(cellField.getValidationRule()))) {
            DataChangeNotifier dcn = validator.hookupComponent(cbx, cellField.getIdent(),
                    parseValidationType(cellField.getValidationType()), cellField.getValidationRule(),
                    cellField.isChangeListenerOnly());
            //cbx.getModel().addListDataListener(dcn);
            cbx.getComboBox().addActionListener(dcn);
            cbx.addChangeListener(dcn);

            if (dcn.getValidationType() == UIValidator.Type.Focus) // returns None when no Validator
            {
                cbx.addFocusListener(dcn);
            }
        }
        return cbx;
    }

    /**
     * Makes adjusts to the border and the colors to make it "flat" for display mode.
     * @param textField the text field to be flattened
     * @param isTransparent make the background transparent instead of using the viewFieldColor
     */
    public static void changeTextFieldUIForDisplay(final JTextField textField, final boolean isTransparent) {
        changeTextFieldUIForDisplay(textField, null, isTransparent);
    }

    /**
     * Makes adjusts to the border and the colors to make it "flat" for display mode.
     * @param textField the text field to be flattened
     * @param isTransparent make the background transparent instead of using the viewFieldColor
     */
    public static void changeTextFieldUIForDisplay(final JTextField textField, final Color borderColor,
            final boolean isTransparent) {
        Insets insets = textField.getBorder().getBorderInsets(textField);
        if (borderColor != null) {
            textField.setBorder(BorderFactory.createMatteBorder(Math.min(insets.top, 3), Math.min(insets.left, 3),
                    Math.min(insets.bottom, 3), Math.min(insets.right, 3), borderColor));
        } else {
            textField.setBorder(BorderFactory.createEmptyBorder(Math.min(insets.top, 3), Math.min(insets.left, 3),
                    Math.min(insets.bottom, 3), Math.min(insets.right, 3)));
        }
        textField.setForeground(Color.BLACK);
        textField.setEditable(false);
        //textField.setFocusable(false); // rods - commented out because it makes it so you can't select and copy

        textField.setOpaque(!isTransparent);
        if (isTransparent) {
            textField.setBackground(null);

        } else if (viewFieldColor != null) {
            textField.setBackground(viewFieldColor.getColor());
        }
    }

    /**
     * @param textField
     * @param border
     * @param fgColor
     * @param bgColor
     * @param isOpaque
     */
    public static void changeTextFieldUIForEdit(final JTextField textField, final Border border,
            final Color fgColor, final Color bgColor, final boolean isOpaque) {
        textField.setBorder(border);
        textField.setForeground(fgColor);
        textField.setEditable(true);
        textField.setFocusable(true);
        textField.setOpaque(isOpaque);
        textField.setBackground(bgColor);
    }

    /**
     * Creates a JTextArea for display purposes only.
     * @param cellField FormCellField info
     * @return the control
     */
    public static JScrollPane changeTextAreaForDisplay(final JTextArea ta) {
        Insets insets = ta.getBorder().getBorderInsets(ta);
        ta.setBorder(BorderFactory.createEmptyBorder(insets.top, insets.left, insets.bottom, insets.bottom));
        ta.setForeground(Color.BLACK);
        ta.setEditable(false);
        ta.setBackground(viewFieldColor.getColor());
        ta.setLineWrap(true);
        ta.setWrapStyleWord(true);

        JScrollPane scrollPane = new JScrollPane(ta);
        insets = scrollPane.getBorder().getBorderInsets(scrollPane);
        scrollPane.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
        scrollPane.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED);
        scrollPane
                .setBorder(BorderFactory.createEmptyBorder(insets.top, insets.left, insets.bottom, insets.bottom));

        return scrollPane;
    }

    /**
     * Creates a JTextArea for display purposes only.
     * @param cellField FormCellField info
     * @return the control
     */
    public static JScrollPane createDisplayTextArea(final FormCellFieldIFace cellField) {
        JTextArea ta = new JTextArea(cellField.getTxtRows(), cellField.getTxtCols());
        return changeTextAreaForDisplay(ta);
    }

    /**
     * Creates a TextFieldWithInfo.
     * @param cellField FormCellField info
     * @param parent the parent mulitview needed because of pop Dialogs (from the info btn)
     * @return the control
     */
    public static TextFieldWithInfo createTextFieldWithInfo(final FormCellField cellField, final MultiView parent) {
        TextFieldWithInfo textFieldInfo = null;
        String txtName = cellField.getProperty("name");
        if (isNotEmpty(txtName)) {
            textFieldInfo = TypeSearchForQueryFactory.getInstance().getTextFieldWithInfo(txtName,
                    cellField.getFormatName());
            if (textFieldInfo != null) {
                textFieldInfo.setMultiView(parent);
                textFieldInfo.setFrameTitle(cellField.getProperty("title"));
                JTextField textField = textFieldInfo.getTextField();
                textField.setColumns(cellField.getTxtCols());

                // Overrides the defined in the TableInfo
                String displayInfoDialogName = cellField.getProperty("displaydlg");
                if (StringUtils.isNotEmpty(displayInfoDialogName)) {
                    textFieldInfo.setDisplayInfoDialogName(displayInfoDialogName);
                }

                changeTextFieldUIForDisplay(textField, false);

            } else {
                String msg = "Could TypeSearchForQueryFactory.getTextFieldWithInfo(" + txtName + ")";
                log.error(msg);
                FormDevHelper.appendFormDevError(msg);
            }
        } else {
            String msg = "textfieldinfo Name for textFieldWithInfo [" + txtName + "] is empty!";
            log.error(msg);
            FormDevHelper.appendFormDevError(msg);
        }
        return textFieldInfo;
    }

    /**
     * Creates an ImageDisplay control.
     * @param cellField FormCellField info
     * @param mode indicates whether in Edit or View mode
     * @param validator the validator
     * @return the control
     */
    public static ImageDisplay createImageDisplay(final FormCellField cellField,
            final AltViewIFace.CreationMode mode, final FormValidator validator) {
        int w = 150;
        int h = 150;
        String sizeDefStr = cellField.getProperty("size");
        if (isNotEmpty(sizeDefStr)) {
            String[] wh = StringUtils.split(sizeDefStr, ",");
            if (wh.length == 2) {
                try {
                    w = Integer.parseInt(wh[0]);
                    h = Integer.parseInt(wh[1]);

                } catch (Exception ex) {
                    edu.ku.brc.af.core.UsageTracker.incrHandledUsageCount();
                    edu.ku.brc.exceptions.ExceptionTracker.getInstance().capture(ViewFactory.class, ex);
                    log.error("size prop for Image is incorrect [" + sizeDefStr + "]");
                }
            }

        }

        boolean imageInEdit = mode == AltViewIFace.CreationMode.EDIT;
        String editModeStr = cellField.getProperty("edit");
        if (isNotEmpty(editModeStr)) {
            imageInEdit = editModeStr.toLowerCase().equals("true");
        }

        // create a new ImageDisplay
        // override the selectNewImage method to notify the parent MultiView when a change occurs
        ImageDisplay imgDisp = new ImageDisplay(w, h, imageInEdit, cellField.getPropertyAsBoolean("border", true));

        if (validator != null) {
            DataChangeNotifier dcn = validator.hookupComponent(imgDisp, cellField.getIdent(),
                    parseValidationType(cellField.getValidationType()), cellField.getValidationRule(), false);
            imgDisp.addPropertyChangeListener("imageURL", dcn);

            if (dcn.getValidationType() == UIValidator.Type.Focus) // returns None when no Validator
            {
                imgDisp.addFocusListener(dcn);
            }
        }

        String urlStr = cellField.getProperty("url");
        if (isNotEmpty(urlStr)) {
            imgDisp.setValue(urlStr, "");
        } else {
            String name = cellField.getProperty("icon");
            if (isNotEmpty(name)) {
                boolean loadIt = true;
                String iconSize = cellField.getProperty("iconsize");
                if (isNotEmpty(iconSize)) {
                    IconManager.IconSize sz = IconManager.getIconSize(Integer.parseInt(iconSize), false, false);
                    if (sz != null) {
                        imgDisp.setImage(IconManager.getImage(name, sz));
                        loadIt = false;
                    }

                }

                if (loadIt) {
                    imgDisp.setImage(IconManager.getIcon(name));
                }
            }
        }
        return imgDisp;
    }

    /**
     * @param fcf
     * @return
     */
    private JButton createFormButton(final FormCellIFace fcf, final String text) {
        String tooltip = fcf.getProperty("tooltip");
        String iconName = fcf.getProperty("icon");
        String sizeStr = fcf.getProperty("size");

        if (StringUtils.isNotEmpty(text)) {
            return createButton(text);

        } else if (StringUtils.isNotEmpty(iconName)) {
            int iconSize = StringUtils.isNotEmpty(sizeStr) && StringUtils.isNumeric(sizeStr)
                    ? Integer.parseInt(sizeStr)
                    : 16;
            IconManager.IconSize iSize = IconManager.getIconSize(iconSize, false, false);
            IconButton iconBtn = new IconButton(IconManager.getIcon(iconName, iSize), true);
            iconBtn.setEnabled(true);
            iconBtn.setToolTipText(UIRegistry.getResourceString(tooltip));
            return iconBtn;
        }
        return createButton("?");
    }

    /**
     * Creates an ImageDisplay control,
     * @param cellField FormCellField info
     * @param isViewMode indicates whether in Edit or View mode
     * @param isRequired whether the field is required or not
     * @return the control
     */
    protected static UIPluginable createPlugin(final MultiView parent, final FormValidator validator,
            final FormCellField cellField, final boolean isViewMode, final boolean isRequired) {
        String pluginName = cellField.getProperty("name");
        if (StringUtils.isEmpty(pluginName)) {
            String msg = "Creating plugin and the name property was missing. [" + cellField.getName() + "]";
            log.error(msg);
            FormDevHelper.appendFormDevError(msg);
            return null;
        }

        // We should refactor the plugin manager.
        Class<?> pluginClass = TaskMgr.getUIPluginClassForName(pluginName);
        if (pluginClass != null && UIPluginable.class.isAssignableFrom(pluginClass)) {
            try {
                // instantiate the plugin object
                UIPluginable uiPlugin = pluginClass.asSubclass(UIPluginable.class).newInstance();

                uiPlugin.setCellName(cellField.getName());

                Properties props = (Properties) cellField.getProperties().clone();

                //log.debug(cellField.getName());
                if (uiPlugin instanceof WebLinkButton) {
                    //if (StringUtils.isNotEmpty((String)props.get("weblink")))
                    {
                        DBTableInfo tInfo = DBTableIdMgr.getInstance()
                                .getByClassName(parent.getView().getClassName());
                        if (tInfo != null) {
                            //log.debug(cellField.getName());
                            DBFieldInfo fInfo = tInfo.getFieldByName(cellField.getName());
                            if (fInfo != null) {
                                //log.debug(fInfo.getFormatStr() + " weblink: "+fInfo.getWebLinkName());
                                if (StringUtils.isEmpty((String) props.get("weblink"))
                                        && StringUtils.isNotEmpty(fInfo.getWebLinkName())) {
                                    props.put("weblink", fInfo.getWebLinkName());
                                }
                            }
                        }
                    }
                }

                // This needs to be done before the initialize.
                if (uiPlugin instanceof UIValidatable) {
                    ((UIValidatable) uiPlugin).setRequired(isRequired);
                }

                // initialize the plugin object

                uiPlugin.initialize(props, isViewMode);

                // get the UI component provided by the plugin object
                JComponent pluginUI = uiPlugin.getUIComponent();

                // check for another required interface (GetSetValueIFace)
                if (!(uiPlugin instanceof GetSetValueIFace)) {
                    FormDevHelper.appendFormDevError("Plugin of class [" + pluginClass.getName()
                            + "] doesn't implement the GetSetValueIFace!");
                    return null;
                }

                if (validator != null) {
                    DataChangeNotifier dcn = validator.hookupComponent(pluginUI, cellField.getIdent(),
                            parseValidationType(cellField.getValidationType()), cellField.getValidationRule(),
                            false);
                    uiPlugin.addChangeListener(dcn);
                }

                return uiPlugin;

            } catch (Exception ex) {
                log.error(ex);
                ex.printStackTrace();
                FormDevHelper.appendFormDevError(ex);
            }
        }
        log.error("Couldn't find plugin by name[" + pluginName + "]");
        return null;
    }

    /**
     * @param mvParent
     * @param subviewDef
     * @param view
     * @param dataType
     * @param options
     * @param props
     * @param classToCreate
     * @param mode
     * @return
     */
    protected SubViewBtn createSubViewBtn(final MultiView mvParent, final FormCellSubViewIFace subviewDef,
            final ViewIFace view, final DATA_TYPE dataType, final int options, final Properties props,
            final Class<?> classToCreate, final AltViewIFace.CreationMode mode) {
        return new SubViewBtn(mvParent, subviewDef, view, dataType, options, props, classToCreate, mode);
    }

    //----------------------------------------------------------------------------------------------------------------
    //-- 
    //----------------------------------------------------------------------------------------------------------------
    class BuildInfoStruct {
        public HashMap<CollapsableSeparator, String> collapseSepHash = null;

        public int curMaxRow = 0;
        public JComponent compToAdd = null;
        public JComponent compToReg = null;
        public boolean doAddToValidator = true;
        public boolean doRegControl = true;
        public int colInx = 0;
        public boolean isRequired = false;
        public boolean isDerivedLabel = false;

        public void clear() {
            curMaxRow = 0;
            compToAdd = null;
            compToReg = null;
            doAddToValidator = true;
            doRegControl = true;
            colInx = 0;
            isRequired = false;
            isDerivedLabel = false;

            if (collapseSepHash != null) {
                collapseSepHash.clear();
            }
        }
    }

    protected boolean createItem(final DBTableInfo parentTableInfo, final DBTableChildIFace childInfo,
            final MultiView parent, final ViewDefIFace viewDef, final FormValidator validator,
            final ViewBuilderIFace viewBldObj, final AltViewIFace.CreationMode mode,
            final HashMap<String, JLabel> labelsForHash, final Object currDataObj, final FormCellIFace cell,
            final boolean isEditOnCreateOnly, final int rowInx, final BuildInfoStruct bi) {
        bi.compToAdd = null;
        bi.compToReg = null;
        bi.doAddToValidator = true;
        bi.doRegControl = true;

        DBRelationshipInfo relInfo = childInfo instanceof DBRelationshipInfo ? (DBRelationshipInfo) childInfo
                : null;

        if (isEditOnCreateOnly) {
            EditViewCompSwitcherPanel evcsp = new EditViewCompSwitcherPanel(cell);
            bi.compToAdd = evcsp;
            bi.compToReg = evcsp;

            if (validator != null) {
                //DataChangeNotifier dcn = validator.createDataChangeNotifer(cell.getIdent(), evcsp, null);
                DataChangeNotifier dcn = validator.hookupComponent(evcsp, cell.getIdent(), UIValidator.Type.Changed,
                        null, false);
                evcsp.setDataChangeNotifier(dcn);
            }

        } else if (cell.getType() == FormCellIFace.CellType.label) {
            FormCellLabel cellLabel = (FormCellLabel) cell;

            String lblStr = cellLabel.getLabel();
            if (cellLabel.isRecordObj()) {
                JComponent riComp = viewBldObj.createRecordIndentifier(lblStr, cellLabel.getIcon());
                bi.compToAdd = riComp;

            } else {
                String lStr = "  ";
                int align = SwingConstants.RIGHT;
                boolean useColon = StringUtils.isNotEmpty(cellLabel.getLabelFor());

                if (lblStr.equals("##")) {
                    //lStr = "  ";
                    bi.isDerivedLabel = true;
                    cellLabel.setDerived(true);

                } else {
                    String alignProp = cellLabel.getProperty("align");
                    if (StringUtils.isNotEmpty(alignProp)) {
                        if (alignProp.equals("left")) {
                            align = SwingConstants.LEFT;

                        } else if (alignProp.equals("center")) {
                            align = SwingConstants.CENTER;

                        } else {
                            align = SwingConstants.RIGHT;
                        }
                    } else if (useColon) {
                        align = SwingConstants.RIGHT;
                    } else {
                        align = SwingConstants.LEFT;
                    }

                    if (isNotEmpty(lblStr)) {
                        if (useColon) {
                            lStr = lblStr + ":";
                        } else {
                            lStr = lblStr;
                        }
                    } else {
                        lStr = "  ";
                    }
                }

                if (lStr.indexOf(LF) > -1) {
                    lStr = "<html>" + StringUtils.replace(lStr, LF, "<br>") + "</html>";
                }
                JLabel lbl = createLabel(lStr, align);
                String colorStr = cellLabel.getProperty("fg");
                if (StringUtils.isNotEmpty(colorStr)) {
                    lbl.setForeground(UIHelper.parseRGB(colorStr));
                }
                labelsForHash.put(cellLabel.getLabelFor(), lbl);
                bi.compToAdd = lbl;
                viewBldObj.addLabel(cellLabel, lbl);
            }

            bi.doAddToValidator = false;
            bi.doRegControl = false;

        } else if (cell.getType() == FormCellIFace.CellType.field) {
            FormCellField cellField = (FormCellField) cell;

            bi.isRequired = bi.isRequired || cellField.isRequired()
                    || (childInfo != null && childInfo.isRequired());

            DBFieldInfo fieldInfo = childInfo instanceof DBFieldInfo ? (DBFieldInfo) childInfo : null;
            if (fieldInfo != null && fieldInfo.isHidden()) {
                FormDevHelper.appendLocalizedFormDevError("ViewFactory.FORM_FIELD_HIDDEN", cellField.getIdent(),
                        cellField.getName(), viewDef.getName());
            } else {

                if (fieldInfo != null && fieldInfo.isHidden()) {
                    FormDevHelper.appendLocalizedFormDevError("ViewFactory.FORM_REL_HIDDEN", cellField.getIdent(),
                            cellField.getName(), viewDef.getName());
                }
            }

            FormCellField.FieldType uiType = cellField.getUiType();

            // Check to see if there is a PickList and get it if there is
            PickListDBAdapterIFace adapter = null;

            String pickListName = cellField.getPickListName();
            if (childInfo != null && StringUtils.isEmpty(pickListName) && fieldInfo != null) {
                pickListName = fieldInfo.getPickListName();
            }

            if (isNotEmpty(pickListName)) {
                adapter = PickListDBAdapterFactory.getInstance().create(pickListName, false);

                if (adapter == null || adapter.getPickList() == null) {
                    FormDevHelper.appendFormDevError("PickList Adapter [" + pickListName + "] cannot be null!");
                    return false;
                }
            }

            /*if (uiType == FormCellFieldIFace.FieldType.text)
            {
            String weblink = cellField.getProperty("weblink");
            if (StringUtils.isNotEmpty(weblink))
            {
                String name = cellField.getProperty("name");
                if (StringUtils.isNotEmpty(name) && name.equals("WebLink"))
                {
                    uiType
                }
            }
            }*/

            // The Default Display for combox is dsptextfield, except when there is a TableBased PickList
            // At the time we set the display we don't want to go get the picklist to find out. So we do it
            // here after we have the picklist and actually set the change into the cellField
            // because it uses the value to determine whether to convert the value into a text string 
            // before setting it.
            if (mode == AltViewIFace.CreationMode.VIEW) {
                if (uiType == FormCellFieldIFace.FieldType.combobox
                        && cellField.getDspUIType() != FormCellFieldIFace.FieldType.textpl) {
                    if (adapter != null)// && adapter.isTabledBased())
                    {
                        uiType = FormCellFieldIFace.FieldType.textpl;
                        cellField.setDspUIType(uiType);

                    } else {
                        uiType = cellField.getDspUIType();
                    }
                } else {
                    uiType = cellField.getDspUIType();
                }
            } else if (uiType == FormCellField.FieldType.querycbx) {
                if (AppContextMgr.isSecurityOn()) {
                    DBTableInfo tblInfo = childInfo != null
                            ? DBTableIdMgr.getInstance()
                                    .getByShortClassName(childInfo.getDataClass().getSimpleName())
                            : null;
                    if (tblInfo != null) {
                        PermissionSettings perm = tblInfo.getPermissions();
                        if (perm != null) {
                            //PermissionSettings.dumpPermissions("QCBX: "+tblInfo.getShortClassName(), perm.getOptions());
                            if (perm.isViewOnly() || !perm.canView()) {
                                uiType = FormCellField.FieldType.textfieldinfo;
                            }
                        }
                    }
                }
            }

            Class<?> fieldClass = childInfo != null ? childInfo.getDataClass() : null;
            String uiFormatName = cellField.getUIFieldFormatterName();

            if (mode == AltViewIFace.CreationMode.EDIT && uiType == FormCellField.FieldType.text
                    && fieldClass != null) {
                if (fieldClass == String.class && fieldInfo != null) {
                    // check whether there's a formatter defined for this field in the schema
                    if (fieldInfo.getFormatter() != null) {
                        uiFormatName = fieldInfo.getFormatter().getName();
                        uiType = FormCellField.FieldType.formattedtext;
                    }
                } else if (fieldClass == Integer.class || fieldClass == Long.class || fieldClass == Short.class
                        || fieldClass == Byte.class || fieldClass == Double.class || fieldClass == Float.class
                        || fieldClass == BigDecimal.class) {
                    //log.debug(cellField.getName()+"  is being changed to NUMERIC");
                    uiType = FormCellField.FieldType.formattedtext;
                    uiFormatName = "Numeric" + fieldClass.getSimpleName();
                }
            }

            // Create the UI Component

            boolean isReq = cellField.isRequired() || (fieldInfo != null && fieldInfo.isRequired())
                    || (relInfo != null && relInfo.isRequired());
            cellField.setRequired(isReq);

            switch (uiType) {
            case text:

                bi.compToAdd = createTextField(validator, cellField, fieldInfo, isReq, adapter);
                bi.doAddToValidator = validator == null; // might already added to validator
                break;

            case formattedtext: {
                Class<?> tableClass = null;
                try {
                    tableClass = Class.forName(viewDef.getClassName());
                } catch (Exception ex) {
                }

                JComponent tfStart = createFormattedTextField(validator, cellField, tableClass,
                        fieldInfo != null ? fieldInfo.getLength() : 0, uiFormatName,
                        mode == AltViewIFace.CreationMode.VIEW, isReq,
                        cellField.getPropertyAsBoolean("alledit", false));
                bi.compToAdd = tfStart;
                if (cellField.getPropertyAsBoolean("series", false)) {
                    JComponent tfEnd = createFormattedTextField(validator, cellField, tableClass,
                            fieldInfo != null ? fieldInfo.getLength() : 0, uiFormatName,
                            mode == AltViewIFace.CreationMode.VIEW, isReq,
                            cellField.getPropertyAsBoolean("alledit", false));

                    // Make sure we register it like a plugin not a regular control
                    SeriesProcCatNumPlugin plugin = new SeriesProcCatNumPlugin((ValFormattedTextFieldIFace) tfStart,
                            (ValFormattedTextFieldIFace) tfEnd);
                    bi.compToAdd = plugin.getUIComponent();
                    viewBldObj.registerPlugin(cell, plugin);
                    bi.doRegControl = false;
                }
                bi.doAddToValidator = validator == null; // might already added to validator
                break;
            }
            case label:
                JLabel label = createLabel("", SwingConstants.LEFT);
                bi.compToAdd = label;
                break;

            case dsptextfield:
                if (StringUtils.isEmpty(cellField.getPickListName())) {
                    JTextField text = UIHelper.createTextField(cellField.getTxtCols());
                    changeTextFieldUIForDisplay(text, cellField.getPropertyAsBoolean("transparent", false));
                    bi.compToAdd = text;
                } else {
                    bi.compToAdd = createTextField(validator, cellField, fieldInfo, isReq, adapter);
                    bi.doAddToValidator = validator == null; // might already added to validator
                }
                break;

            case textfieldinfo:
                bi.compToAdd = createTextFieldWithInfo(cellField, parent);
                break;

            case image:
                bi.compToAdd = createImageDisplay(cellField, mode, validator);
                bi.doAddToValidator = (validator != null);
                break;

            case url:
                BrowserLauncherBtn blb = new BrowserLauncherBtn(cellField.getProperty("title"));
                bi.compToAdd = blb;
                bi.doAddToValidator = false;

                break;

            case combobox:
                bi.compToAdd = createValComboBox(validator, cellField, adapter, isReq);
                bi.doAddToValidator = validator != null; // might already added to validator
                break;

            case checkbox: {
                String lblStr = cellField.getLabel();
                if (lblStr.equals("##")) {
                    bi.isDerivedLabel = true;
                    cellField.setDerived(true);
                }
                ValCheckBox checkbox = new ValCheckBox(lblStr, isReq,
                        cellField.isReadOnly() || mode == AltViewIFace.CreationMode.VIEW);
                if (validator != null) {
                    DataChangeNotifier dcn = validator.createDataChangeNotifer(cellField.getIdent(), checkbox,
                            validator.createValidator(checkbox, UIValidator.Type.Changed));
                    checkbox.addActionListener(dcn);
                    checkbox.addItemListener(dcn);
                }
                bi.compToAdd = checkbox;
                break;
            }

            case tristate: {
                String lblStr = cellField.getLabel();
                if (lblStr.equals("##")) {
                    bi.isDerivedLabel = true;
                    cellField.setDerived(true);
                }
                ValTristateCheckBox tristateCB = new ValTristateCheckBox(lblStr, isReq,
                        cellField.isReadOnly() || mode == AltViewIFace.CreationMode.VIEW);
                if (validator != null) {
                    DataChangeNotifier dcn = validator.createDataChangeNotifer(cellField.getIdent(), tristateCB,
                            null);
                    tristateCB.addActionListener(dcn);
                }
                bi.compToAdd = tristateCB;
                break;
            }

            case spinner: {
                String minStr = cellField.getProperty("min");
                int min = StringUtils.isNotEmpty(minStr) ? Integer.parseInt(minStr) : 0;

                String maxStr = cellField.getProperty("max");
                int max = StringUtils.isNotEmpty(maxStr) ? Integer.parseInt(maxStr) : 0;

                ValSpinner spinner = new ValSpinner(min, max, isReq,
                        cellField.isReadOnly() || mode == AltViewIFace.CreationMode.VIEW);
                if (validator != null) {
                    DataChangeNotifier dcn = validator.createDataChangeNotifer(cellField.getIdent(), spinner,
                            validator.createValidator(spinner, UIValidator.Type.Changed));
                    spinner.addChangeListener(dcn);
                }
                bi.compToAdd = spinner;
                break;
            }

            case password:
                bi.compToAdd = createPasswordField(validator, cellField, isReq);
                bi.doAddToValidator = validator == null; // might already added to validator
                break;

            case dsptextarea:
                bi.compToAdd = createDisplayTextArea(cellField);
                break;

            case textarea: {
                JTextArea ta = createTextArea(validator, cellField, isReq, fieldInfo);
                JScrollPane scrollPane = new JScrollPane(ta);
                scrollPane.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_AS_NEEDED);
                scrollPane.setVerticalScrollBarPolicy(
                        UIHelper.isMacOS() ? ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS
                                : ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED);
                ta.setLineWrap(true);
                ta.setWrapStyleWord(true);

                bi.doAddToValidator = validator == null; // might already added to validator
                bi.compToReg = ta;
                bi.compToAdd = scrollPane;
                break;
            }

            case textareabrief: {
                String title = "";
                DBTableInfo ti = DBTableIdMgr.getInstance().getByClassName(viewDef.getClassName());
                if (ti != null) {
                    DBFieldInfo fi = ti.getFieldByName(cellField.getName());
                    if (fi != null) {
                        title = fi.getTitle();
                    }
                }

                ValTextAreaBrief txBrief = createTextAreaBrief(validator, cellField, isReq, fieldInfo);
                txBrief.setTitle(title);

                bi.doAddToValidator = validator == null; // might already added to validator
                bi.compToReg = txBrief;
                bi.compToAdd = txBrief.getUIComponent();
                break;
            }

            case browse: {
                JTextField textField = createTextField(validator, cellField, null, isReq, null);
                if (textField instanceof ValTextField) {
                    ValBrowseBtnPanel bbp = new ValBrowseBtnPanel((ValTextField) textField,
                            cellField.getPropertyAsBoolean("dirsonly", false),
                            cellField.getPropertyAsBoolean("forinput", true));
                    String fileFilter = cellField.getProperty("filefilter");
                    String fileFilterDesc = cellField.getProperty("filefilterdesc");
                    String defaultExtension = cellField.getProperty("defaultExtension");
                    if (fileFilter != null && fileFilterDesc != null) {
                        bbp.setUseNativeFileDlg(false);
                        bbp.setFileFilter(new FileNameExtensionFilter(fileFilterDesc, fileFilter));
                        bbp.setDefaultExtension(defaultExtension);
                        //bbp.setNativeDlgFilter(new FileNameExtensionFilter(fileFilterDesc, fileFilter));
                    }
                    bi.compToAdd = bbp;

                } else {
                    BrowseBtnPanel bbp = new BrowseBtnPanel(textField,
                            cellField.getPropertyAsBoolean("dirsonly", false),
                            cellField.getPropertyAsBoolean("forinput", true));
                    bi.compToAdd = bbp;
                }
                break;
            }

            case querycbx: {
                ValComboBoxFromQuery cbx = createQueryComboBox(validator, cellField, isReq,
                        cellField.getPropertyAsBoolean("adjustquery", true));
                cbx.setMultiView(parent);
                cbx.setFrameTitle(cellField.getProperty("title"));

                bi.compToAdd = cbx;
                bi.doAddToValidator = validator == null; // might already added to validator
                break;
            }

            case list: {
                JList list = createList(validator, cellField, isReq);

                JScrollPane scrollPane = new JScrollPane(list);
                scrollPane.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_AS_NEEDED);
                scrollPane.setVerticalScrollBarPolicy(
                        UIHelper.isMacOS() ? ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS
                                : ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED);

                bi.doAddToValidator = validator == null;
                bi.compToReg = list;
                bi.compToAdd = scrollPane;
                break;
            }

            case colorchooser: {
                ColorChooser colorChooser = new ColorChooser(Color.BLACK);
                if (validator != null) {
                    DataChangeNotifier dcn = validator.createDataChangeNotifer(cellField.getName(), colorChooser,
                            null);
                    colorChooser.addPropertyChangeListener("setValue", dcn);
                }
                //setControlSize(colorChooser);
                bi.compToAdd = colorChooser;

                break;
            }

            case button:
                JButton btn = createFormButton(cellField, cellField.getProperty("title"));
                bi.compToAdd = btn;
                break;

            case progress:
                bi.compToAdd = createProgressBar(0, 100);
                break;

            case plugin:
                UIPluginable uip = createPlugin(parent, validator, cellField,
                        mode == AltViewIFace.CreationMode.VIEW, isReq);
                if (uip != null) {
                    bi.compToAdd = uip.getUIComponent();
                    viewBldObj.registerPlugin(cell, uip);
                } else {
                    bi.compToAdd = new JPanel();
                    log.error("Couldn't create UIPlugin [" + cellField.getName() + "] ID:" + cellField.getIdent());
                }
                bi.doRegControl = false;
                break;

            case textpl:
                JTextField txt = new TextFieldFromPickListTable(adapter, cellField.getTxtCols());
                changeTextFieldUIForDisplay(txt, cellField.getPropertyAsBoolean("transparent", false));
                bi.compToAdd = txt;
                break;

            default:
                FormDevHelper.appendFormDevError("Don't recognize uitype=[" + uiType + "]");

            } // switch

        } else if (cell.getType() == FormCellIFace.CellType.separator) {
            // still have compToAdd = null;
            FormCellSeparatorIFace fcs = (FormCellSeparatorIFace) cell;
            String collapsableName = fcs.getCollapseCompName();

            String label = fcs.getLabel();
            if (StringUtils.isEmpty(label) || label.equals("##")) {
                String className = fcs.getProperty("forclass");
                if (StringUtils.isNotEmpty(className)) {
                    DBTableInfo ti = DBTableIdMgr.getInstance().getByShortClassName(className);
                    if (ti != null) {
                        label = ti.getTitle();
                    }
                }
            }
            Component sep = viewBldObj.createSeparator(label);
            if (isNotEmpty(collapsableName)) {
                CollapsableSeparator collapseSep = new CollapsableSeparator(sep, false, null);
                if (bi.collapseSepHash == null) {
                    bi.collapseSepHash = new HashMap<CollapsableSeparator, String>();
                }
                bi.collapseSepHash.put(collapseSep, collapsableName);
                sep = collapseSep;

            }
            bi.doRegControl = cell.getName().length() > 0;
            bi.compToAdd = (JComponent) sep;
            bi.doRegControl = StringUtils.isNotEmpty(cell.getIdent());
            bi.doAddToValidator = false;

        } else if (cell.getType() == FormCellIFace.CellType.command) {
            FormCellCommand cellCmd = (FormCellCommand) cell;
            JButton btn = createFormButton(cell, cellCmd.getLabel());
            if (cellCmd.getCommandType().length() > 0) {
                btn.addActionListener(new CommandActionWrapper(
                        new CommandAction(cellCmd.getCommandType(), cellCmd.getAction(), "")));
            }
            bi.doAddToValidator = false;
            bi.compToAdd = btn;

        } else if (cell.getType() == FormCellIFace.CellType.iconview) {
            FormCellSubView cellSubView = (FormCellSubView) cell;

            String subViewName = cellSubView.getViewName();

            ViewIFace subView = AppContextMgr.getInstance().getView(cellSubView.getViewSetName(), subViewName);
            if (subView != null) {
                if (parent != null) {
                    int options = MultiView.VIEW_SWITCHER
                            | (MultiView.isOptionOn(parent.getCreateOptions(), MultiView.IS_NEW_OBJECT)
                                    ? MultiView.IS_NEW_OBJECT
                                    : MultiView.NO_OPTIONS);

                    options |= cellSubView.getPropertyAsBoolean("nosep", false) ? MultiView.DONT_USE_EMBEDDED_SEP
                            : 0;
                    options |= cellSubView.getPropertyAsBoolean("nosepmorebtn", false)
                            ? MultiView.NO_MORE_BTN_FOR_SEP
                            : 0;

                    MultiView multiView = new MultiView(parent, cellSubView.getName(), subView,
                            parent.getCreateWithMode(), options, null);
                    parent.addChildMV(multiView);
                    multiView.setClassToCreate(getClassToCreate(parent, cell));

                    log.debug("[" + cell.getType() + "] [" + cell.getName() + "] col: " + bi.colInx + " row: "
                            + rowInx + " colspan: " + cell.getColspan() + " rowspan: " + cell.getRowspan());
                    viewBldObj.addSubView(cellSubView, multiView, bi.colInx, rowInx, cellSubView.getColspan(), 1);
                    viewBldObj.closeSubView(cellSubView);
                    bi.curMaxRow = rowInx;
                    bi.colInx += cell.getColspan() + 1;
                } else {
                    log.error("buildFormView - parent is NULL for subview [" + subViewName + "]");
                }

            } else {
                log.error("buildFormView - Could find subview's with ViewSet[" + cellSubView.getViewSetName()
                        + "] ViewName[" + subViewName + "]");
            }
            // still have compToAdd = null;
            bi.colInx += 2;

        } else if (cell.getType() == FormCellIFace.CellType.subview) {
            FormCellSubView cellSubView = (FormCellSubView) cell;
            String subViewName = cellSubView.getViewName();
            ViewIFace subView = AppContextMgr.getInstance().getView(cellSubView.getViewSetName(), subViewName);

            if (subView != null) {
                // Check to see this view should be "flatten" meaning we are creating a grid from a form
                if (!viewBldObj.shouldFlatten()) {
                    if (parent != null) {
                        ViewIFace parentView = parent.getView();
                        Properties props = cellSubView.getProperties();

                        boolean isSingle = cellSubView.isSingleValueFromSet();
                        boolean isACollection = false;

                        try {
                            Class<?> cls = Class.forName(parentView.getClassName());
                            Field fld = getFieldFromDotNotation(cellSubView, cls);
                            if (fld != null) {
                                isACollection = Collection.class.isAssignableFrom(fld.getType());
                            } else {
                                log.error("Couldn't find field [" + cellSubView.getName() + "] in class ["
                                        + parentView.getClassName() + "]");
                            }
                        } catch (Exception ex) {
                            log.error("Couldn't find field [" + cellSubView.getName() + "] in class ["
                                    + parentView.getClassName() + "]");
                            edu.ku.brc.af.core.UsageTracker.incrHandledUsageCount();
                            edu.ku.brc.exceptions.ExceptionTracker.getInstance().capture(ViewFactory.class, ex);
                        }

                        if (isSingle) {
                            isACollection = true;
                        }

                        boolean useNoScrollbars = UIHelper.getProperty(props, "noscrollbars", false);
                        //Assume RecsetController will always be handled correctly for one-to-one
                        boolean hideResultSetController = relInfo == null ? false
                                : relInfo.getType().equals(DBRelationshipInfo.RelationshipType.ZeroOrOne);
                        /*XXX bug #9497: boolean canEdit = true;
                        boolean addAddBtn = isEditOnCreateOnly && relInfo != null;
                        if (AppContextMgr.isSecurityOn()) {
                        DBTableInfo tblInfo = childInfo != null ? DBTableIdMgr.getInstance().getByShortClassName(childInfo.getDataClass().getSimpleName()) : null;
                        if (tblInfo != null) {
                            PermissionSettings perm = tblInfo.getPermissions();
                            if (perm != null) {
                                //XXX whoa. What about view perms???
                               //if (perm.isViewOnly() || !perm.canView()) {
                                if (!perm.canModify()) {
                                   canEdit = false;
                                }
                            }
                        }
                        }*/

                        int options = (isACollection && !isSingle ? MultiView.RESULTSET_CONTROLLER
                                : MultiView.IS_SINGLE_OBJ)
                                | MultiView.VIEW_SWITCHER
                                | (MultiView.isOptionOn(parent.getCreateOptions(), MultiView.IS_NEW_OBJECT)
                                        ? MultiView.IS_NEW_OBJECT
                                        : MultiView.NO_OPTIONS)
                                |
                                /* XXX bug #9497:(mode == AltViewIFace.CreationMode.EDIT && canEdit ? MultiView.IS_EDITTING : MultiView.NO_OPTIONS) |
                                (useNoScrollbars ? MultiView.NO_SCROLLBARS : MultiView.NO_OPTIONS)
                                //| (addAddBtn ? MultiView.INCLUDE_ADD_BTN : MultiView.NO_OPTIONS)
                                ; */

                                (mode == AltViewIFace.CreationMode.EDIT ? MultiView.IS_EDITTING
                                        : MultiView.NO_OPTIONS)
                                | (useNoScrollbars ? MultiView.NO_SCROLLBARS : MultiView.NO_OPTIONS)
                                | (hideResultSetController ? MultiView.HIDE_RESULTSET_CONTROLLER
                                        : MultiView.NO_OPTIONS);
                        //MultiView.printCreateOptions("HERE", options);

                        options |= cellSubView.getPropertyAsBoolean("nosep", false)
                                ? MultiView.DONT_USE_EMBEDDED_SEP
                                : 0;
                        options |= cellSubView.getPropertyAsBoolean("nosepmorebtn", false)
                                ? MultiView.NO_MORE_BTN_FOR_SEP
                                : 0;
                        options |= cellSubView.getPropertyAsBoolean("collapse", false)
                                ? MultiView.COLLAPSE_SEPARATOR
                                : 0;

                        if (!(isACollection && !isSingle)) {
                            options &= ~MultiView.ADD_SEARCH_BTN;
                        } else {
                            options |= cellSubView.getPropertyAsBoolean("addsearch", false)
                                    ? MultiView.ADD_SEARCH_BTN
                                    : 0;
                        }

                        //MultiView.printCreateOptions("_______________________________", parent.getCreateOptions());
                        //MultiView.printCreateOptions("_______________________________", options);
                        boolean useBtn = UIHelper.getProperty(props, "btn", false);
                        if (useBtn) {
                            SubViewBtn.DATA_TYPE dataType;
                            if (isSingle) {
                                dataType = SubViewBtn.DATA_TYPE.IS_SINGLESET_ITEM;

                            } else if (isACollection) {
                                dataType = SubViewBtn.DATA_TYPE.IS_SET;
                            } else {
                                dataType = cellSubView.getName().equals("this") ? SubViewBtn.DATA_TYPE.IS_THIS
                                        : SubViewBtn.DATA_TYPE.IS_SET;
                            }

                            SubViewBtn subViewBtn = getInstance().createSubViewBtn(parent, cellSubView, subView,
                                    dataType, options, props, getClassToCreate(parent, cell), mode);
                            subViewBtn.setHelpContext(props.getProperty("hc", null));

                            bi.doAddToValidator = false;
                            bi.compToAdd = subViewBtn;

                            String visProp = cell.getProperty("visible");
                            if (StringUtils.isNotEmpty(visProp) && visProp.equalsIgnoreCase("false")
                                    && bi.compToAdd != null) {
                                bi.compToAdd.setVisible(false);
                            }

                            try {
                                addControl(validator, viewBldObj, rowInx, cell, bi);

                            } catch (java.lang.IndexOutOfBoundsException ex) {
                                String msg = "Error adding control type: `" + cell.getType() + "` id: `"
                                        + cell.getIdent() + "` name: `" + cell.getName() + "` on row: " + rowInx
                                        + " column: " + bi.colInx + "\n" + ex.getMessage();
                                UIRegistry.showError(msg);
                                return false;
                            }

                            bi.doRegControl = false;
                            bi.compToAdd = null;

                        } else {

                            Color bgColor = getBackgroundColor(props, parent.getBackground());

                            //log.debug(cellSubView.getName()+"  "+UIHelper.getProperty(props, "addsearch", false));
                            if (UIHelper.getProperty(props, "addsearch", false)) {
                                options |= MultiView.ADD_SEARCH_BTN;
                            }

                            if (UIHelper.getProperty(props, "addadd", false)) {
                                options |= MultiView.INCLUDE_ADD_BTN;
                            }

                            //MultiView.printCreateOptions("SUBVIEW", options);
                            MultiView multiView = new MultiView(parent, cellSubView.getName(), subView,
                                    parent.getCreateWithMode(), cellSubView.getDefaultAltViewType(), options,
                                    bgColor, cellSubView);
                            multiView.setClassToCreate(getClassToCreate(parent, cell));
                            setBorder(multiView, cellSubView.getProperties());

                            parent.addChildMV(multiView);

                            //log.debug("["+cell.getType()+"] ["+cell.getName()+"] col: "+bi.colInx+" row: "+rowInx+" colspan: "+cell.getColspan()+" rowspan: "+cell.getRowspan());
                            viewBldObj.addSubView(cellSubView, multiView, bi.colInx, rowInx,
                                    cellSubView.getColspan(), 1);
                            viewBldObj.closeSubView(cellSubView);

                            Viewable viewable = multiView.getCurrentView();
                            if (viewable != null) {
                                if (viewable instanceof TableViewObj) {
                                    ((TableViewObj) viewable).setVisibleRowCount(cellSubView.getTableRows());
                                }
                                if (viewable.getValidator() != null && childInfo != null) {
                                    viewable.getValidator().setRequired(childInfo.isRequired());
                                }
                            }
                            bi.colInx += cell.getColspan() + 1;
                        }
                        bi.curMaxRow = rowInx;

                        //if (hasColor)
                        //{
                        //    setMVBackground(multiView, multiView.getBackground());
                        //}

                    } else {
                        log.error("buildFormView - parent is NULL for subview [" + subViewName + "]");
                        bi.colInx += 2;
                    }
                } else {
                    //log.debug("["+cell.getType()+"] ["+cell.getName()+"] col: "+bi.colInx+" row: "+rowInx+" colspan: "+cell.getColspan()+" rowspan: "+cell.getRowspan());
                    viewBldObj.addSubView(cellSubView, parent, bi.colInx, rowInx, cellSubView.getColspan(), 1);

                    AltViewIFace altView = subView.getDefaultAltView();
                    DBTableInfo sbTableInfo = DBTableIdMgr.getInstance().getByClassName(subView.getClassName());
                    ViewDefIFace altsViewDef = (ViewDefIFace) altView.getViewDef();

                    if (altsViewDef instanceof FormViewDefIFace) {
                        FormViewDefIFace fvd = (FormViewDefIFace) altsViewDef;
                        processRows(sbTableInfo, parent, viewDef, validator, viewBldObj, altView.getMode(),
                                labelsForHash, currDataObj, fvd.getRows());

                    } else if (altsViewDef == null) {
                        // This error is bad enough to have it's own dialog
                        String msg = String.format("The Altview '%s' has a null ViewDef!", altView.getName());
                        FormDevHelper.appendFormDevError(msg);
                        UIRegistry.showError(msg);
                    }

                    viewBldObj.closeSubView(cellSubView);
                    bi.colInx += cell.getColspan() + 1;
                }

            } else {
                log.error("buildFormView - Could find subview's with ViewSet[" + cellSubView.getViewSetName()
                        + "] ViewName[" + subViewName + "]");
            }
            // still have compToAdd = null;

        } else if (cell.getType() == FormCellIFace.CellType.statusbar) {
            bi.compToAdd = new JStatusBar();
            bi.doRegControl = true;
            bi.doAddToValidator = false;

        } else if (cell.getType() == FormCellIFace.CellType.panel) {
            bi.doRegControl = false;
            bi.doAddToValidator = false;

            cell.setIgnoreSetGet(true);

            FormCellPanel cellPanel = (FormCellPanel) cell;
            PanelViewable.PanelType panelType = PanelViewable.getType(cellPanel.getPanelType());

            if (panelType == PanelViewable.PanelType.Panel) {
                PanelViewable panelViewable = new PanelViewable(viewBldObj, cellPanel);

                processRows(parentTableInfo, parent, viewDef, validator, panelViewable, mode, labelsForHash,
                        currDataObj, cellPanel.getRows());

                panelViewable.setVisible(cellPanel.getPropertyAsBoolean("visible", true));

                setBorder(panelViewable, cellPanel.getProperties());
                if (parent != null) {
                    Color bgColor = getBackgroundColor(cellPanel.getProperties(), parent.getBackground());
                    if (bgColor != null && bgColor != parent.getBackground()) {
                        panelViewable.setOpaque(true);
                        panelViewable.setBackground(bgColor);
                    }
                }

                bi.compToAdd = panelViewable;
                bi.doRegControl = true;
                bi.compToReg = panelViewable;

            } else if (panelType == PanelViewable.PanelType.ButtonBar) {
                bi.compToAdd = PanelViewable.buildButtonBar(processRows(viewBldObj, cellPanel.getRows()));

            } else {
                FormDevHelper.appendFormDevError("Panel Type is not implemented.");
                return false;
            }
        }

        String visProp = cell.getProperty("visible");
        if (StringUtils.isNotEmpty(visProp) && visProp.equalsIgnoreCase("false") && bi.compToAdd != null) {
            bi.compToAdd.setVisible(false);
        }

        return true;
    }

    /**
     * Processes the rows in a definition.
     * @param tableInfo table info for current form (may be null)
     * @param parent MultiView parent
     * @param viewDef the FormViewDef (Viewdef)
     * @param validator optional validator
     * @param viewBldObj the FormViewObj this row belongs to
     * @param mode the creation mode
     * @param builder the current JGoodies builder
     * @param labelsForHash the has table for label
     * @param cc CellConstraints
     * @param currDataObj the current data object
     * @param formRows the list of rows to be processed
     */
    protected void processRows(final DBTableInfo tableInfo, final MultiView parent, final ViewDefIFace viewDef,
            final FormValidator validator, final ViewBuilderIFace viewBldObj, final AltViewIFace.CreationMode mode,
            final HashMap<String, JLabel> labelsForHash, final Object currDataObj,
            final List<FormRowIFace> formRows) {
        BuildInfoStruct bi = new BuildInfoStruct();
        bi.curMaxRow = 1;

        int rowInx = 1;
        boolean hasRequiredOrDerivedField = false;

        for (FormRowIFace row : formRows) {
            bi.colInx = 1;

            for (FormCellIFace cell : row.getCells()) {
                DBTableChildIFace childInfo = null;
                String cellName = cell.getName();
                if (tableInfo != null && StringUtils.isNotEmpty(cellName)) {
                    childInfo = tableInfo.getItemByName(cellName);
                }

                boolean isEditOnCreateOnly = false;
                //XXX bug #9497: if (mode == AltViewIFace.CreationMode.EDIT)
                if (mode == AltViewIFace.CreationMode.EDIT && cell.getType() == FormCellIFace.CellType.field) {
                    // XXX bug #9497: if (cell.getType() == FormCellIFace.CellType.field) {
                    isEditOnCreateOnly = ((FormCellField) cell).getPropertyAsBoolean("editoncreate", false);
                    ((FormCellField) cell).setEditOnCreate(true);
                    /* XXX bug #9497:} else if (childInfo instanceof DBRelationshipInfo) {
                    if (AppContextMgr.isSecurityOn()) {
                        DBTableInfo tblInfo = childInfo != null ? DBTableIdMgr.getInstance().getByShortClassName(childInfo.getDataClass().getSimpleName()) : null;
                        if (tblInfo != null) {
                            PermissionSettings perm = tblInfo.getPermissions();
                            if (perm != null) {
                                //XXX whoa. What about view perms???
                               //if (perm.isViewOnly() || !perm.canView()) {
                                if (perm.canAdd() && !perm.canModify()) {
                                   isEditOnCreateOnly = true;
                                }
                            }
                        }
                    }
                           
                    }*/
                }

                if (!createItem(tableInfo, childInfo, parent, viewDef, validator, viewBldObj, mode, labelsForHash,
                        currDataObj, cell, isEditOnCreateOnly, rowInx, bi)) {
                    return;
                }

                //log.debug(cell.getType()+" "+cell.getName()+" col: "+bi.colInx);
                if (bi.compToAdd != null) {
                    try {
                        addControl(validator, viewBldObj, rowInx, cell, bi);

                    } catch (java.lang.IndexOutOfBoundsException ex) {
                        String msg = "Error adding control type: `" + cell.getType() + "` id: `" + cell.getIdent()
                                + "` name: `" + cell.getName() + "` on row: " + rowInx + " column: " + bi.colInx
                                + "\n" + ex.getMessage();
                        UIRegistry.showError(msg);
                        return;
                    }
                }

                //XXX bug #9497: if (isEditOnCreateOnly && cell.getType() == FormCellIFace.CellType.field)
                if (isEditOnCreateOnly && cell.getType() == FormCellIFace.CellType.field) {
                    EditViewCompSwitcherPanel evcsp = (EditViewCompSwitcherPanel) bi.compToReg;
                    evcsp.setParentValidator(validator);

                    BuildInfoStruct bi2 = new BuildInfoStruct();
                    bi2.curMaxRow = 1;
                    bi2.colInx = 1;

                    createItem(tableInfo, childInfo, parent, viewDef, evcsp.getValidator(), viewBldObj,
                            AltViewIFace.CreationMode.EDIT, labelsForHash, currDataObj, cell, false, rowInx, bi2);
                    Component editCompReg = bi2.compToReg;
                    Component editCompAdd = bi2.compToAdd;

                    createItem(tableInfo, childInfo, parent, viewDef, null, viewBldObj,
                            AltViewIFace.CreationMode.VIEW, labelsForHash, currDataObj, cell, false, rowInx, bi2);
                    Component viewCompReg = bi2.compToReg;
                    Component viewCompAdd = bi2.compToAdd;

                    evcsp.set(editCompReg, editCompAdd, viewCompReg, viewCompAdd);
                }

                if (!bi.isRequired && ((childInfo != null && childInfo.isRequired())
                        || (cell instanceof FormCellFieldIFace && ((FormCellFieldIFace) cell).isRequired()))) {
                    bi.isRequired = true;
                    ((FormCellFieldIFace) cell).setRequired(true);
                }
            }

            if (bi.isRequired || bi.isDerivedLabel) {
                hasRequiredOrDerivedField = true;
            }
            rowInx += 2;
        }

        if (bi.collapseSepHash != null && bi.collapseSepHash.size() > 0) {
            for (CollapsableSeparator collapseSep : bi.collapseSepHash.keySet()) {
                Component comp = viewBldObj.getControlByName(bi.collapseSepHash.get(collapseSep));
                if (comp != null) {
                    collapseSep.setInnerComp(comp);
                }
            }
        }

        viewBldObj.doneBuilding();

        // Check to see if there is at least one required field.
        // The call to 'viewBldObj.hasRequiredFields is because it may have had an embedded panel
        // that had required fields.
        if (doFixLabels && (hasRequiredOrDerivedField || viewBldObj.hasRequiredFields())) {
            viewBldObj.fixUpRequiredDerivedLabels();
        }
    }

    /**
     * @param validator
     * @param viewBldObj
     * @param rowInx
     * @param cell
     * @param bi
     */
    protected void addControl(final FormValidator validator, final ViewBuilderIFace viewBldObj, final int rowInx,
            final FormCellIFace cell, final BuildInfoStruct bi) {
        int colspan = cell.getColspan();
        int rowspan = cell.getRowspan();

        //log.debug("["+cell.getType()+"] ["+cell.getName()+"] col: "+bi.colInx+" row: "+rowInx+" colspan: "+colspan+" rowspan: "+rowspan);
        viewBldObj.addControlToUI(bi.compToAdd, bi.colInx, rowInx, colspan, rowspan);

        if (bi.doRegControl) {
            viewBldObj.registerControl(cell, bi.compToReg == null ? bi.compToAdd : bi.compToReg);
        }

        bi.curMaxRow = Math.max(bi.curMaxRow, rowspan + rowInx);

        if (validator != null && bi.doAddToValidator) {
            validator.addUIComp(cell.getIdent(), bi.compToReg == null ? bi.compToAdd : bi.compToReg);
        }
        bi.colInx += colspan + 1;
    }

    /**
     * @param cellSubView
     * @param dataClass
     * @return
     */
    protected Field getFieldFromDotNotation(final FormCellSubView cellSubView, final Class<?> dataClass) {
        Class<?> parentCls = dataClass;

        String[] fieldNames = StringUtils.split(cellSubView.getName(), ".");
        for (int i = 0; i < fieldNames.length; i++) {
            try {
                //System.out.println("["+fieldNames[i]+"]");
                if (fieldNames[i].equals("this")) {
                    continue;
                }

                Field fld = null;
                try {
                    fld = parentCls.getDeclaredField(fieldNames[i]);

                } catch (java.lang.NoSuchFieldException ex) {
                    //edu.ku.brc.af.core.UsageTracker.incrHandledUsageCount();
                    //edu.ku.brc.exceptions.ExceptionTracker.getInstance().capture(ViewFactory.class, ex);

                    UIRegistry.showError(
                            String.format("There is no field named '%s' for class %s", fieldNames[i], parentCls));

                    String parentTitle = parentCls.getSimpleName();
                    DBTableInfo ti = DBTableIdMgr.getInstance().getByClassName(parentCls.getName());
                    if (ti != null) {
                        parentTitle = ti.getTitle();
                    }

                    UIRegistry.showError(String.format(UIRegistry.getResourceString("INVALID_FIELD_NAME"),
                            fieldNames[i], parentTitle));
                }
                if (fld != null) {
                    if (i == fieldNames.length - 1) {
                        return fld;
                    }
                    parentCls = fld.getType();

                } else {
                    log.error("Couldn't find field [" + cellSubView.getName() + "] in class ["
                            + parentCls.getSimpleName() + "]");
                }

            } catch (Exception ex) {
                edu.ku.brc.af.core.UsageTracker.incrHandledUsageCount();
                edu.ku.brc.exceptions.ExceptionTracker.getInstance().capture(ViewFactory.class, ex);
                ex.printStackTrace();
            }
        }
        return null;
    }

    /**
     * Determines the class that is to be created.
     * @param multiView the parent
     * @param cell the definitions
     * @return the class
     */
    protected Class<?> getClassToCreate(final MultiView multiView, final FormCellIFace cell) {
        DBTableInfo tableInfo = DBTableIdMgr.getInstance().getByClassName(multiView.getView().getClassName());
        if (tableInfo != null) {
            DBTableChildIFace tblChild = tableInfo.getItemByName(cell.getName());
            if (tblChild != null) {
                return tblChild.getDataClass();
            }
            // Sometime, like in Taxon, the QCBX is not a field in the schema.
            // see 'acceptedParent'
            //log.debug("How did we get here? ["+cell.getName()+"]");
        }
        return null;
    }

    /**
     * Sets a border on the component as defined in the properties.
     * @param comp the component
     * @param props the list of properties
     */
    protected void setBorder(final JComponent comp, final Properties props) {
        if (props != null) {
            String borderType = props.getProperty("border");
            if (StringUtils.isNotEmpty(borderType)) {
                if (borderType.equals("etched")) {
                    comp.setBorder(BorderFactory.createEtchedBorder());

                } else if (borderType.equals("lowered")) {
                    comp.setBorder(BorderFactory.createBevelBorder(BevelBorder.LOWERED));

                } else if (borderType.equals("raised")) {
                    comp.setBorder(BorderFactory.createBevelBorder(BevelBorder.RAISED));

                } else if (borderType.equals("empty")) {
                    comp.setBorder(BorderFactory.createEmptyBorder());

                } else if (borderType.equals("line")) {
                    Color color = Color.LIGHT_GRAY;
                    String borderColor = props.getProperty("bordercolor");
                    if (StringUtils.isNotEmpty(borderColor)) {
                        try {
                            color = UIHelper.parseRGB(borderColor);

                        } catch (ConfigurationException ex) {
                            log.error(ex);
                        }
                    }
                    comp.setBorder(BorderFactory.createLineBorder(color));
                }
            }
        }
    }

    /**
     * @param props
     * @param bgColor
     * @return
     */
    protected Color getBackgroundColor(final Properties props, final Color bgColor) {
        if (props != null) {
            String colorStr = props.getProperty("bgcolor");
            if (StringUtils.isNotEmpty(colorStr)) {
                if (colorStr.endsWith("%")) {
                    try {
                        int percent = Integer.parseInt(colorStr.substring(0, colorStr.length() - 1));
                        double per = (percent / 100.0);
                        int r = Math.min((int) (bgColor.getRed() * per), 255);
                        int g = Math.min((int) (bgColor.getGreen() * per), 255);
                        int b = Math.min((int) (bgColor.getBlue() * per), 255);
                        return new Color(r, g, b);

                    } catch (Exception ex) {
                        edu.ku.brc.af.core.UsageTracker.incrHandledUsageCount();
                        edu.ku.brc.exceptions.ExceptionTracker.getInstance().capture(ViewFactory.class, ex);
                        log.error(ex);
                    }
                } else {
                    try {
                        return UIHelper.parseRGB(colorStr);

                    } catch (ConfigurationException ex) {
                        log.error(ex);
                    }
                }
            }
        }
        return bgColor;
    }

    public void setMVBackground(final MultiView parent, final Color bgColor) {
        for (MultiView mv : parent.getKids()) {
            setMVBackground(mv, bgColor);
        }
        for (Viewable viewable : parent.getViewables()) {
            viewable.getUIComponent().setBackground(bgColor);
        }
    }

    /**
     * Processes the rows for a button bar.
     * @param viewBldObj formViewObj
     * @param formRows formRows
     * @return the array of buttons
     */
    protected JButton[] processRows(final ViewBuilderIFace viewBldObj, final List<FormRowIFace> formRows) {
        List<JButton> btns = new ArrayList<JButton>();

        for (FormRowIFace row : formRows) {
            for (FormCellIFace cell : row.getCells()) {
                if (cell.getType() == FormCellIFace.CellType.command) {

                    FormCellCommand cellCmd = (FormCellCommand) cell;
                    JButton btn = createFormButton(cell, cellCmd.getLabel());
                    if (cellCmd.getCommandType().length() > 0) {
                        btn.addActionListener(new CommandActionWrapper(
                                new CommandAction(cellCmd.getCommandType(), cellCmd.getAction(), "")));
                    }
                    viewBldObj.registerControl(cell, btn);
                    btns.add(btn);
                }
            }
        }

        JButton[] btnsArray = new JButton[btns.size()];
        int i = 0;
        for (JButton b : btns) {
            btnsArray[i++] = b;
        }
        btns.clear();
        return btnsArray;

    }

    /**
     * Creates a Form.
     * @param view view the view definition
     * @param altView the altView to use (if null, then it uses the default ViewDef)
     * @param parentView the MultiView parent (this may be null)
     * @param options the options needed for creating the form
     * @param cellName the name of the cell when it is a subview
     * @param dataClass the class of the data that is put into the form
     * @return the form
     */
    public FormViewObj buildFormViewable(final ViewIFace view, final AltViewIFace altView,
            final MultiView parentView, final int options, final String cellName, final Class<?> dataClass,
            final Color bgColor) {
        try {
            FormViewDef formViewDef = (FormViewDef) altView.getViewDef();

            HashMap<String, JLabel> labelsForHash = new HashMap<String, JLabel>();

            ValidatedJPanel validatedPanel = null;
            FormValidator validator = null;
            if (altView.isValidated()) {
                validatedPanel = new ValidatedJPanel();
                validator = validatedPanel.getFormValidator();
                validator.setDataChangeNotification(true);
            }

            DBTableInfo tableInfo = DBTableIdMgr.getInstance().getByClassName(view.getClassName());
            MultiView parentsMV = parentView != null ? parentView.getMultiViewParent() : null;
            if (tableInfo == null && parentsMV != null) {
                tableInfo = DBTableIdMgr.getInstance().getByClassName(parentsMV.getView().getClassName());
            }

            FormViewObj formViewObj = new FormViewObj(view, altView, parentView, validator, options, cellName,
                    dataClass, bgColor);
            if (!formViewObj.isBuildValid()) {
                return null;
            }

            Object currDataObj = formViewObj.getCurrentDataObj();

            /* XXX bug #9497:            AltViewIFace.CreationMode processMode = altView.getMode();
            //            if (processMode == AltViewIFace.CreationMode.EDIT && (!formViewObj.isEditing() || !MultiView.isOptionOn(options, MultiView.IS_EDITTING))) {
            //               processMode = AltViewIFace.CreationMode.VIEW;
            //            }
                        processRows(tableInfo, parentView, formViewDef, validator, formViewObj, processMode, labelsForHash, currDataObj, formViewDef.getRows());
            */
            processRows(tableInfo, parentView, formViewDef, validator, formViewObj, altView.getMode(),
                    labelsForHash, currDataObj, formViewDef.getRows());

            formViewObj.addUsageNotes();

            if (validatedPanel != null) {
                validatedPanel.addPanel(formViewObj.getPanel());

                // Here we add all the components whether they are used or not
                // XXX possible optimization is to only load the ones being used (although I am not sure how we will know that)
                Map<String, Component> mapping = formViewObj.getControlMapping();
                for (String id : mapping.keySet()) {
                    validatedPanel.addValidationComp(id, mapping.get(id));
                }
                Map<String, String> enableRules = formViewDef.getEnableRules();

                // Load up validation Rules
                FormValidator fv = validatedPanel.getFormValidator();
                formViewObj.setValidator(fv);

                fv.setName(formViewDef.getName()); // For Debugging

                if (parentView != null) {
                    fv.setTopLevel(parentView.isTopLevel());
                }

                if (enableRules != null) {
                    for (String id : enableRules.keySet()) {
                        fv.addEnableRule(id, enableRules.get(id));
                    }
                }

                // Load up labels and associate them with their component
                for (String idFor : labelsForHash.keySet()) {
                    fv.addUILabel(idFor, labelsForHash.get(idFor));
                }

                formViewObj.setFormComp(validatedPanel);

            } else {
                formViewObj.setFormComp(formViewObj.getPanel());
            }

            return formViewObj;

        } catch (Exception e) {
            e.printStackTrace();
            edu.ku.brc.af.core.UsageTracker.incrHandledUsageCount();
            edu.ku.brc.exceptions.ExceptionTracker.getInstance().capture(ViewFactory.class, e);
            log.error("buildPanel - Outer Name[" + altView.getName() + "]");
        }
        return null;
    }

    /**
     * Creates a Table View.
     * @param view view the view definition
     * @param altView the altView to use (if null, then it uses the default ViewDef)
     * @param parentView the MultiView parent (this may be null)
     * @param options the options needed for creating the form
     * @param cellName the name of the cell when it is a subview
     * @param dataClass the class of the data that is put into the form
     * @return the form
     */
    public TableViewObj buildTableViewable(final ViewIFace view, final AltViewIFace altView,
            final MultiView parentView, final int options, final String cellName, final Class<?> dataClass,
            final Color bgColor) {
        try {
            ViewDefIFace viewDef = altView.getViewDef();

            FormValidator validator = null;
            if (altView.isValidated()) {
                ValidatedJPanel validatedPanel = new ValidatedJPanel();
                validator = validatedPanel.getFormValidator();
                validator.setDataChangeNotification(true);
            }

            DBTableInfo tableInfo = DBTableIdMgr.getInstance().getByClassName(view.getClassName());
            MultiView parentsMV = parentView.getMultiViewParent();
            if (tableInfo == null && parentsMV != null) {
                tableInfo = DBTableIdMgr.getInstance().getByClassName(parentsMV.getView().getClassName());
            }

            // Special situation where we create a table from a Form Definition
            if (viewDef instanceof FormViewDef) {
                FormViewDefIFace formViewDef = (FormViewDefIFace) viewDef;
                HashMap<String, JLabel> labelsForHash = new HashMap<String, JLabel>();
                TableViewObj tableViewObj = new TableViewObj(view, altView, parentView, validator, options,
                        cellName, dataClass, bgColor);

                processRows(tableInfo, parentView, formViewDef, null, tableViewObj, altView.getMode(),
                        labelsForHash, validator, formViewDef.getRows());
                return tableViewObj;

            }
            // else
            FormViewDefIFace formViewDef = (FormViewDefIFace) altView.getViewDef();

            HashMap<String, JLabel> labelsForHash = new HashMap<String, JLabel>();

            /*
            ValidatedJPanel validatedPanel = null;
            FormValidator   validator      = null;
            if (altView.isValidated())
            {
            validatedPanel = new ValidatedJPanel();
            validator      = validatedPanel.getFormValidator();
            validator.setDataChangeNotification(true);
            }
            */

            TableViewObj tableViewObj = new TableViewObj(view, altView, parentView, null, options, cellName,
                    dataClass, bgColor);

            //Object currDataObj = tableViewObj.getCurrentDataObj();

            processRows(tableInfo, parentView, formViewDef, null, tableViewObj, altView.getMode(), labelsForHash,
                    validator, formViewDef.getRows());

            /*
            if (validatedPanel != null)
            {
                validatedPanel.addPanel(formViewObj.getPanel());
                
                // Here we add all the components whether they are used or not
                // XXX possible optimization is to only load the ones being used (although I am not sure how we will know that)
                Map<String, Component> mapping = formViewObj.getControlMapping();
                for (String id : mapping.keySet())
                {
            validatedPanel.addValidationComp(id, mapping.get(id));
                }
                Map<String, String> enableRules = formViewDef.getEnableRules();
                
                // Load up validation Rules
                FormValidator fv = validatedPanel.getFormValidator();
                formViewObj.setValidator(fv);
                    
                fv.setName(formViewDef.getName()); // For Debugging
                
                for (String id : enableRules.keySet())
                {
            fv.addEnableRule(id, enableRules.get(id));
                }
                
                // Load up labels and associate them with there component
                for (String idFor : labelsForHash.keySet())
                {
            fv.addUILabel(idFor, labelsForHash.get(idFor));
                }
                
                formViewObj.setFormComp(validatedPanel);
                    
            } else
            {
                formViewObj.setFormComp(formViewObj.getPanel());
            }
            */
            return tableViewObj;

        } catch (Exception e) {
            edu.ku.brc.af.core.UsageTracker.incrHandledUsageCount();
            edu.ku.brc.exceptions.ExceptionTracker.getInstance().capture(ViewFactory.class, e);
            log.error("buildPanel - Outer Name[" + altView.getName() + "]");
            e.printStackTrace();
        }
        return null;
    }

    /**
     * Creates a Table View.
     * @param view view the view definition
     * @param altView the altView to use (if null, then it uses the default ViewDef)
     * @param parentView the MultiView parent (this may be null)
     * @param options the options needed for creating the form
     * @param cellName the name of the cell when it is a subview
     * @param dataClass the class of the data that is put into the form
     * @return the form
     */
    public TableViewObj buildRecordSetTableViewable(final ViewIFace view, final AltViewIFace altView,
            final MultiView parentView, @SuppressWarnings("unused") final int options, final String cellName,
            final Class<?> dataClass, final Color bgColor) {
        RecordSetTableViewObj rsTableViewObj = null;
        try {
            ViewDefIFace viewDef = altView.getViewDef();

            // Special situation where we create a table from a Form Definition
            if (viewDef instanceof FormViewDef) {
                FormViewDefIFace formViewDef = (FormViewDefIFace) viewDef;
                HashMap<String, JLabel> labelsForHash = new HashMap<String, JLabel>();

                rsTableViewObj = new RecordSetTableViewObj(view, altView, parentView, null, 0, cellName, dataClass,
                        bgColor);

                DBTableInfo tableInfo = DBTableIdMgr.getInstance().getByClassName(view.getClassName());

                processRows(tableInfo, parentView, formViewDef, null, rsTableViewObj, altView.getMode(),
                        labelsForHash, null, formViewDef.getRows());
                return rsTableViewObj;
            }

        } catch (Exception e) {
            edu.ku.brc.af.core.UsageTracker.incrHandledUsageCount();
            edu.ku.brc.exceptions.ExceptionTracker.getInstance().capture(ViewFactory.class, e);
            log.error("buildPanel - Outer Name[" + altView.getName() + "]");
            e.printStackTrace();
        }
        return rsTableViewObj;
    }

    /**
     * Creates a FormViewObj.
     * 
     * @param multiView the parent multiView
     * @param view the definition of the form view to be created
     * @param altName the name of the altView to be used (can be null - then it defaults to the default AltViewIFace)
     * @param data the data to be set into the form
     * @param options the options needed for creating the form
     * @return a new FormViewObj
     */
    public static Viewable createFormView(final MultiView multiView, final ViewIFace view, final String altName,
            final Object data, final int options, final String cellName) {
        return createFormView(multiView, view, altName, data, options, cellName, null);
    }

    /**
     * Creates a FormViewObj.
     * 
     * @param multiView the parent multiView
     * @param view the definition of the form view to be created
     * @param altName the name of the altView to be used (can be null - then it defaults to the default AltViewIFace)
     * @param data the data to be set into the form
     * @param options the options needed for creating the form
     * @param bgColor the background color
     * @return a new FormViewObj
     */
    public static Viewable createFormView(final MultiView multiView, final ViewIFace view, final String altName,
            final Object data, final int options, final String cellName, final Color bgColor) {
        if (viewFieldColor == null) {
            viewFieldColor = AppPrefsCache.getColorWrapper("ui", "formatting", "viewfieldcolor");
        }

        AltViewIFace altView = view.getAltView(altName);

        if (altView != null) {
            Viewable viewable = getInstance().buildViewable(view, altView, multiView, options, cellName, bgColor);
            if (viewable != null) {
                if (data != null) {
                    viewable.setDataObj(data);
                    //viewable.setDataIntoUI();
                } else {
                    // This is bad to have when you don't have any items yet. - rods
                    //FormDevHelper.appendFormDevError("Form could be created because the data was null! ["+view.getName()+"]["+altView.getName()+"]");
                }
                return viewable;
            }
        }
        return null;
    }

    /**
     * @return the isFormTransparent
     */
    public static boolean isFormTransparent() {
        return isFormTransparent;
    }

    /**
     * @param isFormTransparent the isFormTransparent to set
     */
    public static void setFormTransparent(boolean isFormTransparent) {
        ViewFactory.isFormTransparent = isFormTransparent;
    }

    /**
     * Returns the singleton for the ViewSetMgr.
     * @return the singleton for the ViewSetMgr
     */
    public static ViewFactory getInstance() {
        if (instance != null) {
            return instance;

        }
        // else
        String factoryNameStr = AccessController.doPrivileged(new PrivilegedAction<String>() {
            public String run() {
                return System.getProperty(factoryName);
            }
        });

        if (factoryNameStr != null) {
            try {
                instance = (ViewFactory) Class.forName(factoryNameStr).newInstance();
                return instance;

            } catch (Exception e) {
                edu.ku.brc.af.core.UsageTracker.incrHandledUsageCount();
                edu.ku.brc.exceptions.ExceptionTracker.getInstance().capture(AppContextMgr.class, e);
                InternalError error = new InternalError("Can't instantiate ViewFactory factory " + factoryNameStr); //$NON-NLS-1$
                error.initCause(e);
                throw error;
            }
        }
        return instance = new ViewFactory();
    }

}