Package DisplayProject

Source Code of DisplayProject.UIutils$NodeRemoved

/*
Copyright (c) 2003-2008 ITerative Consulting Pty Ltd. All Rights Reserved.

Redistribution and use in source and binary forms, with or without modification, are permitted
provided that the following conditions are met:

o Redistributions of source code must retain the above copyright notice, this list of conditions and
the following disclaimer.
 
o Redistributions in binary form must reproduce the above copyright notice, this list of conditions
and the following disclaimer in the documentation and/or other materials provided with the distribution.
   
o This jcTOOL Helper Class software, whether in binary or source form may not be used within,
or to derive, any other product without the specific prior written permission of the copyright holder

 
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,
BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.


*/
package DisplayProject;

import java.awt.AWTEvent;
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Component;
import java.awt.Container;
import java.awt.Cursor;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Frame;
import java.awt.Graphics2D;
import java.awt.GraphicsConfiguration;
import java.awt.GraphicsDevice;
import java.awt.GraphicsEnvironment;
import java.awt.Insets;
import java.awt.KeyboardFocusManager;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.SystemColor;
import java.awt.Toolkit;
import java.awt.Window;
import java.awt.color.ColorSpace;
import java.awt.event.ActionEvent;
import java.awt.event.ComponentAdapter;
import java.awt.event.ComponentEvent;
import java.awt.event.InputEvent;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseListener;
import java.awt.image.BufferedImage;
import java.awt.image.BufferedImageOp;
import java.awt.image.ByteLookupTable;
import java.awt.image.ColorConvertOp;
import java.awt.image.LookupOp;
import java.beans.Expression;
import java.beans.PropertyChangeSupport;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.text.DecimalFormat;
import java.text.MessageFormat;
import java.text.NumberFormat;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.Iterator;
import java.util.List;
import java.util.MissingResourceException;
import java.util.StringTokenizer;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javax.swing.AbstractButton;
import javax.swing.Action;
import javax.swing.BorderFactory;
import javax.swing.ButtonGroup;
import javax.swing.InputMap;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JCheckBoxMenuItem;
import javax.swing.JComboBox;
import javax.swing.JComponent;
import javax.swing.JDialog;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JPopupMenu;
import javax.swing.JRadioButtonMenuItem;
import javax.swing.JScrollBar;
import javax.swing.JScrollPane;
import javax.swing.JTabbedPane;
import javax.swing.JTable;
import javax.swing.JTextArea;
import javax.swing.JTree;
import javax.swing.JViewport;
import javax.swing.JWindow;
import javax.swing.KeyStroke;
import javax.swing.MenuElement;
import javax.swing.RepaintManager;
import javax.swing.SwingConstants;
import javax.swing.SwingUtilities;
import javax.swing.ToolTipManager;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.border.Border;
import javax.swing.border.TitledBorder;
import javax.swing.table.TableCellEditor;
import javax.swing.table.TableCellRenderer;
import javax.swing.table.TableColumn;
import javax.swing.text.BadLocationException;
import javax.swing.text.DefaultEditorKit;
import javax.swing.text.DefaultFormatterFactory;
import javax.swing.text.Document;
import javax.swing.text.JTextComponent;
import javax.swing.text.MaskFormatter;
import javax.swing.text.NumberFormatter;
import javax.swing.text.TextAction;
import javax.swing.tree.DefaultTreeModel;
import javax.swing.tree.TreeModel;

import org.apache.log4j.Logger;

import DisplayProject.actions.ActionMgr;
import DisplayProject.actions.AppletConnectionInfo;
import DisplayProject.actions.BooleanValue;
import DisplayProject.actions.Caption;
import DisplayProject.actions.ColourChange;
import DisplayProject.actions.Column;
import DisplayProject.actions.ElementList;
import DisplayProject.actions.Enabled;
import DisplayProject.actions.ExitOnTab;
import DisplayProject.actions.FloatOverText;
import DisplayProject.actions.Focusable;
import DisplayProject.actions.Height;
import DisplayProject.actions.IntegerValue;
import DisplayProject.actions.MaxCharacters;
import DisplayProject.actions.MenuText;
import DisplayProject.actions.MoveAbove;
import DisplayProject.actions.MoveBelow;
import DisplayProject.actions.NodeInsert;
import DisplayProject.actions.ObjectValue;
import DisplayProject.actions.Parent;
import DisplayProject.actions.PendingAction;
import DisplayProject.actions.Row;
import DisplayProject.actions.TableRow;
import DisplayProject.actions.TextValue;
import DisplayProject.actions.UserWindow;
import DisplayProject.actions.Visible;
import DisplayProject.actions.WidgetState;
import DisplayProject.actions.Width;
import DisplayProject.actions.WindowDisplayState;
import DisplayProject.binding.BindingManager;
import DisplayProject.controls.ArrayField;
import DisplayProject.controls.AutoResizingComboBox;
import DisplayProject.controls.FillInField;
import DisplayProject.controls.Graphic;
import DisplayProject.controls.ListView;
import DisplayProject.controls.MenuList;
import DisplayProject.controls.OutlineField;
import DisplayProject.controls.Panel;
import DisplayProject.controls.TextGraphic;
import DisplayProject.events.ClientEventManager;
import DisplayProject.factory.MenuFactory;
import DisplayProject.plaf.Win32LookAndFeel;
import DisplayProject.table.ArrayFieldCellHelper;
import DisplayProject.table.ArrayFieldCellRenderer;
import DisplayProject.table.FormattedCellRenderer;
import DisplayProject.table.GenericCellEditor;
import DisplayProject.table.ArrayFieldCellEditor.EditorLayoutPanel;
import Framework.Array_Of_ListElement;
import Framework.CancelException;
import Framework.CloneHelper;
import Framework.DynamicArray;
import Framework.ErrorMgr;
import Framework.EventHandle;
import Framework.EventManager;
import Framework.ForteKeyboardFocusManager;
import Framework.FrameworkUtils;
import Framework.ImageData;
import Framework.ListElement;
import Framework.MsgCatalog;
import Framework.NumericFormat;
import Framework.ParameterHolder;
import Framework.Task;
import Framework.TextData;
import Framework.UsageException;

/**
* This is a collection of common routines relating to the GUI
*
*/
public class UIutils {
    private static Logger _log = Logger.getLogger(UIutils.class);
    private static final String NESTED_PROPERTY_SEPERATOR = ".";
    /*
     * There is a difference on colour definition between
     * Forte and Java. Essentially where A "Bright" colour is used
     * in Forte the ordinary colour is used in Java
     */
    public static final Color Black = java.awt.Color.black;
    public static final Color Blue = new Color(64, 64, 255);
    public static final Color BrightBlue = java.awt.Color.blue;
    public static final Color BrightBrown = new Color(85, 64, 44);
    public static final Color BrightCyan = java.awt.Color.cyan;
    public static final Color BrightGreen = java.awt.Color.green;
    public static final Color BrightMagenta = java.awt.Color.magenta;
    public static final Color BrightRed = java.awt.Color.red;
    public static final Color BrightYellow = java.awt.Color.yellow;
    public static final Color Brown = new Color(103, 64, 21);
    public static final Color Cyan = new Color(85, 255, 255);

    public static final Color Gray1 = new Color(224, 224, 224);
    public static final Color Gray2 = new Color(192, 192, 192);
    public static final Color Gray3 = new Color(160, 160, 160);
    public static final Color Gray4 = new Color(128, 128, 128);
    public static final Color Gray5 = new Color(96, 96, 96);
    public static final Color Gray6 = new Color(64, 64, 64);
    public static final Color Gray7 = new Color(32, 32, 32);
    public static final Color Green = new Color(64, 255, 64);
    public static final Color Inherit = null;
    public static final Color Magenta = new Color(255, 85, 255);
    public static final Color PaleBlue = new Color(128, 128, 255);
    public static final Color PaleBrown = new Color(128, 64, 0);
    public static final Color PaleCyan = new Color(170, 255, 255);
    public static final Color PaleMagenta = new Color(255, 170, 255);
    public static final Color PaleRed = new Color(255, 128, 128);
    public static final Color PaleGreen = new Color(128, 255, 128);
    public static final Color PaleYellow = new Color(255, 255, 170);
    public static final Color Red = new Color(255, 64, 64);
    public static final Color White = java.awt.Color.white;
    public static final Color Yellow = new Color(255, 255, 85);
   

    /**
     * In Forte, the number of columns of a control could be set for several controls. This is mimiced in Java,
     * but the number of columns appears to be wrong. This constant is a scaling factor that when applied to the
     * number of columns in Forte, gives a result that is approximately the same width
     */
    public static final double FORTE_COLUMNS_SCALING_FACTOR = 0.7;
   
    private UIutils() {
    }

    /**
     * This method procesed all the pending GUI actions in the correct order and
     * in the EDT. This work is deligated to the ActionMgr class
     *
     */
    public static void processGUIActions() {
        ActionMgr.processGUIActions();
    }

    /**
     * Process GUI actions on a specific object, and runs on the EDT
     *
     * @param target
     */
    public static void processGUIActions(Component target) {
        ActionMgr.processGUIActions(target);
    }

    /**
     * registers a new color and provides an index to it.
     *
     * @param red
     * @param green
     * @param blue
     * @return
     */
    public static int registerColor(int red, int green, int blue) {
        return WindowSystem.registerColor(red, green, blue);
    }

    /**
     * deregisters the Custom Forte colour
     *
     * @param index
     */
    public static void unregisterColor(int index) {
        WindowSystem.unregisterColor(index);
    }
    /**
     * The size of the screen in pixels
     */
    private static Dimension screenSizePixels = Toolkit.getDefaultToolkit().getScreenSize();
    /**
     * The number of pixels per mil
     */
    private static double screenRatioPixelsPerMil = ((double) Toolkit.getDefaultToolkit().getScreenResolution()) / 1000.0;

    /**
     * Gets the Width of the screen in mils
     *
     * @return int
     */
    public static int getWidthInMils() {
        return (int) (screenSizePixels.width / screenRatioPixelsPerMil);
    }

    /**
     * Gets the Height of the screen in mils
     *
     * @return int
     */
    public static int getHeightInMils() {
        return (int) (screenSizePixels.height / screenRatioPixelsPerMil);
    }

    /**
     * Converts Mils to Pixels using the current screen resolution
     *
     * @param pMils
     * @return int
     */
    public static int milsToPixels(int pMils) {
        // NB -- if you're willing to assume pMils > 0, you can use the first
        // one, which is maginally faster.
        // return (int)(pMils * screenRatioPixelsPerMil + 0.5);
        return (int) (pMils * screenRatioPixelsPerMil + (pMils < 0 ? -0.5 : 0.5));
    }

    /**
     * Converts Pixels to Mils using the current screen resolution
     *
     * @param pPix
     * @return
     */
    public static int pixelsToMils(int pPix) {
        return (int) (pPix / screenRatioPixelsPerMil);
    }

    /**
     * Converts columns to Pixels using the average width of characters in the
     * control's font
     *
     * @param pCols
     * @param pWidget
     * @return int
     */
    public static int colsToPixels(int pCols, JComponent pWidget) {
        // TF:26/9/07: We need to add in the spacing between the columns
        return (int) (pCols * (averageCharacter(pWidget)+1));
    }
   
    /**
     * Get average character width based on a component
     * @param component
     * @return
     */
    public static int averageCharacter(JComponent component) {
        FontMetrics fm = component.getFontMetrics(component.getFont());
        int[] wds = fm.getWidths();
        float av = 0;
        for (int i = 0; i < wds.length; i++)
            av += wds[i];
        av /= wds.length;
        av *= 0.92;
        // TF:26/9/07: Allowed this number to round up or down
        return (int)(av+0.5);
    }
   
    /**
     * Get average character width based on a font
     * @param font
     * @return
     */
    public static int averageCharacter(Font font){
        JLabel label = new JLabel();
        label.setFont(font);
        return averageCharacter(label);
    }

    /**
     * Converts Pixels to Columns using the average width of characters in the
     * control's font
     *
     * @param pPixels
     * @param pWidget
     * @return
     */
    public static int pixelsToCols(int pPixels, JComponent pWidget) {
      // TF:19/06/2008:Changed this to mirror the colsToPixels function for consistency
      int avgSize = averageCharacter(pWidget) + 1;
      // Round up
      return (int)((pPixels + avgSize - 1) / avgSize);
    }

    /**
     * Converts rows to Pixels using the height of the control's font.
     *
     * @param pRows
     * @param pWidget
     * @return
     */
    public static int rowsToPixels(int pRows, JComponent pWidget) {
        FontMetrics fm = pWidget.getFontMetrics(pWidget.getFont());
        return pRows * fm.getHeight();//(fm.getMaxAscent() + fm.getMaxDescent());
    }

    /**
     * Converts the Forte colour constant to an equivelant java COLOR. Not all
     * Forte colours translate perfectly.
     *
     * @param colour
     * @return
     */
    public static Color forteToJavaColor(int colour) {
        Color target = null;
        switch (colour) {
            case Constants.C_BLACK:
                target = UIutils.Black;
                break;
            case Constants.C_BLUE:
                target = UIutils.Blue;
                break;
            case Constants.C_BRIGHTBLUE:
                target = UIutils.BrightBlue;
                break;
            case Constants.C_BRIGHTBROWN:
                target = UIutils.BrightBrown;
                break;
            case Constants.C_BRIGHTCYAN:
                target = UIutils.BrightCyan;
                break;
            case Constants.C_BRIGHTGREEN:
                target = UIutils.BrightGreen;
                break;
            case Constants.C_BRIGHTMAGENTA:
                target = UIutils.BrightMagenta;
                break;
            case Constants.C_BRIGHTRED:
                target = UIutils.BrightRed;
                break;
            case Constants.C_BRIGHTYELLOW:
                target = UIutils.BrightYellow;
                break;
            case Constants.C_BROWN:
                target = UIutils.Brown;
                break;
            case Constants.C_CYAN:
                target = UIutils.Cyan;
                break;
            case Constants.C_GRAY1:
                target = UIutils.Gray1;
                break;
            case Constants.C_GRAY2:
                target = UIutils.Gray2;
                break;
            case Constants.C_GRAY3:
                target = UIutils.Gray3;
                break;
            case Constants.C_GRAY4:
                target = UIutils.Gray4;
                break;
            case Constants.C_GRAY5:
                target = UIutils.Gray5;
                break;
            case Constants.C_GRAY6:
                target = UIutils.Gray6;
                break;
            case Constants.C_GRAY7:
                target = UIutils.Gray7;
                break;
            case Constants.C_GREEN:
                target = UIutils.Green;
                break;
            case Constants.C_MAGENTA:
                target = UIutils.Magenta;
                break;
            case Constants.C_PALEBLUE:
                target = UIutils.PaleBlue;
                break;
            case Constants.C_PALEBROWN:
                target = UIutils.PaleBrown;
                break;
            case Constants.C_PALECYAN:
                target = UIutils.PaleCyan;
                break;
            case Constants.C_PALEMAGENTA:
                target = UIutils.PaleMagenta;
                break;
            case Constants.C_PALERED:
                target = UIutils.PaleRed;
                break;
            case Constants.C_PALEGREEN:
                target = UIutils.PaleGreen;
                break;
            case Constants.C_PALEYELLOW:
                target = UIutils.PaleYellow;
                break;
            case Constants.C_RED:
                target = UIutils.Red;
                break;
            case Constants.C_WHITE:
                target = UIutils.White;
                break;
            case Constants.C_YELLOW:
                target = UIutils.Yellow;
                break;
            case Constants.C_DEFAULT:
                target = SystemColor.control;
                break;
            case Constants.C_INHERIT:
                target = null;
                break;
            default:
                if (colour < WindowSystem.cREG_COL_OFFSET)
                    target = null;
                else
                    target = WindowSystem.registeredJavaColor(colour);
                break;
        }
        return target;
    }

    public static int getAlphaValue(BufferedImage pImage, int pRow, int pCol) {
        return (pImage.getRGB(pCol, pRow) & 0xFF000000) >> 24;
    }

    public static int getRedValue(BufferedImage pImage, int pRow, int pCol) {
        return (pImage.getRGB(pCol, pRow) & 0x00FF0000) >> 16;
    }

    public static int getGreenValue(BufferedImage pImage, int pRow, int pCol) {
        return (pImage.getRGB(pCol, pRow) & 0x0000FF00) >> 8;
    }

    public static int getBlueValue(BufferedImage pImage, int pRow, int pCol) {
        return (pImage.getRGB(pCol, pRow) & 0x000000FF) >> 0;
    }

    public static void setRedValue(BufferedImage pImage, int pRow, int pCol, int pValue) {
        pImage.setRGB(pCol, pRow, (pImage.getRGB(pCol, pRow) & 0xFF00FFFF) | ((pValue & 0xFF) << 16));
    }

    public static void setGreenValue(BufferedImage pImage, int pRow, int pCol, int pValue) {
        pImage.setRGB(pCol, pRow, (pImage.getRGB(pCol, pRow) & 0xFFFF00FF) | ((pValue & 0xFF) << 8));
    }

    public static void setBlueValue(BufferedImage pImage, int pRow, int pCol, int pValue) {
        pImage.setRGB(pCol, pRow, (pImage.getRGB(pCol, pRow) & 0xFFFFFF00) | ((pValue & 0xFF) << 0));
    }

    public static void setAlphaValue(BufferedImage pImage, int pRow, int pCol, int pValue) {
        pImage.setRGB(pCol, pRow, (pImage.getRGB(pCol, pRow) & 0x00FFFFFF) | ((pValue & 0xFF) << 24));
    }

    public static void setRGBValue(BufferedImage pImage, int pRow, int pCol, int pRed, int pGreen, int pBlue) {
        pImage.setRGB(pCol, pRow, ((pRed & 0xFF) << 16) | ((pGreen & 0xFF) << 8) | (pBlue & 0xFF));
    }

    /**
     * Resizes a JLabel based on the Font, number of lines and line widths
     *
     * @author Duncan Meyer
     * @param label
     */
    public static Dimension labelWidth(JLabel label) {
        return labelWidth(label, false);
    }

    public static Dimension labelWidth(JLabel label, boolean validateUP) {
        // TF:22/11/07:Made the TextGraphic have a good idea how to lay itself out,
        // meaning that this method is no longer needed.
        if (label instanceof TextGraphic) {
            return label.getMinimumSize();
        }
        // Remove the trailing "\n" character.
        String labelTxt = label.getText();
        if (labelTxt == null)
            return label.getSize();
        int p = labelTxt.indexOf("\n");
        if (p >= 0) {
            if (labelTxt.lastIndexOf("\n") == labelTxt.length() - 1) {
                label.setText(labelTxt.substring(0, labelTxt.length() - 1));
            }
        }
        final String labelText = label.getText();
        final JLabel lab = label;
        // Insert html tags in labels where appropriate and resize labels from
        // metrics.
        Font f = lab.getFont();
        FontMetrics fm = lab.getFontMetrics(f);
        p = labelText.indexOf("\n");
        StringTokenizer s = new StringTokenizer(labelText, "\n");
        int width = 0;
        int lines = 0;
        // If the string contains \n characters and doesn't have html tags
        // already.
        if (s.hasMoreTokens() && (p != -1) && ((labelText.length() < 6) || !(labelText.substring(0, 6).equals("<html>")))) {
            StringBuilder target = new StringBuilder("<html>");//PM:7 oct. 2008:changed to StringBuilder
            // obtain number of lines and insert html <r> tags into label.
            // obtain the dimensions of the label from this data.
            while (s.hasMoreTokens()) {
                lines++;
                String token = s.nextToken();
                int newWidth = SwingUtilities.computeStringWidth(fm, token);
                if (newWidth > width)
                    width = newWidth;
                target.append(token);
                if (s.hasMoreTokens())
                    target.append("<br>");
            }
            target.append("</html>");
            lab.setText(target.toString());
            // Label does not need html tags because it contains no \n
            // characters..
        }
        else {

            // It's possible we've already processed this text, or it was sent
            // as HTML, so we need
            // to look for HTML line terminators, eg <br>, <p>. However, we must
            // search case insensitive
            String lowerLabelText = labelText.toLowerCase();
            List<String> allLines = new ArrayList<String>();
            int index = 0;
            do {
                int breakIndex = lowerLabelText.indexOf("<br>", index);
                int paraIndex = lowerLabelText.indexOf("<p>", index);
                int newIndex = Math.min(breakIndex < 0 ? Integer.MAX_VALUE : breakIndex, paraIndex < 0 ? Integer.MAX_VALUE : paraIndex);
                if (newIndex < Integer.MAX_VALUE) {
                    // There's at least one more token. Copy the normal case
                    // text.
                    String thisLine = labelText.substring(index, newIndex);
                    allLines.add(thisLine);
                    // Reset the search index, ensuring we skip over the
                    // remainder of this tag
                    index = labelText.indexOf(">", newIndex + 1) + 1;
                }
                else {
                    // no more tokens, just copy what we currently have
                    String thisLine = labelText.substring(index);
                    allLines.add(thisLine);
                    index = -1;
                }
            } while (index >= 0);

            // Now we have the lines in the array list, find their widths
            width = 0;
            for (String thisLine : allLines) {
                int thisLineWidth = SwingUtilities.computeStringWidth(fm, thisLine);
                if (thisLineWidth > width) {
                    width = thisLineWidth;
                }
                lines++;
            }
        }
        int height = (fm.getHeight() + fm.getDescent()) * lines;
        Dimension sz = new Dimension(width + 1, height);

        // TF:21/9/07:If we're explicitly sized, keep these dimensions the same. If we're sized to parent,
        // set the size to be the larger of the calculated (minimum) size and the current size
        GridCell cell = GridField.getConstraints(lab);
        if (cell.getWidthPolicy() == Constants.SP_EXPLICIT) {
            sz.width = lab.getWidth();
        }
        else if (cell.getWidthPolicy() == Constants.SP_TO_PARENT) {
            sz.width = Math.max(sz.width, lab.getWidth());
        }
        if (cell.getHeightPolicy() == Constants.SP_EXPLICIT) {
            sz.height = lab.getHeight();
        }
        else if (cell.getHeightPolicy() == Constants.SP_TO_PARENT) {
            sz.height = Math.max(sz.height, lab.getHeight());
        }
        boolean sizeChanged = false;
        if (!lab.isPreferredSizeSet() || !lab.getPreferredSize().equals(sz)) {
            lab.setPreferredSize(sz);
            sizeChanged = true;
        }
        if (!lab.isMinimumSizeSet() || !lab.getMinimumSize().equals(sz)) {
            lab.setMinimumSize(sz);
            sizeChanged = true;
        }
        if (lab.getWidth() != sz.width || lab.getHeight() != sz.height) {
            lab.setSize(sz);
            sizeChanged = true;
        }
        if (validateUP && sizeChanged) {
            Component target = lab;
            while (target.getParent() != null) {
                target.getParent().validate();
                target = target.getParent();
            }
        }
        return sz;
    }

    public static int columnWidthForTable(JComponent comp, String text) {
        int result;
        Font f = comp.getFont();
        FontMetrics fm = comp.getFontMetrics(f);
        result = SwingUtilities.computeStringWidth(fm, text) + 16;
        return result;
    }

    /**
     * Displays a dialog indicating that the field contains invalid characters
     *
     * @param fieldName
     * @param fieldValue
     */
    public static void invalidCharsDialog(String fieldName, String fieldValue) {
        Object[] data = { fieldName, fieldValue };
        String msg = MessageFormat.format("Invalid characters encounted in field {0}: {1}", data);
        WindowManager.showMessageDialog(null, msg, "Invalid Characters", JOptionPane.ERROR_MESSAGE);
    }

    // Note that this works for mouse events - but does not stop the user using
    // shortcuts
    // to, for example, close the window whilst we are waiting on a query
    // response. Will
    // raise new issue for this.
    private static final MouseAdapter mouseAdapterWait = new MouseAdapter() {
    };

    private static final KeyListener kl = new KeyListener() {
        public void keyPressed(KeyEvent ke) {
        };

        public void keyReleased(KeyEvent ke) {
        };

        public void keyTyped(KeyEvent ke) {
        };
    };

    /**
     * Forte Windows displayed the 'Hour Glass' cursor and disabled the window
     * while processing the body of an event handler. This method changes the
     * cursor and disables the window.
     *
     * @deprecated use CursorMgr.startEvent() instead
     */
    public static void startWaitCursor(JComponent component) {
        CursorMgr.startEvent();
    }

    /**
     * Forte Windows displayed the 'Hour Glass' cursor and disabled the window
     * while processing the body of an event handler. This method changes the
     * cursor and disables the window.
     *
     * @deprecated use CursorMgr.startEvent() instead
     */
    public static void startWaitCursor(JWindow win) {
        CursorMgr.startEvent();
    }

    /**
     * Forte Windows displayed the 'Hour Glass' cursor and disabled the window
     * while processing the body of an event handler. This method changes the
     * cursor and disables the window.
     *
     * @deprecated use startWaitCursor() instead
     */
    public static void startWaitCursor(Object o) {
        CursorMgr.startEvent();
    }

    /**
     * Forte Windows displayed the 'Hour Glass' cursor and disabled the window
     * while processing the body of an event handler. This method changes the
     * cursor and disables the window.
     */
    public static void startWaitCursor() {
        CursorMgr.startEvent();
    }

    /**
     * @deprecated use startWaitCursor() instead
     */
    protected static void startWaitCursorGP(final Component glass) {
        UIutils.invokeOnGuiThread(new Runnable() {
            public void run() {
                glass.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
                glass.addMouseListener(mouseAdapterWait);
                glass.addKeyListener(kl);
                glass.setVisible(true);
            }
        });
    }

    /**
     * Forte Windows displayed the 'Hour Glass' cursor and disabled the window
     * while processing the body of an event handler. This method changes the
     * cursor and enables the window.
     *
     * @deprecated use CursorMgr.endEvent() instead
     */
    public static void stopWaitCursor(JComponent component) {
        CursorMgr.endEvent();
    }

    /**
     * Forte Windows displayed the 'Hour Glass' cursor and disabled the window
     * while processing the body of an event handler. This method changes the
     * cursor and enables the window.
     *
     * @deprecated use CursorMgr.endEvent() instead
     */
    public static void stopWaitCursor(JWindow win) {
        CursorMgr.endEvent();
    }

    /**
     * Forte Windows displayed the 'Hour Glass' cursor and disabled the window
     * while processing the body of an event handler. This method changes the
     * cursor and enables the window.
     *
     * @deprecated use CursorMgr.endEvent() instead
     */
    public static void stopWaitCursor(Object o) {
        CursorMgr.endEvent();
    }

    /**
     * Retrieve the glass pane associate with the passed component if one exists.
     *
     * @param component
     *            the component of which to get the glass pane
     * @return the glass pane, or null if not possible to determine
     */
    protected static GlassPaneWithEvents getGlassPane(Component component) {
       
      if (component instanceof JDialog) {
          Component comp = ((JDialog)component).getGlassPane();
         
          // Install our customised glass pane if not already installed.  CraigM: 31/03/2008
          if (comp instanceof GlassPaneWithEvents == false) {
            comp = new GlassPaneWithEvents(((JDialog)component).getContentPane());
            ((JDialog)component).setGlassPane(comp);
          }
         
          return (GlassPaneWithEvents)comp;
        }

      else if (component instanceof JFrame) {
          Component comp = ((JFrame)component).getGlassPane();

          // Install our customised glass pane if not already installed.  CraigM: 31/03/2008
          if (comp instanceof GlassPaneWithEvents == false) {
            comp = new GlassPaneWithEvents(((JFrame)component).getContentPane());
            ((JFrame)component).setGlassPane(comp);
          }
         
          return (GlassPaneWithEvents)comp;
        }
     
        else {
            return null;
        }
    }

    /**
     * Forte Windows displayed the 'Hour Glass' cursor and disabled the window
     * while processing the body of an event handler. This method changes the
     * cursor and enables the window.
     */
    public static void stopWaitCursor() {
        CursorMgr.endEvent();
    }

    protected static void stopWaitCursorGP(final Component component) {
        UIutils.processGUIActions();
        UIutils.invokeOnGuiThread(new Runnable() {
            public void run() {
                // UIutils.processGUIActions();
                component.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
                component.removeMouseListener(mouseAdapterWait);
                component.removeKeyListener(kl);
                component.setVisible(false);
            }
        });
    }

    /**
     * This method sets the Enabled state on a compound widget and its children
     *
     *
     */
    public static void setEnabled(java.awt.Component comp, boolean value) {
        Enabled.set(comp, value);
    }

    /**
     * This method enables a column in an ArrayField (JTable) by setting a flag
     * in the CellEditor
     *
     * @param comp
     * @param value
     */
    public static void setEnabled(GenericCellEditor comp, boolean value) {
        Enabled.set(comp, value);
    }

    /**
     * This method sets the Visible state on a compound widget and its children
     *
     *
     */
    public static void setVisible(Component comp, boolean value) {
        Visible.set(comp, value);
    }

    /**
     * sets the Visible state on a column in a ListView or ArrayField (JTable)
     *
     * @param comp
     * @param value
     */
    public static void setVisible(GenericCellEditor comp, boolean value) {
        Visible.set(comp, value);
    }

    /**
     * This method sets the Focus state on a compound widget and its children
     *
     *
     */
    public static void setFocusable(Component comp, boolean value) {
        Focusable.set(comp, value);
    }

    /**
     * This method emulates the state attribute and gets the state on the
     * ArrayColumn base on the forte constanr
     *
     * @param comp
     * @param state
     * @deprecated - use WidgetState.set(comp, state) instead
     */
    public static void setState(ArrayColumn comp, int state) {
        if (comp == null)
            return;
        switch (state) {
            case Constants.FS_UPDATE:
                Enabled.set((GenericCellEditor) comp.getEditor(), true);
                Visible.set((GenericCellEditor) comp.getEditor(), true);
                break;
            case Constants.FS_DISABLED:
                Enabled.set((GenericCellEditor) comp.getEditor(), false);
                Visible.set((GenericCellEditor) comp.getEditor(), true);
                break;
            case Constants.FS_INVISIBLE:
                Enabled.set((GenericCellEditor) comp.getEditor(), false);
                Visible.set((GenericCellEditor) comp.getEditor(), false);
                break;
            case Constants.FS_VIEWONLY:
                Enabled.set((GenericCellEditor) comp.getEditor(), true);
                Visible.set((GenericCellEditor) comp.getEditor(), true);
                break;
            case Constants.FS_INACTIVE:
                Enabled.set((GenericCellEditor) comp.getEditor(), true);
                Visible.set((GenericCellEditor) comp.getEditor(), true);
                break;
        }
        return;
    }

    /**
     * This method emulates the forte state attribute and gets the state on the
     * selected ButtonGroup base on the forte constant
     *
     * @param comp
     * @param state
     */
    public static void setState(ButtonGroup comp, int state) {
        if (comp == null)
            return;
        Enumeration<AbstractButton> enum1 = comp.getElements();
        while (enum1.hasMoreElements()) {
            UIutils.setState((Component) enum1.nextElement(), state);
        }
    }

    /**
     * sets the Forte state on a Menu
     *
     * @param comp
     * @param state
     */
    public static void setState(MenuElement comp, int state) {
        if (comp == null)
            return;
        if (comp instanceof JMenuItem) {
            setState((JMenuItem) comp, state);
            return;
        }
        if (comp instanceof JMenu) {
            setState((JMenu) comp, state);
            return;
        }
    }

    /**
     * sets the forte state on a Menu.
     *
     * @param mi
     * @param state
     */
    public static void setState(JMenuItem mi, int state) {
        switch (state) {
            case Constants.MS_ENABLED:
                setEnabled(mi, true);
                setVisible(mi, true);
                break;
            case Constants.MS_DISABLED:
                setEnabled(mi, false);
                setVisible(mi, true);
                break;
            case Constants.MS_INVISIBLE:
                setEnabled(mi, true);
                setVisible(mi, false);
                break;
        }
    }

    /**
     * sets the Forte state on a Menu
     *
     * @param comp
     * @param state
     */
    public static void setState(JMenu comp, int state) {
        switch (state) {
            case Constants.MS_ENABLED:
                setEnabled(comp, true);
                setVisible(comp, true);
                break;
            case Constants.MS_DISABLED:
                setEnabled(comp, false);
                setVisible(comp, true);
                break;
            case Constants.MS_INVISIBLE:
                setEnabled(comp, true);
                setVisible(comp, false);
                break;
        }
    }

    /**
     * sets the Forte state on a popup menu
     *
     * @param comp
     * @param state
     */
    public static void setState(JPopupMenu comp, int state) {
        switch (state) {
            case Constants.MS_ENABLED:
                setEnabled(comp, true);
                setVisible(comp, true);
                break;
            case Constants.MS_DISABLED:
                setEnabled(comp, false);
                setVisible(comp, true);
                break;
            case Constants.MS_INVISIBLE:
                setEnabled(comp, true);
                setVisible(comp, false);
                break;
        }
    }

    /**
     * This method emulates the forte state attribute and gets the state on the
     * selected component base on the forte constant
     *
     * @param comp
     * @param state
     */
    public static void setState(Component comp, int state) {
        if (comp == null)
            return;
        WidgetState.set(comp, state);
    }

    /**
     * This method emulates the forte state attribute on a menu, it return the
     * state as the forte constant
     *
     * @param comp
     * @param state
     */
    public static int getState(JMenuItem comp) {
        return getState((Component) comp);
    }

    /**
     * This method emulates the forte state attribute on a menu, it return the
     * state as the forte constant
     *
     * @param comp
     * @param state
     */
    public static int getState(MenuElement comp) {
        if (comp instanceof JMenuItem)
            return getState((Component) comp);
        // default
        RuntimeException errorVar = new RuntimeException("Menu state not supported for: " + comp.getClass().getName());
        ErrorMgr.addError(errorVar);
        throw errorVar;
    }

    /**
     * Returns the State of a Widget as a Forte State
     *
     * @param comp
     * @return
     */
    public static int getState(Component comp) {
        if (comp instanceof JMenuItem) {
            boolean isEnabled = Enabled.is(comp);
            boolean isVisible = Visible.is(comp);

            if (isEnabled && isVisible)
                return Constants.MS_ENABLED;

            if (!isEnabled && isVisible)
                return Constants.MS_DISABLED;

            if (isEnabled && !isVisible)
                return Constants.MS_INVISIBLE;

            // default
            RuntimeException errorVar = new RuntimeException("Menu state not supported for: " + comp.getName());
            ErrorMgr.addError(errorVar);
            throw errorVar;
        }
        else {
            if ((comp instanceof JPanel) && (comp.getParent() != null && comp.getParent() instanceof JTabbedPane)) {
                return Constants.FS_VIEWONLY;
            }
            else {
                boolean isEnabled = Enabled.is(comp);
                boolean isVisible = Visible.is(comp);
                boolean isFocusable = Focusable.is(comp);

                if (!isVisible)
                    return Constants.FS_INVISIBLE;

                if (isEnabled && isFocusable)
                    return Constants.FS_UPDATE;

                if (!isEnabled && !isFocusable)
                    return Constants.FS_DISABLED;

                if (!isEnabled && isFocusable)
                    return Constants.FS_VIEWONLY;

                if (isEnabled && !isFocusable)
                    return Constants.FS_INACTIVE;
            }
            // default
            RuntimeException errorVar = new RuntimeException("Widget state not supported for: " + comp.getName());
            ErrorMgr.addError(errorVar);
            throw errorVar;
        }
    }

    /**
     * The GetStateForUsage method retrieves the state setting information for a
     * widget in a given usage. You can use GetStateForUsage as a convenient way
     * to dynamically determine a widget�s state for any usage its parent window
     * can take. The GetStateForUsage method returns an integer that identifies
     * the state of the widget in the particular usage.
     *
     * CraigM:23/06/2008 - Just call the WidgetState.getForUsage method.
     *
     * @param comp
     * @param usage
     * @return
     */
    public static int getStateForUsage(JComponent comp, int usage) {
      return WidgetState.getForUsage(comp, usage);
    }
   
   
    /**
     * sets the forte state on a column in an ArrayField or ListView (JTable)
     *
     * @param comp
     * @param state
     */
    public static void setState(GenericCellEditor comp, int state) {

        switch (state) {
            case Constants.FS_UPDATE:
                setEnabled(comp, true);
                setVisible(comp, true);
                break;
            case Constants.FS_DISABLED:
                setEnabled(comp, false);
                setVisible(comp, true);
                break;
            case Constants.FS_INVISIBLE:
                setEnabled(comp, false);
                setVisible(comp, false);
                break;
            case Constants.FS_VIEWONLY:
                setEnabled(comp, false);
                setVisible(comp, true);
                break;
            case Constants.FS_VISIBLE:
                setEnabled(comp, false);
                setVisible(comp, true);
                break;

        }
    }

    /**
     * provides the equivelant of the Forte HasDataChanged for widgets.
     *
     * @param comp
     * @return
     */
    public static boolean hasDataChanged(JComponent comp) {
        boolean hasit = false;
        Object o = comp.getClientProperty("HasDataChanged");
        if ((o != null) && (o instanceof Boolean)) {
            hasit = ((Boolean) o).booleanValue();
        }
        return hasit;
    }

    /**
     * provides the equivelant of the Forte HasDataChanged for windows.
     *
     * @param comp
     * @return
     */
    public static boolean hasDataChanged(JFrame frame) {
        boolean hasit = false;
        Object o = null;
        try {
            Method m = frame.getClass().getMethod("getForm", (Class[])null);
            JPanel form = ((JPanel) m.invoke(frame, (Object[])null));
            o = form.getClientProperty("HasDataChanged");
        }
        catch (Exception e) {
            _log.error("Unhandled exception", e);
        }
        if ((o != null) && (o instanceof Boolean)) {
            hasit = ((Boolean) o).booleanValue();
        }
        return hasit;
    }

    /**
     * used to indicate that data has changed in a window
     *
     * @param frame
     * @param value
     */
    public static void setDataChanged(JFrame frame, boolean value) {
        try {
            Method m = frame.getClass().getMethod("getForm", (Class[])null);
            JPanel form = ((JPanel) m.invoke(frame, (Object[])null));
            form.putClientProperty("HasDataChanged", Boolean.valueOf(value));
        }
        catch (Exception e) {
            _log.error("Unhandled exception", e);
        }
    }
    /**
     * used to indicate that the data has changed in a component
     *
     * @param comp
     * @param value
     */
    public static void setDataChanged(JComponent comp, boolean value) {
        JComponent c = comp;
        while (c != null) {
            c.putClientProperty("HasDataChanged", Boolean.valueOf(value));
            if (c.getParent() instanceof JComponent)
                c = ((JComponent) c.getParent());
            else
                c = null;
        }
    }

    /**
     * This method is a helper that returns the current node in a ListView
     * (JTable). This hides the complexity of accessing the current node
     *
     * @author Peter
     *
     */
    public static DisplayNode currentNode(JTree treeView) {
        DisplayNode dn = (DisplayNode) treeView.getSelectionPath().getLastPathComponent();
        return dn;
    }

    /**
     * This method is a helper that returns the current node in a ListView
     * (JTable). This hides the complexity of accessing the current node
     *
     * @author Peter
     *
     */
    public static DisplayNode currentNode(JTable listView) {
        if (listView.getModel() instanceof TableSorter) {
            DisplayNode dn = ((((ArrayFieldModel) ((TableSorter) listView.getModel()).getTableModel()).getCurrentRow()));
            return dn;
        }
        else
            return null;
    }

    /**
     * Returns the currently selected node in OutlineField
     *
     * @param outlineField
     * @return DisplayNode
     */
    public static DisplayNode currentNode(OutlineField outlineField) {
        return outlineField.getCurrentNode();
    }

    /**
     * returns the current node of the JListView emulating the Forte ListView
     *
     * @param listView
     * @return DisplayNode
     * @deprecated the JListView type should not be used, use a ListView instead
     */
    public static DisplayNode currentNode(JListView listView) {
        DisplayNode dn = (DisplayNode) listView.getCurrentNode();
        return dn;
    }

    /**
     * This method is a helper that refreshes the data in a ListView (JTable).
     * This hides the complexity of accessing the model
     *
     * @author Peter
     *
     */
    public static void updateFieldFromData(JTable listView) {
        if (listView.getModel() instanceof TableSorter) {
            ((ArrayFieldModel) ((TableSorter) listView.getModel()).getTableModel()).fromData();
        }
    }

    /**
   * The updateFieldFromData method refreshes a widget�s data display
   * immediately, according to the current values for any data mapped to a
   * widget.
   *
   * Widgets mapped directly to data attributes update their data displays
   * automatically. You use the UpdateFieldFromData method to update the data
   * displays of widgets mapped to virtual attributes, which do not update
   * their data displays.
   *
   * If you use this method to update a compound field, it also updates all
   * the child widgets of the compound field. To refresh all widgets in a
   * window, invoke the UpdateFieldFromData method on the window, referring to
   * the window�s Form attribute.
   *
   * @param component - Any window component
   */
    public static void updateFieldFromData(Component component) {
      // get the related Window for the component
      JFrame frame = getDeclaredFrame(component);
      if (frame != null) {
        try {
          // Get the window binding Manager
          Method bindingManagerMethod;
          bindingManagerMethod = frame.getClass().getDeclaredMethod("getBindingManager", new Class[0]);
          bindingManagerMethod.setAccessible(true);
          BindingManager bindingManager = (BindingManager)bindingManagerMethod.invoke(frame, new Object[0]);
          if (bindingManager != null) {
            updateFieldFromData(component, frame, bindingManager);
          }
        } catch (Exception e) {
          // ignore the error, no binding Manager
        }
    }
    }

    private static void updateFieldFromData(Component component, JFrame frame, BindingManager bindingManager) {
      if (component instanceof JComponent) {
        JComponent jComponent = (JComponent) component;
        // Get the component's related data if it is a JComponent
        Object data = bindingManager.getDataObject(jComponent);
        if (data != null) {
          Object propertyChangeHolder;
          String dataObjectPath = BindingManager.getDataObjectPath(jComponent);
          if (dataObjectPath != null && dataObjectPath.indexOf(NESTED_PROPERTY_SEPERATOR) != -1) {
            String parentObjectPath = dataObjectPath.substring(0, dataObjectPath.lastIndexOf(NESTED_PROPERTY_SEPERATOR));
            // get the parent object
            propertyChangeHolder = bindingManager.getDataObject(parentObjectPath);
        } else {
          // Use the from propertyChangeSupport
          propertyChangeHolder = frame;
        }
        // Get the window listeners
          try {
            Field field = propertyChangeHolder.getClass().getField("qq_Listeners");
            field.setAccessible(true);
            PropertyChangeSupport propertyChangeSupport = (PropertyChangeSupport)field.get(propertyChangeHolder);
            if (propertyChangeSupport != null) {

              // if there is data then fire a Property Change to force a re-binding
              propertyChangeSupport.firePropertyChange(getPropertyNameForComponent(jComponent), null, data);
            }
          } catch (Exception e) {
            // ignore the error, no listener
          }
        } else {
          if (component instanceof CompoundField) {
            // if no data and a CompoundField then loop thru all the child components
            CompoundField compoundField = (CompoundField) component;
            Component[] componentArray = compoundField.getComponents();
            for (int i = 0; i < componentArray.length; i++) {
              updateFieldFromData(componentArray[i], frame, bindingManager);
            }
          }
        }
      } else if (component instanceof JFrame) {
        // if a window then use the Form panel as the component
        updateFieldFromData(getForm((JFrame)component), frame, bindingManager);
      }
    }

    private static String getPropertyNameForComponent(JComponent jComponent) {
      //AD:14/12/2008: FTL-1 Fixed the jcomponent name to deal with nested component names
      String propertyName = jComponent.getName();
      int index = propertyName.lastIndexOf(NESTED_PROPERTY_SEPERATOR);
      if (index != -1) {
        // if there is nesting to the name the only use the final part
        propertyName = propertyName.substring(index+1);
    }
      return FrameworkUtils.getPropertyName(propertyName);

    }
    /**
     * getTabPages facilitates the creation of a collection of JPanels from a
     * tab layout It is intended that this method is used in a 'get' mode only
     */
    public static List<JPanel> getTabPages(JTabbedPane tp) {
        DynamicArray<JPanel> pages = new DynamicArray<JPanel>(JPanel.class);

        int numberOfTabs = tp.getTabCount();
        for (int i = 0; i < numberOfTabs; i++) {
            Component tmpPanel = tp.getComponentAt(i);
            if (tmpPanel instanceof JPanel)
                pages.add((JPanel)tmpPanel);
        }

        return pages;
    }

    /**
     * getTobPage facilitates the return of Top the JPanel from a tab layout It
     * is intended that this method is used in a 'get' mode only
     */
    public static JPanel getTopPage(JTabbedPane tp) {
        // Khon Chau 07032007 original code
        // this code was OK if all tabs are visible, but since certain tabs are
        // added/removed depending on status and product, etc, their order in
        // tp.Components does not remain the same although they are display in
        // the correct
        // order on the window
        // JPanel top = ((JPanel)tp.getComponent(tp.getSelectedIndex()+3));

        // just use the java method to get the selected component
        JPanel top = (JPanel) tp.getSelectedComponent();
        return top;
    }

    /**
     * A ButtonGroup (converted from a MenuList) is processed to return and
     * array of ListElements representing the menu Items.
     *
     * @param bg
     * @return
     */
    public static Array_Of_ListElement<ListElement> getMenuElementList(ButtonGroup bg) {
        Array_Of_ListElement<ListElement> les = new Array_Of_ListElement<ListElement>();
        Enumeration<AbstractButton> enum1 = bg.getElements();
        while (enum1.hasMoreElements()) {
            Object element = enum1.nextElement();
            if (element instanceof JRadioButtonMenuItem) {
                les.add(new ListElement(((JRadioButtonMenuItem) element).getText(), ((Integer) ((JRadioButtonMenuItem) element)
                        .getClientProperty("qq_value")).intValue()));
            }
            if (element instanceof JCheckBoxMenuItem) {
                les.add(new ListElement(((JCheckBoxMenuItem) element).getText(), ((Integer) ((JCheckBoxMenuItem) element)
                        .getClientProperty("qq_value")).intValue()));
            }
        }
        return les;
    }

    /**
     * adds entries to the ButtonGroup (formally a MenuList)
     *
     * @param bg
     * @param les
     */
    public static void setMenuElementList(ButtonGroup bg, Array_Of_ListElement<ListElement> les) {
        Enumeration<AbstractButton> enum1 = bg.getElements();
        while (enum1.hasMoreElements()) {
            bg.remove((AbstractButton) enum1.nextElement());
        }
        Iterator<ListElement> it = les.iterator();
        while (it.hasNext()) {
            ListElement le = (ListElement) it.next();
            MenuFactory.newRadioMenuItem(le.toString(), bg, le.getIntegerValue());
        }
    }

    /**
     * The SetViewNodes method assigns an array of DisplayNode objects to the
     * list view field. Because a list view field displays non-hierarchical
     * data, you do not need to create a node hierarchy to provide the data for
     * the field. You can simply construct an array of DisplayNode objects and
     * then use the SetViewNodes method to assign the array to the list view
     * field.
     *
     * @param lv
     * @param nodes
     */
  public static void setViewNodes(JTable lv, Array_Of_DisplayNode<DisplayNode> nodes) {
        ((ArrayFieldModel) ((TableSorter) lv.getModel()).getTableModel()).setViewNodes(nodes);
    }

    /**
     * The SetViewNodes method assigns an array of DisplayNode objects to the
     * list view field. Because a list view field displays non-hierarchical
     * data, you do not need to create a node hierarchy to provide the data for
     * the field. You can simply construct an array of DisplayNode objects and
     * then use the SetViewNodes method to assign the array to the list view
     * field.
     *
     * @param lv
     * @param nodes
     * @deprecated the type JListView is deprecated, use ListView instead
     */
    @SuppressWarnings("unchecked")
  public static void setViewNodes(JListView lv, DynamicArray nodes) {
        lv.setViewNodes(nodes);
    }

    /**
     * The SetViewNodes method assigns an array of DisplayNode objects to the
     * list view field. Because a list view field displays non-hierarchical
     * data, you do not need to create a node hierarchy to provide the data for
     * the field. You can simply construct an array of DisplayNode objects and
     * then use the SetViewNodes method to assign the array to the list view
     * field.
     *
     * @param lv
     * @param nodes
     */
    public static void setViewNodes(ListView lv, Array_Of_DisplayNode<DisplayNode> nodes) {
        lv.setViewNodes(nodes);
    }

    /**
     * sets the caption on a Panel (JPanel)
     *
     * @param panel
     * @param caption
     */
    public static void setCaption(JPanel panel, TextData caption) {
        setCaption(panel, caption.toString());
    }

    /**
     * sets the caption on a Panel (JPanel)
     *
     * @param panel
     * @param caption
     */
    public static void setCaption(final JPanel panel, final String caption) {
        if (panel == null)
            return;
        final Border border = panel.getBorder();
        Runnable runner = new Runnable() {
            public void run() {
                if (border != null) {
                    if (border instanceof TitledBorder) {
                        ((TitledBorder) border).setTitle(caption);
                    }
                    else {
                        panel.setBorder(BorderFactory.createTitledBorder(border, caption, TitledBorder.LEFT, TitledBorder.TOP));
                    }

                }
                else {
                    panel.setBorder(BorderFactory.createTitledBorder(caption));
                }
            }
        };
        if (SwingUtilities.isEventDispatchThread()) {
            runner.run();
        }
        else {
            try {
                SwingUtilities.invokeAndWait(runner);
            }
            catch (InterruptedException e) {
                CancelException errorVar = new CancelException(e);
                ErrorMgr.addError(errorVar);
                throw errorVar;
            }
            catch (InvocationTargetException e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * Returns the caption of a JPanel, emulating a Forte Panel, as a String
     *
     * @param panel
     * @return
     */
    public static String getCaption(JPanel panel) {
        if (panel == null)
            return "";
        Border border = panel.getBorder();
        if ((border != null) && (border instanceof TitledBorder)) {
            return ((TitledBorder) border).getTitle();
        }
        else {
            return "";
        }

    }

    /**
     * get the caption from and array or listview
     *
     * @param panel
     * @return
     */
    public static String getCaption(JTable table) {
        if (table == null)
            return "";
        Border border = table.getBorder();
        if ((border != null) && (border instanceof TitledBorder)) {
            return ((TitledBorder) border).getTitle();
        }
        else {
            return "";
        }

    }

    public static Component getFieldByName(TextData pName, Component pWidget) {
        return getFieldByName(pName.toString(), pWidget);
    }

    /**
     * This method returns a specified child widget of a compound field. If the
     * widget is not found, it returns null.
     *
     * @param pName -
     *            the name of the child widget to be retrieved. For an array
     *            field, this is the name of a template field.
     * @param pRootPane -
     *            the widget at which to begin searching.
     * @return
     */
    public static Component getFieldByName(String pName, Component pWidget) {
        // First, translate the forte name into a java type name. We prefix with "qq_",
        // replace any "." with "_" and if we come across [*] we strip it and terminate
        // the name here.
        // TF:8/11/07:Most of the time names no longer are prefixed with "qq_" as this
        // stops some customers' searches working. However, to maintain compatibility
        // with older code (which are prefixed with qq_) we need to check both.
        UIutils.processGUIActions();
        if (pName == null || pName.length()==0) return null; //PM:7 oct. 2008:performance
        StringBuilder newName = new StringBuilder();
        newName.append(pName);
        int index = newName.indexOf(".");
        while (index >= 0) {
            newName.replace(index, index + 1, "_");
            index = newName.indexOf(".");
        }
        index = newName.indexOf("[*]");
        if (index >= 0) {
//            newName.setLength(index);
            newName.delete(0, index + 4);
        }
        Component result;
        if (pWidget instanceof MenuElement) {
            result = UIutils._getMenuByName(newName.toString(),
                    (MenuElement) pWidget, 0);
            if (result == null) {
                newName.insert(0, "qq_");
                result = UIutils._getMenuByName(newName.toString(),
                        (MenuElement) pWidget, 0);
            }
        } else {
            result = UIutils._getFieldByName(newName.toString(), pWidget);
            if (result == null) {
                newName.insert(0, "qq_");
                result = UIutils._getFieldByName(newName.toString(), pWidget);
            }
        }
        return result;
    }

    /**
     * _getFieldByName: private method used by getFieldByName to recurse down a
     * component hierarchy to see if the widget with the given name exists in
     * the hierarchy.
     *
     * @param pName -
     *            the name of the widget
     * @param pWidget -
     *            the current widget under test
     * @return the widget that is a descendent of the passed widget with the
     *         passed name, or null if none can be found to satisfy this
     *         criteria
     */
    private static Component _getFieldByName(String pName, Component pWidget) {
        Component targetWidget = pWidget;
        if (pName == null || targetWidget == null) {
            return null;
        }
        if (targetWidget instanceof JFrame) {
            targetWidget = getForm((JFrame) targetWidget);
        }
        // UIutils.processGUIActions();

        String name = targetWidget.getName();

        if (name != null && (pName.equalsIgnoreCase(name) || pName.substring(3).equalsIgnoreCase(name))) { // extra
            return targetWidget;
        }
        if (targetWidget instanceof ArrayField) {
            ArrayField aContainer = (ArrayField) targetWidget;
            ArrayColumnModel acm = (ArrayColumnModel)aContainer.getColumnModel();
            int colCount = acm.getRealColumnCount();
            for (int i = 0; i < colCount; i++) {
                ArrayColumn ac = (ArrayColumn)acm.getRealColumn(i);
                TableCellEditor tce = ac.getCellEditor();
                JComponent comp = (JComponent)tce.getTableCellEditorComponent(aContainer, null, true, -1, -1);
                if (comp == null) { // then find the cell renderer
                    ArrayFieldCellRenderer afcr = (ArrayFieldCellRenderer) ac
                            .getCellRenderer();
                    comp = (JComponent) afcr.getTableCellRendererComponent(
                            aContainer, null, false, true, -1, -1);
                    comp = (JComponent) comp.getComponent(0);
                    String compName = (comp == null) ? "" : comp.getName();
                    if (compName.endsWith(pName)) {
                        return comp;
                    }
                } else if (comp instanceof EditorLayoutPanel
                        && comp.getComponent(0) != null) {
                    comp = (JComponent) comp.getComponent(0);
                }
                String compName = (comp == null) ? "" : comp.getName();
                if (compName.endsWith(pName)) {
                    return comp;
                }
            }
        } else if (targetWidget instanceof Container) {
            Container aContainer = (Container) targetWidget;
            Component[] children = aContainer.getComponents();
            for (int i = 0; i < children.length; i++) {
                Component result = UIutils._getFieldByName(pName, children[i]);
                if (result != null) {
                    return result;
                }
            }
        }
        return null;
    }

    /**
     * _getMenuByName: private method used by getFieldByName to recurse down a
     * menu hierarchy to see if the widget with the given name exists in the
     * hierarchy.
     *
     * @param pName -
     *            the name of the widget
     * @param pWidget -
     *            the current widget under test
     * @return the widget that is a descendent of the passed widget with the
     *         passed name, or null if none can be found to satisfy this
     *         criteria
     */
    private static Component _getMenuByName(String pName, MenuElement pWidget,
            int indent) {
        // TF:8/11/07:Optimised this method
        Component targetWidget = (Component) pWidget;
        if (pName == null || targetWidget == null) {
            return null;
        }
        // UIutils.processGUIActions();

        String name = targetWidget.getName();
        if (_log.isDebugEnabled()) {
            StringBuilder pad = new StringBuilder(64);//PM:7 oct. 2008:changed to StringBuilder
            for (int x = 0; x < indent; x++)
                pad.append(" ");
            indent++;
            pad.append(name).append(":").append(pName);
            _log.debug(pad.toString());
        }
        if (name != null
                && (pName.endsWith(name) || pName.substring(3).endsWith(name)))
            return targetWidget;

        // TF:8/11/07:Changed this method to recurse a menu hierarchy instead of
        // a component hierarchy
        for (MenuElement me : pWidget.getSubElements()) {
            Component result = UIutils._getMenuByName(pName, me, indent);
            if (result != null) {
                return result;
            }
        }
        // if (targetWidget instanceof Container) {
        // Container aContainer = (Container) targetWidget;
        // Component[] children = aContainer.getComponents();
        // for (int i = 0; i < children.length; i++) {
        // Component result = UIutils._getMenuByName(pName, children[i],
        // indent);
        // if (result != null) {
        // return result;
        // }
        // }
        // }
        return null;
    }

    public static Component getFieldByName1(String pName, Component pWidget) {
        int firstDotIndex = pName.indexOf('.');
        // String nameToFind = pName;
        String widgetName = pWidget.getName();
        if (widgetName == null || (widgetName.length() >= 3 && widgetName.substring(0, 3).equals("qq_"))) {
            // This widget was unnamed in Forte so cannot take part in the name
            // chain
            // we'll just traverse our children looking
            if (pWidget instanceof Container) {
                Container aContainer = (Container) pWidget;
                Component[] children = aContainer.getComponents();
                for (int i = 0; i < children.length; i++) {
                    Component result = UIutils.getFieldByName(pName,
                            children[i]);
                    if (result != null) {
                        return result;
                    }
                }
            }
            return null;
        } else if (pWidget instanceof JFrame) {
            // ------------------------------------------------------------------------
            // We've been passed the actual window, we need to look at all our
            // children
            // ------------------------------------------------------------------------
                Container aContainer = (Container) pWidget;
                Component[] children = aContainer.getComponents();
                for (int i = 0; i < children.length; i++) {
                    Component result = UIutils.getFieldByName(pName, children[i]);
                    if (result != null) {
                        return result;
                    }
                }
        } else if (widgetName.equalsIgnoreCase(pName)) {
            // -------------------------------------------------------------------------------------
            // This is the exact widget, even if it contains a dot, like
            // "R_MortgageNew.eCCCPurpose"
            // -------------------------------------------------------------------------------------
            return pWidget;
        }
        else {
            // This is a widget with a name so must exist in the name chain
            if (firstDotIndex >= 0) {
                String firstPart = pName.substring(0, firstDotIndex);

                // Drop off the dot between the last section and this section
                String trailingPart = pName.substring(firstDotIndex + 1);

                // See if we are in an array list (should have [*] in the name)
                boolean isInArrayList = false;
                if (firstPart.indexOf("[*]") >= 0) {
                    // This must be the last 3 characters in the string
                    firstPart = firstPart.substring(0, firstPart.length() - 3);
                    isInArrayList = true;
                    // At the moment, we don't need this attribute, as columns
                    // in a JTable have
                    // no equivalent in java. Thus, we'll just return the
                    // JTable.
                }

                if (widgetName.equalsIgnoreCase(firstPart)) {
                    if (isInArrayList) {
                        return pWidget;
                    }

                    // This is the actual widget, and we must be a container
                    Container aContainer = (Container) pWidget;
                    Component[] children = aContainer.getComponents();
                    for (int i = 0; i < children.length; i++) {
                        Component result = UIutils.getFieldByName(trailingPart, children[i]);
                        if (result != null) {
                            return result;
                        }
                    }
                }
                else {
                    return null;
                }
            }
            else {
                // See if this is looking for us
                if (widgetName.equalsIgnoreCase(pName)) {
                    return pWidget;
                }
                else {
                    return null;
                }
            }
        }
        return null;
    }

    /**
     * Provides the inner width in mils of the component passed in
     *
     * @param comp -
     *            JComponent
     * @return int - inner width in mils
     */
    public static int getInnerWidthInMils(Component comp) {
        Insets ins = ((JComponent) comp).getInsets();
        int innerWidth = Width.get(comp, false) - ins.left - ins.right;
        return pixelsToMils(innerWidth);
    }

    /**
     * Provides the inner width in mils of the JFrame passed in
     *
     * @param comp
     * @return
     */
    public static int getInnerWidthInMils(JFrame comp) {
        Insets ins = comp.getInsets();
        int innerWidth = comp.getWidth() - ins.left - ins.right;
        return pixelsToMils(innerWidth);
    }

    /**
     * Provides the inner height in mils of the component passed in
     *
     * @param comp -
     *            JComponent
     * @return int - inner height in mils
     */
    public static int getInnerHeightInMils(JComponent comp) {
        Insets ins = comp.getInsets();
        // Border bdr = comp.getBorder();
        int innerHeight = 0;
        innerHeight = Height.get(comp, false) - ins.top - ins.bottom;
        return pixelsToMils(innerHeight);
    }

    public static int getInnerHeightInMils(Container comp) {
        Insets ins = comp.getInsets();
        int innerHeight = 0;
        innerHeight = comp.getHeight() - ins.top - ins.bottom;
        return pixelsToMils(innerHeight);
    }

    public static class SelectAllAction extends TextAction {

        /**
         *
         */
        private static final long serialVersionUID = 4323798519981286912L;

        /**
         * Create this action with the appropriate identifier.
         *
         * @param nm
         *            the name of the action, Action.NAME.
         * @param select
         *            whether to extend the selection when changing the caret
         *            position.
         */
        public SelectAllAction() {
            super(DefaultEditorKit.selectAllAction);
        }

        /** The operation to perform when this action is triggered. */
        public void actionPerformed(ActionEvent e) {
            JTextComponent target = getTextComponent(e);
            if (target != null) {
                Document doc = target.getDocument();
                target.setCaretPosition(0);
                target.moveCaretPosition(doc.getLength());
            }
        }
    }
   
    /**
     * @param comp
     * @return the current window usage state this component is in.
     *
     * CraigM: 24/04/2008.
     */
    public static int getWindowUsage(JComponent comp) {
        try {
          JFrame frame = UIutils.getWindowForComponent(comp);

          if (frame == null) {
              return Constants.FS_UPDATE;
          }
          return UIutils.getWindowUsage((JFrame)frame);
        }
        catch (InvocationTargetException e) {
            UsageException errorVar = new UsageException("getWindowUsage() cannot locate the usage table, check that this JFrame was generated from jcTOOL", e);
            ErrorMgr.addError(errorVar);
            throw errorVar;
        }
        catch (NoSuchMethodException e) {
            UsageException errorVar = new UsageException("getWindowUsage() cannot locate the usage table, check that this JFrame was generated from jcTOOL", e);
            ErrorMgr.addError(errorVar);
            throw errorVar;
        }
        catch (Throwable e) {
            UsageException errorVar = new UsageException("getWindowUsage() failure", e);
            ErrorMgr.addError(errorVar);
            throw errorVar;
        }
    }

    /**
     * @param window
     * @return the current usage state for the window.
     *
     * CraigM: 24/04/2008.
     * @throws NoSuchMethodException
     * @throws SecurityException
     * @throws InvocationTargetException
     * @throws IllegalAccessException
     * @throws IllegalArgumentException
     */
    public static int getWindowUsage(JFrame window) throws
                      SecurityException,
                      NoSuchMethodException,
                      IllegalArgumentException,
                      IllegalAccessException,
                      InvocationTargetException {
    Method currUsageMethod = window.getClass().getMethod("getUsage", (Class[]) null);
        return ((Integer)currUsageMethod.invoke(window, (Object[]) null)).intValue();
    }

    public static void setBackground(Component pComponent, Color pColour) {
        ColourChange.setBackground(pComponent, pColour);
    }

    /**
     * sets the foreground colour of a component using the EDT
     *
     * @param pComponent
     * @param pColour
     */
    public static void setForeground(Component pComponent, Color pColour) {
        ColourChange.setForeground(pComponent, pColour);
    }

    private static void _setWidthPartnership(JComponent[] pComponents) {
        // This method MUST be called from the GUI thread!
        int width = 0;
        for (int i = 0; i < pComponents.length; i++) {
            JComponent thisComp = pComponents[i];
            JComponent[] property = (JComponent[]) thisComp.getClientProperty("widthPartnership");
            if (property == null) {
                thisComp.putClientProperty("widthPartnership", pComponents);
            }
            if (thisComp.getWidth() > width) {
                width = thisComp.getWidth();
            }
        }
        for (int i = 0; i < pComponents.length; i++) {
            JComponent thisComp = pComponents[i];
            Dimension d = new Dimension(width, thisComp.getHeight());
            if (thisComp.getWidth() != width) {
                thisComp.setSize(d);
                thisComp.setMinimumSize(d);
                thisComp.setPreferredSize(d);
            }
        }
    }

    /**
     * sets the width partnership on a set of components. All components width's
     * will be made as lard as the largest component
     *
     * @param pComponents
     */
    public static void setWidthPartnership(final JComponent[] pComponents) {
        try {
            SwingUtilities.invokeAndWait(new Runnable() {
                public void run() {
                    UIutils._setWidthPartnership(pComponents);
                }
            });
        }
        catch (Exception e) {
            _log.error("Unhandled exception in setWidthPartnership", e);
        }
        for (int i = 0; i < pComponents.length; i++) {
            final JComponent thisComp = pComponents[i];
            thisComp.addComponentListener(new ComponentAdapter() {
                public void componentResized(ComponentEvent e) {
                    JComponent[] property = (JComponent[]) thisComp.getClientProperty("widthPartnership");
                    if (property != null) {
                        UIutils._setWidthPartnership(property);
                    }
                }
            });
        }
    }

    /**
     * The GetColumnCoordinates method returns the coordinates of the rectangle
     * around a column within an array field.
     *
     * @param table -
     *            the subject
     * @param column -
     *            You use GetColumnCoordinates to get the specific coordinates,
     *            relative to the ArrayField, of the rectangle that surrounds
     *            the column specified with the column parameter. The column
     *            parameter is given as the number of the column within the
     *            ArrayField, numbered from 1 as the first column on the left.
     * @param xLeft
     * @param yTop
     * @param xRight
     * @param yBottom
     *            This returns the coordinates in the four output parameters
     *            xLeft, yTop, xRight, yBottom. These are measured in mils,
     *            relative to the top left corner of the ArrayField, without any
     *            enclosing frame (it is the inner corner). The column is
     *            considered to contain the cells containing the data only, and
     *            does not include the column header.
     * @return This returns a value of TRUE always.
     *
     *
     */
    public static boolean getColumnCoordinates(JTable table, int column, ParameterHolder xLeft, ParameterHolder yTop, ParameterHolder xRight,
            ParameterHolder yBottom) {
        boolean vis = true;
        // int rows = 0;
        int left = 0;
        int top = 0;
        for (int col = 0; col < (column - 1); col++) {
            left += table.getColumnModel().getColumn(1).getWidth();
        }
        int right = table.getColumnModel().getColumn(column - 1).getWidth() + left;
        int bottom = 0;
        if (table.getParent() instanceof JViewport) {
            JViewport sp = (JViewport) table.getParent();
            bottom = sp.getHeight();
        }
        else {
            bottom = table.getHeight();
        }
        if (table.getTableHeader() != null) {
            bottom -= table.getTableHeader().getHeight();
            top += table.getTableHeader().getHeight();
        }
        xLeft.setInt(UIutils.pixelsToMils(left));
        yTop.setInt(UIutils.pixelsToMils(top));
        xRight.setInt(UIutils.pixelsToMils(right));
        yBottom.setInt(UIutils.pixelsToMils(bottom));
        return vis;
    }

    /**
     * The GetRowCoordinates method returns the coordinates of the rectangle
     * around a row within an array field
     *
     * @param table
     * @param row -
     *            You use GetRowCoordinates to get the specific coordinates,
     *            relative to the ArrayField, of the rectangle that surrounds
     *            the row specified with the row parameter. The row parameter is
     *            given as the number of the row within the data associated with
     *            the ArrayField, numbered from 1 as the first row in the array.
     * @param xLeft
     * @param yTop
     * @param xRight
     * @param yBottom
     *            This returns the coordinates in the four output parameters
     *            xLeft, yTop, xRight, yBottom. These are measured in mils,
     *            relative to the top left corner of the ArrayField, without any
     *            enclosing frame (it is the inner corner). The row is
     *            considered to contain the cells containing the data, without
     *            any separator lines associated with the row.
     * @return
     */
    public static boolean getRowCoordinates(JTable table, int row, ParameterHolder xLeft, ParameterHolder yTop, ParameterHolder xRight,
            ParameterHolder yBottom) {
        boolean vis = true;
        ArrayColumnModel cm = (ArrayColumnModel) table.getColumnModel();
        Enumeration<TableColumn> cols = cm.getColumns();
        int width = 0;
        while (cols.hasMoreElements()) {
            width += ((ArrayColumn) cols.nextElement()).getWidth();
        }
        Rectangle top = table.getCellRect(row - 1, 0, true);
        xLeft.setInt(UIutils.pixelsToMils(top.x));
        yTop.setInt(UIutils.pixelsToMils(top.y));
        xRight.setInt(UIutils.pixelsToMils(top.x + width));
        yBottom.setInt(UIutils.pixelsToMils(top.height + top.y));
        return vis;
    }

    /**
     * sets the elements in a ListField
     *
     * @param comp
     * @param les
     * @deprecated
     */
    public static void setElementList(ListField comp, Array_Of_ListElement<ListElement> les) {
        ElementList.set(comp, les);
    }

    /**
     * sets the elements in a FillInField or DropList (both are emulated using a
     * AutoResizingComboBox)
     *
     * AD:26/6/2008 Change JComboBox to AutoResizingComboBox to reduce casting later
     * @param comp
     * @param les
     */
    public static void setElementList(AutoResizingComboBox comp, Array_Of_ListElement<ListElement> les) {
        ElementList.set(comp, les);
    }

    /**
     * sets the elements in a ScrollList (JList)
     *
     * @param comp
     * @param les
     *
     */
    public static void setElementList(JList comp, Array_Of_ListElement<ListElement> les) {
        ElementList.setOnJList(comp, les);

    }

    /**
     * Returns an Array_Of_ListElement containing the elements from a AutoResizingComboBox
     * emulating a FOrte DropList or FillInField
     *
     * AD:26/6/2008 Change JComboBox to AutoResizingComboBox to reduce casting later
     * @param comp
     * @return
     */
    public static Array_Of_ListElement<ListElement> getElementList(AutoResizingComboBox comp) {
        return ElementList.get(comp);
    }

    /**
     * Returns an Array_Of_ListElement containin the elements from a ListField
     *
     * @param comp
     * @return
     */
    public static Array_Of_ListElement<ListElement> getElementList(ListField comp) {
        if (comp instanceof AutoResizingComboBox)
            return ElementList.get((AutoResizingComboBox) comp);
        else if (comp instanceof RadioList)
            return ElementList.get((RadioList) comp);
        else if (comp instanceof JList)
            return ElementList.get((JList) comp);
        else
            return null;
    }

    /**
     * Returns an Array_Of_ListElement containing the elements from a JList
     * emulating a Forte ScrollList
     *
     * @param comp
     * @return
     */
    public static Array_Of_ListElement<ListElement> getElementList(JList comp) {
        return ElementList.get(comp);
    }

    /**
     * Returns an Array_Of_ListElement containing the elements from a JList
     * emulating a Forte RadiolList
     *
     * @param comp
     * @return
     */
    public static Array_Of_ListElement<ListElement> getElementList(RadioList comp) {
        return ElementList.get(comp);
    }

    /**
     * The ExtractListElement method clones the specified list element from a
     * list field�s element list, returning the clone as a ListElement object.
     *
     * @param comp -
     *            the target component
     * @param value -
     *            ExtractListElement uses the type of the value parameter to
     *            specify the list element it should clone. You can specify that
     *            the method search an element list by any list element
     *            attribute. ExtractListElement searches the list until it finds
     *            the match specified by the value parameter, and returns only
     *            the first match.
     * @return ListElement
     */
    public static ListElement extractListElement(ListField comp, Object value) {
        ListElement le = null;
        Array_Of_ListElement<ListElement> les = getElementList(comp);
        for (ListElement local : les) {
            if (local.getObjectValue() != null && local.getObjectValue().equals(value)) {
                // TF:27/8/07:Made a clone of the result as this is what Forte did.
                le = CloneHelper.clone(local, false);
                break;
            }
        }
        return le;
    }

    /**
     * Extracts a ListElement from the JList emulating a Forte ScrollList
     *
     * @param comp -
     *            the target component
     * @param value -
     *            the TextValue of the ListElement, as a TextData
     * @return
     */
    public static ListElement extractListElement(ListField comp, TextData value) {
      return extractListElement(comp, value.getValue());
    }
   
    /**
     * Extracts a ListElement from the ListField by searching it's elements for the first one
     * that has the passed value as it's TextValue and returning this element.
     *
     * @param comp -
     *            the target component
     * @param value -
     *            the TextValue of the ListElement
     * @return
     */
    public static ListElement extractListElement(ListField comp, String value) {
      ListElement le = null;
      Array_Of_ListElement<ListElement> les = getElementList(comp);
      for (ListElement local : les) {
        if (local.getTextValue() != null && local.getTextValue().isEqual(value).getValue()) {
          // TF:27/8/07:Made a clone of the result as this is what Forte did.
          le = CloneHelper.clone(local, false);
          break;
        }
      }
      return le;
    }
   
    /**
     * Extracts a ListElement from the JList emulating a Forte ScrollList
     *
     * @param comp -
     *            the target component
     * @param value -
     *            the IntegerValue of the ListElement
     * @return
     */
    public static ListElement extractListElement(ListField comp, int value) {
        ListElement le = null;
        Array_Of_ListElement<ListElement> les = getElementList(comp);
        for (ListElement local : les) {
            if (local.getIntegerValue() == value) {
                // TF:27/8/07:Made a clone of the result as this is what Forte did.
                le = CloneHelper.clone(local, false);
                break;
            }
        }
        return le;
    }

    /**
     * Sets the column of a widged based from 1
     *
     * @param comp
     * @param value
     */
    public static void setColumn(JComponent comp, int value) {
        Column.set(comp, value);

    }

    /**
     * Sets the row of a widged based from 1
     *
     * @param comp
     * @param value
     */
    public static void setRow(JComponent comp, int value) {
        Row.set(comp, value);
    }

    /**
     * sets the parent of a widget
     *
     * @param comp
     * @param parent
     */
    public static void setParent(JComponent comp, JComponent parent) {
        Parent.set(comp, parent);

    }

    /**
     * Returns the column of a widget, based from 1
     *
     * @param comp
     * @return
     */
    public static int getColumn(JComponent comp) {
        return Column.get(comp);
    }

    /**
     * Returns the Row of a Widget, based from 1
     *
     * @param comp
     * @return
     */
    public static int getRow(JComponent comp) {
        return Row.get(comp);
    }

    /**
     * Returns the Parent of a Widget
     *
     * @param comp
     * @return
     */
    public static Component getParent(JComponent comp) {
        return Parent.get(comp);
    }

    /**
     * sets the TextValue of a component
     *
     * @param comp
     * @param value
     */
    public static void setTextValue(JTextComponent comp, String value) {
        setTextValue(comp, new TextData(value));
    }

    public static void setTextValue(ListField comp, String value) {
        setTextValue(comp, new TextData(value));
    }

    /**
     * sets the TextValue of a component
     *
     * @deprecated
     * @param comp
     * @param value
     */
    public static void setTextValue(JTextComponent comp, TextData value) {
        TextValue.set(comp, value);
    }

    /**
     * @deprecated
     * @param comp
     * @param value
     */
    public static void setTextValue(ListField comp, TextData value) {
        TextValue.set(comp, value);
    }

    /**
     * Returns the text value of the component
     *
     * @param comp
     * @return
     * @deprecated
     */
    public static TextData getTextValue(JTextComponent comp) {
        return TextValue.get(comp);
    }

    /**
     * @deprecated
     */
    public static TextData getTextValue(ListField comp) {
        return TextValue.get(comp);
    }

    /**
     * sets the IntegerValue of AutoResizingComboBox emulating a Forte DropList or
     * FillInField
     *
     * @param comp
     * @return
     * @deprecated
     */
    public static void setIntegerValue(Component comp, int value) {
        if (comp instanceof ListField)
            IntegerValue.set((ListField) comp, value);

    }

    /**
     * sets the IntegerValue of ListField
     *
     * @param comp
     * @return
     * @deprecated
     */
    public static void setIntegerValue(ListField comp, int value) {
        IntegerValue.set(comp, value);
    }

    /**
     * Returns the IntegerValue of AutoResizingComboBox emulating a Forte DropList or
     * FillInField
     *
     * @param comp
     * @return
     * @deprecated
     */
    public static int getIntegerValue(JComponent comp) {
        return IntegerValue.get((ListField) comp);
    }

    /**
     * set ObjectValue on lists
     *
     * @author Peter
     */

    public static void setObjectValue(Component comp, Object value) {
        ObjectValue.set(comp, value);
    }

    /**
     * Returns the ObjectValue of a AutoResizingComboBox emulating a Forte DropList or
     * FillInField
     *
     * @param comp
     * @return
     */
    public static Object getObjectValue(JComponent comp) {
        return ObjectValue.get(comp);
    }

    // set BooleanValue on Toggles
    /**
     * @author Peter
     */

    public static void setBooleanValue(Component comp, boolean value) {
        BooleanValue.set(comp, value);
    }

    /**
     * Gets the BooleanValue of JCheckBox emulating a Forte ToggleField
     *
     * @param comp -
     *            target component
     * @return
     */
    public static boolean getBooleanValue(JComponent comp) {
        return BooleanValue.get(comp);
    }

    /**
     * getDisplayState() provides translation of the Frame's extended state to
     * the Forte display state.
     *
     * Frame.NORMAL = DS_NORMAL Frame.ICONIFIED = DS_ICONIZED
     * Frame.MAXIMIZED_HORIZ = DS_ALTERNATE Frame.MAXIMIZED_VERT = DS_ALTERNATE
     * Frame.MAXIMIZED_BOTH = DS_ALTERNATE default value is DS_UNKNOWN;
     *
     * @param frame
     * @return
     */
    public static int getDisplayState(Frame frame) {
        return WindowDisplayState.get(frame);
    }

    /**
     * setDisplayState() provides translation of the Frame's extended state to
     * the Forte display state.
     *
     * Frame.NORMAL = DS_NORMAL Frame.ICONIFIED = DS_ICONIZED
     * Frame.MAXIMIZED_HORIZ = DS_ALTERNATE Frame.MAXIMIZED_VERT = DS_ALTERNATE
     * Frame.MAXIMIZED_BOTH = DS_ALTERNATE default value is DS_UNKNOWN;
     *
     * @param frame
     * @param DisplayState
     */
    public static void setDisplayState(Frame frame, int DisplayState) {
        WindowDisplayState.set(frame, DisplayState);
    }

    /**
     * this emulates the request finalize method in forte by posting the
     * AfterFinalize event on the window
     *
     * @param win
     */
    public static void requestFinalize(JFrame win) {
        requestFinalize(win, 0);
    }

    /**
     * this emulates the request finalize method in forte by posting the
     * AfterFinalize event on the window
     *
     * @param win
     * @param reasonCode
     */
    public static void requestFinalize(JFrame win, int reasonCode) {
      // CraigM:22/04/2008:Don't do a glass pane check.
        FocusHelper.requestFinalizeNoCheck(win, reasonCode);
    }

    public static void requestFinalize(JFrame win, String evt) {
        ClientEventManager.postEvent(win, evt);
    }

    public static void requestFinalize(JFrame win, EventHandle evt) {
      // TF:24/04/2008: Changed this to use the client event manager to get the right order for events
        ClientEventManager.postEvent(evt);
    }

    /**
     * inserts a node into a parent. This is usually used for building a tree of
     * DisplayNodes and informing the mapped TreeView (JTree) of the change.
     *
     * @param comp
     * @param pParent
     * @param pChild
     * @param index
     */
    public static void nodeInserted(Component comp, DisplayNode pParent, DisplayNode pChild, int index) {
        // UIutils.addAction(new NodeInserted(comp, pParent, pChild, index));
        new NodeInsert(comp, pParent, pChild, index).performAction();
    }

    /**
     * this is used to notify the TreeView (JTree) that a DisplayNode has been
     * removed
     *
     * @param comp
     * @param pChild
     */
    public static void nodeRemoved(Component comp, DisplayNode pChild) {
        new NodeRemoved(comp, pChild).performAction();
    }

    private static class NodeRemoved extends PendingAction {
        private DisplayNode kid;

        public NodeRemoved(Component pComponent, DisplayNode pChild) {
            super(pComponent);
            this.kid = pChild;
        }

        @SuppressWarnings("unused")
        public DisplayNode getChild() {
            return this.kid;
        }

        @SuppressWarnings("deprecation")
    public void performAction() {
            if (this._component instanceof OutlineField) {
                ((OutlineField)this._component).getModel().removeNodeFromParent(kid);
            }
            else if (this._component instanceof JTree) {
                DefaultTreeModel tm = ((TreeViewModel) ((JTree) this._component).getModel());
                if (kid.getParent() != null)
                    tm.removeNodeFromParent(kid);
            }
            else if (this._component instanceof JTable) {

            }
            else if (this._component instanceof JListView) {

            }
            else if (this._component instanceof ListView) {
                ((ListView) this._component).removeNode(this.kid);
            }
        }
    }

    /**
     * Reload the text of the underlying widget if the message set or
     * the message number has been set.
     * @param comp
     */
    private static void reloadTextIfNecessary(JComponent comp) {
      // TF:22/04/2008:Check to see if we need to alter the text of the passed
      // widget based on the message catalog
      // TF:Mar 8, 2010:Re-used methods to reduce dependency on hard-coded strings
      int msgNum = getMsgNumber(comp);
      int msgSet = getMsgSet(comp);
      if (msgNum > 0 && msgSet > 0) {
        MsgCatalog catalog = MsgCatalog.getInstance();
        if (catalog != null) {
          if (comp instanceof JTextComponent) {
            TextData value = TextValue.get((JTextComponent)comp);
            String text = catalog.getString(msgSet, msgNum, value == null ? null : value.toString());
            TextValue.set((JTextComponent)comp, text);
          }
          else if (comp instanceof JLabel) {
            TextData value = TextValue.get((JLabel)comp);
            String text = catalog.getString(msgSet, msgNum, value == null ? null : value.toString());
            TextValue.set((JLabel)comp, text);
          }
          else if (comp instanceof JMenuItem) {
            TextData value = MenuText.get((JMenuItem)comp);
            String text = catalog.getString(msgSet, msgNum, value == null ? null : value.toString());
            MenuText.set((JMenuItem)comp, text);
          }
          else if (comp instanceof JButton) {
            TextData value = TextValue.get((JButton)comp);
            String text = catalog.getString(msgSet, msgNum, value == null ? null : value.toString());
            TextValue.set((JButton)comp, text);
          }
          //PM:24/4/08 added support for Panel and GridField
          else if (comp instanceof Panel) {
            TextData value = Caption.get((Panel)comp);
            String text = catalog.getString(msgSet, msgNum, value == null ? null : value.toString());
            Caption.set((Panel)comp, text);
          }
          else if (comp instanceof GridField) {
            TextData value = Caption.get((GridField)comp);
            String text = catalog.getString(msgSet, msgNum, value == null ? null : value.toString());
            Caption.set((GridField)comp, text);
          }
          // CraigM:28/04/2008: Added support for check boxes
          else if (comp instanceof JCheckBox) {
            String value = ((JCheckBox)comp).getText();
            String text = catalog.getString(msgSet, msgNum, value);
            ((JCheckBox)comp).setText(text);
          }
          // TF:26/06/2008:Added support for radio lists
          else if (comp instanceof JCheckBox) {
            String value = ((JCheckBox)comp).getText();
            String text = catalog.getString(msgSet, msgNum, value);
            ((JCheckBox)comp).setText(text);
          }
        }
      }
        //PM:2/5/08
        /*
         * Added support for Floatover text in the message catalog
         */
        Integer floatOverMsgNum = (Integer)comp.getClientProperty("qq_FloatOverMsgNum");
        Integer floatOverMsgSet = (Integer)comp.getClientProperty("qq_FloatOverSetNum");
        if (floatOverMsgNum != null && floatOverMsgSet != null && floatOverMsgNum.intValue() != 0 && floatOverMsgSet != 0) {
          String text = MsgCatalog.getInstance().getString(floatOverMsgSet, floatOverMsgNum.intValue());
          FloatOverText.set(comp, text);
        }
    }
   
    /**
     * sets the title set on a given window
     *
     * @param comp
     * @param msgSet
     */
    public static void reloadTitle(JFrame frame, int titleSet, int titleNum) {
      if (titleSet != 0 && titleNum != 0) {
        MsgCatalog catalog = MsgCatalog.getInstance();
        if (catalog != null) {
          String value = frame.getTitle();
          String text = catalog.getString(titleSet, titleNum, value);
          frame.setTitle(text);
        }
      }
    }
   
    /**
     * sets the float over help message number on a component
     * @param comp
     * @param msgNumber
     */
    public static void setFloatOverMsgNumber(JComponent comp, int msgNumber) {
        comp.putClientProperty("qq_FloatOverMsgNum", new Integer(msgNumber));
        reloadTextIfNecessary(comp);
    }
    /**
     * sets the float over help set number on a component
     * @param comp
     * @param msgNumber
     */
    public static void setFloatOverSetNumber(JComponent comp, int setNumber) {
        comp.putClientProperty("qq_FloatOverSetNum", new Integer(setNumber));
        reloadTextIfNecessary(comp);
    }
    /**
     * sets both the float over help set and msg number on a component
     * @param comp
     * @param msgNumber
     * @param setNumber
     */
    public static void setFloatOverMsgAndSetNumber(JComponent comp, int msgNumber, int setNumber) {
        comp.putClientProperty("qq_FloatOverSetNum", new Integer(setNumber));
        comp.putClientProperty("qq_FloatOverMsgNum", new Integer(msgNumber));
        reloadTextIfNecessary(comp);
    }

    /**
     * sets the message set on a given component
     *
     * @param comp
     * @param msgSet
     */
    public static void setMsgSet(JComponent comp, int msgSet) {
        comp.putClientProperty("qq_msgSet", new Integer(msgSet));
        reloadTextIfNecessary(comp);
    }

    /**
     * sets the message number on a given component
     *
     * @param comp
     * @param msgNumber
     */
    public static void setMsgNumber(JComponent comp, int msgNumber) {
        comp.putClientProperty("qq_msgNumber", new Integer(msgNumber));
        reloadTextIfNecessary(comp);
    }

    /**
     * Retrieves the message set number from a component. Returns 0 if it does
     * not exist
     *
     * @param comp
     * @return int
     */
    public static int getMsgSet(JComponent comp) {
        Integer msgSet = (Integer) comp.getClientProperty("qq_msgSet");
        if (msgSet != null) {
            return msgSet.intValue();
        }
        else {
            return 0;
        }
    }

    /**
     * Retrieves the message set number from a menu. Returns 0 if it does not
     * exist
     *
     * @param comp
     * @return int
     */
    public static int getMsgSet(MenuElement comp) {
      int result = 0;
        if (comp instanceof JMenuItem) {
            JMenuItem jmi = (JMenuItem) comp;
            Integer msgSet = (Integer) jmi.getClientProperty("qq_msgSet");
            if (msgSet != null) {
                result = msgSet.intValue();
            }
        }
        return result;
    }

    /**
     * Retrieves the message number from a component Returns 0 if it does not
     * exist.
     *
     * @param comp
     * @return
     */
    public static int getMsgNumber(JComponent comp) {
        Integer msgNumber = (Integer) comp.getClientProperty("qq_msgNumber");
        if (msgNumber != null) {
            return msgNumber.intValue();
        }
        else {
            return 0;
        }
    }

    /**
     * Retrieves the message number from a Menu Returns 0 if it does not exist.
     *
     * @param comp
     * @return
     */
    public static int getMsgNumber(MenuElement comp) {
      int result = 0;
        if (comp instanceof JMenuItem) {
            JMenuItem jmi = (JMenuItem) comp;
            Integer msgNumber = (Integer) jmi.getClientProperty("qq_msgNumber");
            if (msgNumber != null) {
                result = msgNumber.intValue();
            }
        }
        return result;
    }

    /**
     * The ReloadLabelText method loads text from the specified message catalog
     * to replace the text in the widget and all child widgets. Use this method
     * to load the messages from the message file. Typically, you call
     * ReloadLabelText before invoking the Open method for a window.
     *
     * @param win
     */
    public static void reloadLabelText(JFrame win) {
        try {
            reloadLabelText(win, MsgCatalog.getInstance());
        }
        catch (MissingResourceException e) {
            // use defaults
        }
    }

    /**
     * The ReloadLabelText method loads text from the specified message catalog
     * to replace the text in the widget and all child widgets. If one set
     * number is used for all widgets on the window, you can simply invoke
     * ReloadLabelText on the Window object. Otherwise, you must invoke the
     * method on the individual child widgets. Use this method to load the
     * messages from the message file. Typically, you call ReloadLabelText
     * before invoking the Open method for a window.
     *
     * @param win
     * @param mcat
     */
    public static void reloadLabelText(final JFrame win, final MsgCatalog mcat) {
        int defaultSet = -1;
        if (win == null || mcat == null) {
            return;
        }
        Method gForm;
//        Method msgSet;
//        Method msgNumber;
        Field[] fields = null;
        JPanel form = null;
        try {
            gForm = win.getClass().getMethod("getForm", new Class[] {});
//            msgSet = win.getClass().getMethod("getqq_msgSet", new Class[] {});
//            msgNumber = win.getClass().getMethod("getqq_msgNumber", new Class[] {});
        }
        catch (SecurityException e) {
            return;
        }
        catch (NoSuchMethodException e) {
            return;
        }
        if (gForm == null) {
            return;
        }
        int mset, num;
        Expression expr;
        try {
            expr = new Expression(win, "getTitleSetNum", new Object[0]);
            expr.execute();
            mset = ((Integer) expr.getValue()).intValue();

            expr = new Expression(win, "getTitleMsgNum", new Object[0]); //$NON-NLS-1$
            expr.execute();
            num = ((Integer) expr.getValue()).intValue();

            expr = new Expression(win, "getSetNum", new Object[0]);
            expr.execute();
            defaultSet = ((Integer) expr.getValue()).intValue();

            expr = new Expression(win, "getForm", new Object[0]); //$NON-NLS-1$
            expr.execute();
            form = ((JPanel) expr.getValue());

            if ((mset < 1) && (defaultSet > 0)) {
                mset = defaultSet;
            }
            if ((mset > 0) && (num > 0)) {
                win.setTitle(mcat.getString(mset, num, win.getTitle()));
            }
            fields = win.getClass().getDeclaredFields();
        }
        catch (Exception e) {
            // do nothing
        }
        finally {
          // TF:Mar 9, 2010:Changed this to perform its actions on the EDT
          final int defSet = defaultSet;
          final JPanel theForm = form;
          final Field[] theFields = fields;
          ActionMgr.addAction(new PendingAction(null) {
            @Override
            public void performAction() {
                    JMenuBar jmb = (JMenuBar) win.getJMenuBar();
                    if (jmb != null) {
                        MenuElement[] kids = jmb.getSubElements();
                        for (int i = 0; i < kids.length; i++) {
                            if (kids[i] instanceof JMenuItem) {
                              // TF:Mar 8, 2010:Added in the default set parameter
                                reloadLabelText((JMenuItem) kids[i], mcat, defSet);
                            }
                            else if (kids[i] instanceof JPopupMenu) {
                              // TF:Mar 8, 2010:Added in the default set parameter
                                reloadLabelText((JPopupMenu) kids[i], mcat, defSet);
                            }
                        }
                    }
                    if (theForm != null) {
                        Component[] kids = theForm.getComponents();
                        for (int i = 0; i < kids.length; i++) {
                            if (kids[i] instanceof JComponent) {
                              // TF:Mar 8, 2010:Added in the default set parameter
                                reloadLabelText((JComponent) kids[i], mcat, defSet);
                            }
                        }
                    }
                    if (theFields != null) {
                        for (int f = 0; f < theFields.length; f++) {
                            try {
                                if ((theFields[f].get(win) != null) && (theFields[f].get(win) instanceof JPopupMenu)) {
                                  // TF:Mar 8, 2010:Added in the default set parameter
                                    reloadLabelText((JPopupMenu) theFields[f].get(win), mcat, defSet);
                                }
                            }
                            catch (IllegalArgumentException e) {
                                // do nothing
                            }
                            catch (IllegalAccessException e) {
                                // do nothing
                            }
                        }
                    }
            }
            @Override
            public String toString() {
              return "reloadLabelText(" + win + ", " + mcat + ")";
            }
          });
        }
    }

    /**
     * Return the default message set for the component. This is the message set for
     * the window to which the control is currently parented. If there is no default
     * set, then this method returns -1
     * @param comp
     * @return
     */
    public static int getDefaultMessageSet(JComponent comp) {
      // TF:Mar 2, 2010:Changed this to use the getSetNum method
        int defaultSet = -1;
        try {
            Expression expr = new Expression(comp.getRootPane().getParent(), "getSetNum", new Object[0]);
            expr.execute();
            defaultSet = ((Integer) expr.getValue()).intValue();
        }
        catch (Exception e) {
        }
        return defaultSet;
    }
   
    /**
     * The ReloadLabelText method loads text from the specified message catalog
     * to replace the text in the widget and all child widgets. Use this method
     * to load the messages from the message file. Typically, you call
     * ReloadLabelText before invoking the Open method for a window.
     *
     * @param comp
     * @param mcat
     */
  public static void reloadLabelText(JComponent comp, MsgCatalog mcat) {
        int defaultSet = getDefaultMessageSet(comp);
        reloadLabelText(comp, mcat, defaultSet);
    }
    /**
     * The ReloadLabelText method loads text from the specified message catalog
     * to replace the text in the widget and all child widgets. Use this method
     * to load the messages from the message file. Typically, you call
     * ReloadLabelText before invoking the Open method for a window.
     *
     * @param comp
     * @param mcat
     */
    @SuppressWarnings("deprecation")
  public static void reloadLabelText(final JComponent comp, final MsgCatalog mcat, final int defaultSet) {
        if (comp == null || mcat == null) {
            return;
        }
//        if (mcat == null) {
//            mcat = MsgCatalog.getInstance();
//        }
       
        // TF:Mar 9, 2010:Changed this to process it on the EDT
        ActionMgr.addAction(new PendingAction(null) {
      @Override
      public void performAction() {
          // TF:Mar 8, 2010:Re-used methods to reduce dependency on hard-coded strings
            int msgSet = getMsgSet(comp);
            int msgNumber = getMsgNumber(comp);
            if (msgSet <= 0 && defaultSet > 0) {
                msgSet = defaultSet;
            }

            // DropList
           // AD:26/6/2008 Change JComboBox to AutoResizingComboBox to reduce casting later
            if (comp instanceof AutoResizingComboBox) {
            Integer tvSet = (Integer) comp.getClientProperty("qq_TextValueSet");
            if ((tvSet == null) || (tvSet.intValue() < 1)) {
                tvSet = Integer.valueOf(defaultSet);
            }
            if (tvSet.intValue() < 1) {
                return;
            }
            AutoResizingComboBox rl = (AutoResizingComboBox) comp;
            for (int i = 0; i < rl.getItemCount(); i++) {
                ListElement le = (ListElement) rl.getItemAt(i);
                le.reloadLabelText(mcat, tvSet.intValue());
            }
            return;
        }
        // ScrollList
        if ((comp instanceof JList) && !(comp instanceof RadioList) && !(comp instanceof JListView)) {
            Integer tvSet = (Integer) comp.getClientProperty("qq_TextValueSet");
            if ((tvSet == null) || (tvSet.intValue() < 1)) {
                tvSet = Integer.valueOf(defaultSet);
            }
            if (tvSet.intValue() < 1) {
                return;
            }
            JList rl = (JList) comp;
            for (int i = 0; i < rl.getModel().getSize(); i++) {
                ListElement le = (ListElement) rl.getModel().getElementAt(i);
                le.reloadLabelText(mcat, tvSet.intValue());
            }
            return;
        }

            if (msgSet > 0 && msgNumber > 0) {
                if (comp instanceof JLabel) {
                    JLabel jl = (JLabel) comp;
                    jl.setText(mcat.getString(msgSet, msgNumber, jl.getText()));
                    labelWidth(jl);
                    return;
                }
                else if (comp instanceof JButton) {
                    JButton jb = (JButton) comp;
                    jb.setText(mcat.getString(msgSet, msgNumber, jb.getText()));
                    processMnemonic(jb);
                    packButton(jb);
                    return;
                }
                else if (comp instanceof JTabbedPane) {
                    JTabbedPane jtp = (JTabbedPane) comp;
                    for (int i = 0; i < jtp.getComponentCount(); i++) {
                        if (jtp.getComponentAt(i) instanceof JPanel) {
                            JPanel kid = (JPanel) jtp.getComponentAt(i);
                            int s = UIutils.getMsgSet(kid);
                            int n = UIutils.getMsgNumber(kid);
                            jtp.setTitleAt(i, mcat.getString(s, n, jtp.getTitleAt(i)));
                        }
                    }

                }
                else if (comp instanceof GridField) {
                    GridField gf = (GridField) comp;
                    TextData cap = gf.getCaption();
                    if (cap != null) {
                        gf.setCaption(new TextData(mcat.getString(msgSet, msgNumber, gf.getCaption().asString())));
                    }
                    else {
                        gf.setCaption(new TextData(mcat.getString(msgSet, msgNumber)));
                    }

                }
                else if (comp instanceof JPanel) {
                    JPanel gf = (JPanel) comp;
                    String cap = getCaption(gf);
                    if (cap != null) {
                      // TF:Mar 11, 2010:Changed this to use Caption.set instead of setCaption
//                        setCaption(gf, mcat.getString(msgSet, msgNumber, getCaption(gf)));
                        Caption.set(gf, mcat.getString(msgSet, msgNumber, getCaption(gf)));
                    }
                    else {
                      // TF:Mar 11, 2010:Changed this to use Caption.set instead of setCaption
//                      setCaption(gf, mcat.getString(msgSet, msgNumber));
                        Caption.set(gf, mcat.getString(msgSet, msgNumber));
                    }
                    if ((gf.getParent() != null) && (gf.getParent() instanceof JTabbedPane)) {
                        JTabbedPane jt = (JTabbedPane) comp.getParent();
                        int index = jt.indexOfComponent(comp);
                        if (index != -1) {
                            jt.setTitleAt(index, mcat.getString(msgSet, msgNumber, jt.getTitleAt(index)));
                        }
                    }

                }
                else if (comp instanceof JCheckBox) {
                    JCheckBox jtb = (JCheckBox) comp;
                    jtb.setText(mcat.getString(msgSet, msgNumber, jtb.getText()));
                    packCheck(jtb);
                }
                else {
                    _log.debug("UIutils.reloadLabelText() is not implemented for " + comp.getClass().getName());
                }
            }
              if (comp instanceof RadioList) {
                  Integer tvSet = (Integer) comp.getClientProperty("qq_TextValueSet");
                  if ((tvSet == null) || (tvSet.intValue() < 1)) {
                      tvSet = Integer.valueOf(defaultSet);
                  }
                  if (tvSet.intValue() < 1) {
                      return;
                  }
                  RadioList rl = (RadioList) comp;
                  if (msgNumber > 0) {
                    rl.setCaption(mcat.getString(msgSet, msgNumber, TextData.valueOf(rl.getCaption())));
                  }
                  for (ListElement le : rl.getElementList()) {
                      le.reloadLabelText(mcat, tvSet.intValue());
                  }
//                  rl.update();
                  return;
              }
              else if (comp instanceof ListView){ //PM:23/4/08 added support for ListView
                ListView lv = (ListView)comp;
              // TF:Mar 9, 2010:Corrected this for the default set
                int titleSetNum = lv.getTitleSetNum();
                if (titleSetNum <= 0 && defaultSet > 0) {
                  titleSetNum = defaultSet;
                }
                lv.loadColumnHeadings(titleSetNum, mcat);
              }
              else if (comp instanceof OutlineField) {
                OutlineField of = (OutlineField)comp;
                of.setDefaultSet(defaultSet, mcat);
              }
              else if (comp instanceof JTable) {
                JTable jt = (JTable) comp;
                ArrayColumnModel acm = (ArrayColumnModel) jt.getColumnModel();
                for (int col = 0; col < acm.allColumns.size(); col++) {
                    ArrayColumn ac = (ArrayColumn) acm.allColumns.get(col);
                    String header = (String) ac.getHeaderValue();
                    msgSet = ac.getTitleSetNumber();
                    if (msgSet <= 0 && defaultSet > 0) {
                        msgSet = defaultSet;
                    }
                    ac.setHeaderValue(mcat.getString(msgSet, ac.getTitleMsgNumber(), header));
                }
            }
            Component[] kids = comp.getComponents();
            for (int i = 0; i < kids.length; i++) {
                if (kids[i] instanceof JComponent) {
                    reloadLabelText((JComponent) kids[i], mcat, defaultSet);
                }
            }
      }
      @Override
      public String toString() {
        return "reloadLabelText(" + comp + ", " + mcat + ", " + defaultSet +")";
      }
    });
    }

    /**
     * The ReloadLabelText method loads text from the specified message catalog
     * to replace the text in the widget and all child widgets. Use this method
     * to load the messages from the message file. Typically, you call
     * ReloadLabelText before invoking the Open method for a window.
     *
     * @param comp
     * @param mcat
     */
    public static void reloadLabelText(JMenuItem comp, MsgCatalog mcat) {
        int defaultSet = getDefaultMessageSet(comp);
      reloadLabelText(comp, mcat, defaultSet);
    }
   
    /**
     * The ReloadLabelText method loads text from the specified message catalog
     * to replace the text in the widget and all child widgets. Use this method
     * to load the messages from the message file. Typically, you call
     * ReloadLabelText before invoking the Open method for a window.
     *
     * @param comp
     * @param mcat
     */
    public static void reloadLabelText(final JMenuItem comp, final MsgCatalog mcat, final int defaultSet) {
        if (comp == null || mcat == null) {
            return;
        }
        // TF:Mar 9, 2010:Changed this to process it on the EDT
        ActionMgr.addAction(new PendingAction(null) {
      @Override
      public void performAction() {
            Integer msgSet, msgNumber = null;
            msgSet = (Integer) comp.getClientProperty("qq_msgSet");
            msgNumber = (Integer) comp.getClientProperty("qq_msgNumber");
            if (((msgSet == null) || (msgSet.intValue() < 1)) && (defaultSet > -1)) {
                msgSet = Integer.valueOf(defaultSet);
            }
            if ((msgSet != null) && (msgNumber != null) && msgNumber.intValue() > 0) {
                String value = mcat.getString(msgSet.intValue(), msgNumber.intValue(), comp.getText());
                comp.setText(value);
                processMnemonic(comp);
            }
            MenuElement[] kids = comp.getSubElements();
            for (int i = 0; i < kids.length; i++) {
                if (kids[i] instanceof JMenuItem) {
                    reloadLabelText((JMenuItem) kids[i], mcat, defaultSet);
                }
                else if (kids[i] instanceof JPopupMenu) {
                    reloadLabelText((JPopupMenu) kids[i], mcat, defaultSet);
                }
            }
      }
      @Override
      public String toString() {
        return "reloadLabelText(" + comp + ", " + mcat + ", " + defaultSet + ")";
      }
    });
    }

    /**
     * processes the Menu text, detects the presence of '&', removes this and
     * takes the next char and sets it as the Mnemonic
     *
     * @param menu
     */
    public static void processMnemonic(JMenuItem menu) {
        String value = menu.getText();
        int amp = value.indexOf("&");
        if (amp != -1) {
            menu.setMnemonic(value.charAt(amp + 2));
            // WARNING: The assignment to variable value has no effect
            // value =
            value = value.replaceAll("&", "");
        }
        menu.setText(value);
    }

    public static void processMnemonic(JButton jb) {
        String value = jb.getText();
        int amp = value.indexOf("&");
        if (amp != -1) {
            jb.setMnemonic(value.charAt(amp + 2));
            // WARNING: The assignment to variable value has no effect
            // value =
            value = value.replaceAll("&", "");
        }
        jb.setText(value);
    }

    /**
     * The ReloadLabelText method loads text from the specified message catalog
     * to replace the text in the widget and all child widgets. Use this method
     * to load the messages from the message file. Typically, you call
     * ReloadLabelText before invoking the Open method for a window.
     *
     * @param comp
     * @param mcat
     */
    public static void reloadLabelText(JPopupMenu comp, MsgCatalog mcat) {
        int defaultSet = getDefaultMessageSet(comp);
      reloadLabelText(comp, mcat, defaultSet);
    }

    /**
     * The ReloadLabelText method loads text from the specified message catalog
     * to replace the text in the widget and all child widgets. Use this method
     * to load the messages from the message file. Typically, you call
     * ReloadLabelText before invoking the Open method for a window.
     *
     * @param comp
     * @param mcat
     */
    public static void reloadLabelText(final JPopupMenu comp, final MsgCatalog mcat, final int defaultSet) {
        if (comp == null || mcat == null) {
            return;
        }
        // TF:Mar 9, 2010:Changed this to process it on the EDT
        ActionMgr.addAction(new PendingAction(null) {
      @Override
      public void performAction() {
            Integer msgSet, msgNumber = null;
            msgSet = (Integer) comp.getClientProperty("qq_msgSet");
            msgNumber = (Integer) comp.getClientProperty("qq_msgNumber");
            if ((msgSet != null) && (msgNumber != null)) {
                String value = mcat.getString(msgSet.intValue(), msgNumber.intValue(), comp.getLabel());
                // int amp = value.indexOf("&");
                // if (amp != -1){
                // comp.setMnemonic(value.charAt(amp+2));
                // value = value.replace("&", "");
                // }
                comp.setLabel(value);
            }
            MenuElement[] kids = comp.getSubElements();
            for (int i = 0; i < kids.length; i++) {
                if (kids[i] instanceof JMenuItem) {
                    reloadLabelText((JMenuItem) kids[i], mcat, defaultSet);
                }
                else if (kids[i] instanceof JPopupMenu) {
                    reloadLabelText((JPopupMenu) kids[i], mcat, defaultSet);
                }
            }
      }
      @Override
      public String toString() {
        return "reloadLabelText(" + comp+", " + mcat + ", " + defaultSet + ")";
      }
        });
    }

    /**
     * Deletes the selected text in the JTextComponent
     *
     * @param comp
     * @deprecated this method is not thread-safe, use DeleteSelection action instead
     */
    public static void deleteSelection(JTextComponent comp) {
        try {
            comp.getDocument().remove(comp.getSelectionStart(), comp.getSelectionEnd());
        }
        catch (BadLocationException e) {
            _log.error("Error deleting selection", e);
        }

    }

    /**
     * sets the numeric template on a DataField
     *
     * @param dataField
     * @param template
     */
    public static void setNumericTemplate(DataField dataField, TextData template) {
        setNumericTemplate(dataField, template.getAsString());
    }

    /**
     * sets the numeric template on a DataField
     *
     * @param dataField
     * @param template
     */
    public static void setNumericTemplate(DataField dataField, String template) {
        if (dataField == null)
            return;
        if (template == null) {
            dataField.setFormatterFactory(null);
            return;
        }
        NumericFormat nf = new NumericFormat(template, NumericFormat.qq_Resolver.cTEMPLATE);
        DefaultFormatterFactory factory = new DefaultFormatterFactory(new NumberFormatter(nf.getFormatter()), // default
                new NumberFormatter(nf.getFormatter()), // display
                new NumberFormatter(nf.getFormatter()), // edit
                null); // null value
        dataField.setFormatterFactory(factory);
        if (dataField.getTable() != null) {
            JTable table = dataField.getTable();
            ArrayColumn ac = (ArrayColumn) table.getColumnModel().getColumn(dataField.getTableColumn());
            ac.setCellRenderer(new FormattedCellRenderer(nf, SwingUtilities.LEFT));
        }
    }

    /**
     * Implements the moveAbove Forte capability for components in a container
     *
     * @param moveTarget
     * @param aboveTarget
     */
    public static void moveAbove(JComponent moveTarget, JComponent aboveTarget) {
        MoveAbove.set(moveTarget, aboveTarget);
    }

    /**
     * Implements the moveBelow Forte Capability for components in a container
     *
     * @param moveTarget
     * @param aboveTarget
     */
    public static void moveBelow(JComponent moveTarget, JComponent belowTarget) {
        MoveBelow.set(moveTarget, belowTarget);
    }

    /**
     * The SetAsFunctionKey method allows you to assign any key on the keyboard
     * to be a function key.
     *
     * @param win
     * @param key
     * @param isFunction -
     *            The isFunction parameter specifies whether or not the key
     *            specified in the key parameter is a function key. To turn on a
     *            function key, set isFunction to TRUE. To turn off a function
     *            key, set isFunction to FALSE.
     * @return The return value for the SetAsFunctionKey method is an integer
     *         that represents a use count for the number of times the code for
     *         the window declared a particular key code as a function key. The
     *         count starts at zero. Every time you invoke SetAsFunctionKey for
     *         a particular key code with the isFunction parameter set to TRUE,
     *         UDS increments the use count by one. Every time you invoke
     *         SetAsFunctionKey for the particular key code with the isFunction
     *         parameter set to FALSE, UDS decrements the use count by one. The
     *         key is treated as a function key only when the count is greater
     *         than zero. Normally, you can ignore this return value.
     */
    public static int setAsFunctionKey(JFrame win, int key, boolean isFunction) {
        return UIutils.setAsFunctionKey(win, key, isFunction, false);
    }

    /**
     * @see UIutils.setAsFunctionKey(JFrame, int, boolean)
     *
     * @param includeAltKey Only set to true if the key is not used as a menu hot key. If it
     * is used as a menu hot key, then the menu hot key will no longer function.
     */
    public static int setAsFunctionKey(JFrame win, int key, boolean isFunction, boolean includeAltKey) {
        try {
            Expression expr = new Expression(win, "getForm", new Object[0]);
            expr.execute();
            JPanel form = ((JPanel) expr.getValue());
            Integer count = (Integer) form.getClientProperty("qq_FNkeyCount");
            if (count == null) {
                count = new Integer(0);
            }
            int changedKey = convertFunctionKeySymbol(key);
            InputMap im = form.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW);

            // In forte we have a virtual key, such as VK_K which we can say map to a button. It's not until the
            // key is pressed that we can test the modifiers, whereas in Java we can just register on say Ctrl-K.
            // Hence, we have to register for every combination of keystroke and then set up the modifiers later.
            if (isFunction){
                String keyVal = Integer.toString(changedKey);
                // Iterate through, setting up every combination of keystroke. We'll ignore ALT_GRAPH mask for now,
                // because most applications don't use them, and it halves the number of keystrokes to trap.
//              for (int i = 0; i <= (InputEvent.CTRL_MASK | InputEvent.ALT_MASK | InputEvent.SHIFT_MASK | InputEvent.META_MASK); i++) {
//                  im.put(KeyStroke.getKeyStroke(changedKey, i), keyVal );
//              }
                im.put(KeyStroke.getKeyStroke(changedKey, 0), keyVal );
                im.put(KeyStroke.getKeyStroke(changedKey, InputEvent.CTRL_MASK), keyVal );

                if (includeAltKey) {
                    im.put(KeyStroke.getKeyStroke(changedKey, InputEvent.ALT_MASK), keyVal );
                }
                im.put(KeyStroke.getKeyStroke(changedKey, InputEvent.SHIFT_MASK), keyVal );
//              im.put(KeyStroke.getKeyStroke(changedKey, InputEvent.ALT_MASK|InputEvent.CTRL_MASK), keyVal );
//              im.put(KeyStroke.getKeyStroke(changedKey, InputEvent.ALT_MASK|InputEvent.SHIFT_MASK), keyVal );
                im.put(KeyStroke.getKeyStroke(changedKey, InputEvent.CTRL_MASK|InputEvent.SHIFT_MASK), keyVal );
//              im.put(KeyStroke.getKeyStroke(changedKey, InputEvent.ALT_MASK|InputEvent.CTRL_MASK|InputEvent.SHIFT_MASK), keyVal );
                form.getActionMap().put(Integer.toString(changedKey), new FunctionKeyAction(key, win));
                count = new Integer(count.intValue() + 1);
            } else {
                // Iterate through, removing every combination of keystroke
//              for (int i = 0; i <= (InputEvent.CTRL_MASK | InputEvent.ALT_MASK | InputEvent.SHIFT_MASK | InputEvent.META_MASK); i++) {
//                    im.put(KeyStroke.getKeyStroke(changedKey, i), null);
//              }
                im.put(KeyStroke.getKeyStroke(changedKey, 0), null );
                im.put(KeyStroke.getKeyStroke(changedKey, InputEvent.CTRL_MASK), null );

                if (includeAltKey) {
                    im.put(KeyStroke.getKeyStroke(changedKey, InputEvent.ALT_MASK), null );
                }
                im.put(KeyStroke.getKeyStroke(changedKey, InputEvent.SHIFT_MASK), null );
//              im.put(KeyStroke.getKeyStroke(changedKey, InputEvent.ALT_MASK|InputEvent.CTRL_MASK), null );
//              im.put(KeyStroke.getKeyStroke(changedKey, InputEvent.ALT_MASK|InputEvent.SHIFT_MASK), null );
                im.put(KeyStroke.getKeyStroke(changedKey, InputEvent.CTRL_MASK|InputEvent.SHIFT_MASK), null );
//              im.put(KeyStroke.getKeyStroke(changedKey, InputEvent.ALT_MASK|InputEvent.CTRL_MASK|InputEvent.SHIFT_MASK), null );
                form.getActionMap().put(Integer.toString(changedKey), null);
                count = new Integer(Math.min(count.intValue() - 1, 0));
            }
            form.putClientProperty("qq_FNkeyCount", count);
            return count.intValue();
        }
        catch (NullPointerException e) {
            UsageException errorVar = new UsageException("NullPointerException on getForm() in window " + win.getName(), e);
            ErrorMgr.addError(errorVar);
            throw errorVar;
        }
        catch (Exception e) {
            UsageException errorVar = new UsageException("The JFrame: " + win.getName() + " dose not have a Form property", e);
            ErrorMgr.addError(errorVar);
            throw errorVar;
        }
    }

    /**
     * Converts the Forte Function Key constants to the equivelant Java Function
     * Key constants
     *
     * @param key
     * @return
     */
    public static int convertFunctionKeySymbol(int key) {
        int functionKey = KeyEvent.VK_0;
        switch (key) {
            case Constants.FN_F1:
                functionKey = KeyEvent.VK_F1;
                break;
            case Constants.FN_F2:
                functionKey = KeyEvent.VK_F2;
                break;
            case Constants.FN_F3:
                functionKey = KeyEvent.VK_F3;
                break;
            case Constants.FN_F4:
                functionKey = KeyEvent.VK_F4;
                break;
            case Constants.FN_F5:
                functionKey = KeyEvent.VK_F5;
                break;
            case Constants.FN_F6:
                functionKey = KeyEvent.VK_F6;
                break;
            case Constants.FN_F7:
                functionKey = KeyEvent.VK_F7;
                break;
            case Constants.FN_F8:
                functionKey = KeyEvent.VK_F8;
                break;
            case Constants.FN_F9:
                functionKey = KeyEvent.VK_F9;
                break;
            case Constants.FN_F10:
                functionKey = KeyEvent.VK_F10;
                break;
            case Constants.FN_F11:
                functionKey = KeyEvent.VK_F11;
                break;
            case Constants.FN_F12:
                functionKey = KeyEvent.VK_F12;
                break;
            case Constants.FN_F13:
                functionKey = KeyEvent.VK_F13;
                break;
            case Constants.FN_F14:
                functionKey = KeyEvent.VK_F14;
                break;
            case Constants.FN_F15:
                functionKey = KeyEvent.VK_F15;
                break;
            case Constants.FN_F16:
                functionKey = KeyEvent.VK_F16;
                break;
            case Constants.FN_F17:
                functionKey = KeyEvent.VK_F17;
                break;
            case Constants.FN_F18:
                functionKey = KeyEvent.VK_F18;
                break;
            case Constants.FN_F19:
                functionKey = KeyEvent.VK_F19;
                break;
            case Constants.FN_F20:
                functionKey = KeyEvent.VK_F20;
                break;
            case Constants.FN_F21:
                functionKey = KeyEvent.VK_F21;
                break;
            case Constants.FN_F22:
                functionKey = KeyEvent.VK_F22;
                break;
            case Constants.FN_F23:
                functionKey = KeyEvent.VK_F23;
                break;
            case Constants.FN_F24:
                functionKey = KeyEvent.VK_F24;
                break;
            case Constants.VK_0:
                functionKey = KeyEvent.VK_0;
                break;
            case Constants.VK_1:
                functionKey = KeyEvent.VK_1;
                break;
            case Constants.VK_2:
                functionKey = KeyEvent.VK_2;
                break;
            case Constants.VK_3:
                functionKey = KeyEvent.VK_3;
                break;
            case Constants.VK_4:
                functionKey = KeyEvent.VK_4;
                break;
            case Constants.VK_5:
                functionKey = KeyEvent.VK_5;
                break;
            case Constants.VK_6:
                functionKey = KeyEvent.VK_6;
                break;
            case Constants.VK_7:
                functionKey = KeyEvent.VK_7;
                break;
            case Constants.VK_8:
                functionKey = KeyEvent.VK_8;
                break;
            case Constants.VK_9:
                functionKey = KeyEvent.VK_9;
                break;
            case Constants.VK_A:
                functionKey = KeyEvent.VK_A;
                break;
            case Constants.VK_B:
                functionKey = KeyEvent.VK_B;
                break;
            case Constants.VK_C:
                functionKey = KeyEvent.VK_C;
                break;
            case Constants.VK_D:
                functionKey = KeyEvent.VK_D;
                break;
            case Constants.VK_E:
                functionKey = KeyEvent.VK_E;
                break;
            case Constants.VK_F:
                functionKey = KeyEvent.VK_F;
                break;
            case Constants.VK_G:
                functionKey = KeyEvent.VK_G;
                break;
            case Constants.VK_H:
                functionKey = KeyEvent.VK_H;
                break;
            case Constants.VK_I:
                functionKey = KeyEvent.VK_I;
                break;
            case Constants.VK_J:
                functionKey = KeyEvent.VK_J;
                break;
            case Constants.VK_K:
                functionKey = KeyEvent.VK_K;
                break;
            case Constants.VK_L:
                functionKey = KeyEvent.VK_L;
                break;
            case Constants.VK_M:
                functionKey = KeyEvent.VK_M;
                break;
            case Constants.VK_N:
                functionKey = KeyEvent.VK_N;
                break;
            case Constants.VK_O:
                functionKey = KeyEvent.VK_O;
                break;
            case Constants.VK_P:
                functionKey = KeyEvent.VK_P;
                break;
            case Constants.VK_Q:
                functionKey = KeyEvent.VK_Q;
                break;
            case Constants.VK_R:
                functionKey = KeyEvent.VK_R;
                break;
            case Constants.VK_S:
                functionKey = KeyEvent.VK_S;
                break;
            case Constants.VK_T:
                functionKey = KeyEvent.VK_T;
                break;
            case Constants.VK_U:
                functionKey = KeyEvent.VK_U;
                break;
            case Constants.VK_V:
                functionKey = KeyEvent.VK_V;
                break;
            case Constants.VK_W:
                functionKey = KeyEvent.VK_W;
                break;
            case Constants.VK_X:
                functionKey = KeyEvent.VK_X;
                break;
            case Constants.VK_Y:
                functionKey = KeyEvent.VK_Y;
                break;
            case Constants.VK_Z:
                functionKey = KeyEvent.VK_Z;
                break;
            case Constants.VK_ADD:
                functionKey = KeyEvent.VK_ADD;
                break;
            case Constants.VK_BACKSPACE:
                functionKey = KeyEvent.VK_BACK_SPACE;
                break;
            case Constants.VK_CANCEL:
                functionKey = KeyEvent.VK_CANCEL;
                break;
            case Constants.VK_DECIMAL:
                functionKey = KeyEvent.VK_DECIMAL;
                break;
            case Constants.VK_DELETE:
                functionKey = KeyEvent.VK_DELETE;
                break;
            case Constants.VK_DIVIDE:
                functionKey = KeyEvent.VK_DIVIDE;
                break;
            case Constants.VK_DOWN:
                functionKey = KeyEvent.VK_DOWN;
                break;
            case Constants.VK_END:
                functionKey = KeyEvent.VK_END;
                break;
            case Constants.VK_ENTER:
                functionKey = KeyEvent.VK_ENTER;
                break;
            case Constants.VK_ESCAPE:
                functionKey = KeyEvent.VK_ESCAPE;
                break;
            case Constants.VK_HOME:
                functionKey = KeyEvent.VK_HOME;
                break;
            case Constants.VK_INSERT:
                functionKey = KeyEvent.VK_INSERT;
                break;
            case Constants.VK_LEFT:
                functionKey = KeyEvent.VK_LEFT;
                break;
            case Constants.VK_MULTIPLY:
                functionKey = KeyEvent.VK_MULTIPLY;
                break;
            case Constants.VK_NUMPAD0:
                functionKey = KeyEvent.VK_NUMPAD0;
                break;
            case Constants.VK_NUMPAD1:
                functionKey = KeyEvent.VK_NUMPAD1;
                break;
            case Constants.VK_NUMPAD2:
                functionKey = KeyEvent.VK_NUMPAD2;
                break;
            case Constants.VK_NUMPAD3:
                functionKey = KeyEvent.VK_NUMPAD3;
                break;
            case Constants.VK_NUMPAD4:
                functionKey = KeyEvent.VK_NUMPAD4;
                break;
            case Constants.VK_NUMPAD5:
                functionKey = KeyEvent.VK_NUMPAD5;
                break;
            case Constants.VK_NUMPAD6:
                functionKey = KeyEvent.VK_NUMPAD6;
                break;
            case Constants.VK_NUMPAD7:
                functionKey = KeyEvent.VK_NUMPAD7;
                break;
            case Constants.VK_NUMPAD8:
                functionKey = KeyEvent.VK_NUMPAD8;
                break;
            case Constants.VK_NUMPAD9:
                functionKey = KeyEvent.VK_NUMPAD9;
                break;
            case Constants.VK_PGDN:
                functionKey = KeyEvent.VK_PAGE_DOWN;
                break;
            case Constants.VK_PGUP:
                functionKey = KeyEvent.VK_PAGE_UP;
                break;
            case Constants.VK_PRINTSCREEN:
                functionKey = KeyEvent.VK_PRINTSCREEN;
                break;
            case Constants.VK_RETURN:
                functionKey = KeyEvent.VK_ENTER;
                break;
            case Constants.VK_RIGHT:
                functionKey = KeyEvent.VK_RIGHT;
                break;
            case Constants.VK_SPACE:
                functionKey = KeyEvent.VK_SPACE;
                break;
            case Constants.VK_SUBTRACT:
                functionKey = KeyEvent.VK_SUBTRACT;
                break;
            case Constants.VK_TAB:
                functionKey = KeyEvent.VK_TAB;
                break;
            case Constants.VK_UP:
                functionKey = KeyEvent.VK_UP;
                break;
        }
        return functionKey;

    }

    /**
     * Converts the java COLOR to an equivelant Forte colour constant.
     *
     * @param colour
     * @return
     */
    public static int javaToForteColor(Color colour) {
        int target = Constants.C_INHERIT;
        if (colour == null)
            return target;

        if (colour.equals(UIutils.Black))
            target = Constants.C_BLACK;
        else if (colour.equals(UIutils.Blue))
            target = Constants.C_BLUE;
        else if (colour.equals(UIutils.BrightBlue))
            target = Constants.C_BRIGHTBLUE;

        else if (colour.equals(UIutils.BrightBrown))
            target = Constants.C_BRIGHTBROWN;

        else if (colour.equals(UIutils.BrightCyan))
            target = Constants.C_BRIGHTCYAN;

        else if (colour.equals(UIutils.BrightGreen))
            target = Constants.C_BRIGHTGREEN;

        else if (colour.equals(UIutils.BrightMagenta))
            target = Constants.C_BRIGHTMAGENTA;

        else if (colour.equals(UIutils.BrightRed))
            target = Constants.C_BRIGHTRED;

        else if (colour.equals(UIutils.BrightYellow))
            target = Constants.C_BRIGHTYELLOW;

        else if (colour.equals(UIutils.Brown))
            target = Constants.C_BROWN;

        else if (colour.equals(UIutils.Cyan))
            target = Constants.C_CYAN;

        else if (colour.equals(UIutils.Gray1))
            target = Constants.C_GRAY1;

        else if (colour.equals(UIutils.Gray2))
            target = Constants.C_GRAY2;

        else if (colour.equals(UIutils.Gray3))
            target = Constants.C_GRAY3;

        else if (colour.equals(UIutils.Gray4))
            target = Constants.C_GRAY4;

        else if (colour.equals(UIutils.Gray5))
            target = Constants.C_GRAY5;

        else if (colour.equals(UIutils.Gray6))
            target = Constants.C_GRAY6;

        else if (colour.equals(UIutils.Gray7))
            target = Constants.C_GRAY7;

        else if (colour.equals(UIutils.Green))
            target = Constants.C_GREEN;

        else if (colour.equals(UIutils.Magenta))
            target = Constants.C_MAGENTA;

        else if (colour.equals(UIutils.PaleBlue))
            target = Constants.C_PALEBLUE;

        else if (colour.equals(UIutils.PaleBrown))
            target = Constants.C_PALEBROWN;

        else if (colour.equals(UIutils.PaleCyan))
            target = Constants.C_PALECYAN;

        else if (colour.equals(UIutils.PaleMagenta))
            target = Constants.C_PALEMAGENTA;

        else if (colour.equals(UIutils.PaleRed))
            target = Constants.C_PALERED;

        else if (colour.equals(UIutils.PaleGreen))
            target = Constants.C_PALEGREEN;

        else if (colour.equals(UIutils.PaleYellow))
            target = Constants.C_PALEYELLOW;

        else if (colour.equals(UIutils.Red))
            target = Constants.C_RED;

        else if (colour.equals(UIutils.White))
            target = Constants.C_WHITE;

        else if (colour.equals(UIutils.Yellow))
            target = Constants.C_YELLOW;

        else {
            int index = WindowSystem.getRegisteredColour(colour);
            if (index > 0) {
                return index;
            }
        }
        return target;
    }

    /**
     * returns the Form widget of the Window.
     *
     * @param win
     * @return JPanel
     */
    //PM:13/6/08 changed to return type of Panel to unsure it is a compound field
    public static Panel getForm(JFrame win) {
                try {
                Expression expr = new Expression(win, "getForm", new Object[0]);
                    expr.execute();
                    Panel form = ((Panel)expr.getValue());
                    return form;
            } catch (Exception e) {
                return null;
            }

    }
    /**
     * this is a simple stub to aid in printing
     * @param printForm
     * @return
     */
    public static JPanel getForm(JPanel printForm) {
        return printForm;
    }

    /**
     * gets the value of the Maximum characters allowed in the field. Zero means
     * there is no limit
     *
     * @param comp
     * @return
     */
    public static int getMaxCharacters(JTextComponent comp) {
        return MaxCharacters.get(comp);
    }

    /**
     * gets the value of the Maximum characters allowed in the field. Zero means
     * there is no limit
     *
     * @param comp
     * @return
     */
    public static int getMaxCharacters(FillInField comp) {
        return MaxCharacters.get(comp);
    }

    /**
     * gets the caret position in a text component
     *
     * @param comp
     * @return
     */
    public static int getCursorPosition(JTextComponent comp) {
        int pos = comp.getCaret().getDot();
        return pos;

    }

    /**
     * gets the caret position in a AutoResizingComboBox emulating a Forte FIllinField
     *
     * AD:26/6/2008 Change JComboBox to AutoResizingComboBox to reduce casting later
     * @param comp
     * @return
     */
    public static int getCursorPosition(AutoResizingComboBox comp) {
        int pos = 0;
        if (comp.isEditable() && comp.getEditor() instanceof JTextComponent) {
            JTextComponent df = ((JTextComponent) comp.getEditor());
            pos = df.getCaret().getDot();
        }
        return pos;

    }

//    /**
//     * returns the data object attached to the panel
//     *
//     * @param panel
//     * @return
//     *
//     * TF:15/3/08:Removed in preference for using getDataObject(JComponent), as this relies
//     * on using object maps which are obsolete
//     */
//    public static Object getDataObject(JPanel panel) {
//        Object data = null;
//        if (panel instanceof GridField)
//            data = ((GridField) panel).getDataObject();
//        else
//            data = panel.getClientProperty("qq_DataObject");
//        return data;
//    }

    /**
     * invoked a Runnable on the EDT
     *
     * @param pAction
     */
    public static void invokeOnGuiThread(Runnable pAction) {
        Task.checkTaskCancelled();

        if (SwingUtilities.isEventDispatchThread()) {
            pAction.run();
        }
        else {
            try {
                SwingUtilities.invokeAndWait(pAction);
            }
            catch (InterruptedException e) {
                e.printStackTrace();
            }
            catch (InvocationTargetException e) {
                e.printStackTrace();
            }
        }
    }

    /*
     * emulates the Forte PurgeEvents method to aid in validation. It is only
     * implemented for DataFields.
     *
     * Any other "creative" (or wierd) usage of PurgeEvents is not supported.
     */
    public static void purgeEvents() {
        EventManager.purgeEvents();
//        EventHandle eh = (EventHandle) EventManager.CurrentEvent.get();
//        if (eh != null) {
//            ReEditCell.edit(eh);
//        }

    }

    /**
     * returns the current row from a JTable, while considering a current event;
     *
     * @param table
     * @return
     */
    public static int getCurrentRow(JTable table) {
        Integer current = currentRow.get();
        return current.intValue();

    }

    public static void setCurrentRow(JTable table, int row) {
        currentRow.set(new Integer(row));
        TableRow.set(table, row);

    }
    /**
     * Store the current row for the focused table on this thread. This current row is 1-based as
     * per forte arrays, not 0-based as per Java
     */
    public static ThreadLocal<Integer> currentRow = new ThreadLocal<Integer>() {
        protected Integer initialValue() {
            return new Integer(0);
        }
    };

    private static final Pattern fillCharacter = Pattern.compile("([^\\\\]|^)<(.)>");
    private static final Pattern optionalCharacters = Pattern.compile("([^\\\\]|^)\\[(.*)\\]");
    private static final Pattern repititionCount = Pattern.compile("([^\\\\]|^)\\((\\d+)\\)");

    /**
     * Translate a forte-style character template into a java-style character
     * template.
     * <p>
     * The following table lists the codes for a data field�s character format.
     * To force the literal interpretation of any character, precede the
     * character with a backslash. <table >
     * <tr>
     * <th>Code</th>
     * <th>Definition</th>
     * </tr>
     * <tr>
     * <td>?</td>
     * <td>Any single character.</td>
     * </tr>
     * <tr>
     * <td>#</td>
     * <td>Any single-digit number (0-9).</td>
     * </tr>
     * <tr>
     * <td>a</td>
     * <td>A lower case alphabetic character (a-z).</td>
     * </tr>
     * <tr>
     * <td>A</td>
     * <td>An upper case alphabetic character (A-Z).</td>
     * </tr>
     * <tr>
     * <td>@</td>
     *      <td>Any upper or lower case alphabetic character (a-Z).</td>
     *      </tr>
     *      <tr>
     *      <td>k</td>
     *      <td>Any single Kanji character.</td>
     *      </tr>
     *      <tr>
     *      <td>n</td>
     *      <td>A lower case alphanumeric character (a-z, 0-9).</td>
     *      </tr>
     *      <tr>
     *      <td>N</td>
     *      <td>An upper case alphanumeric character (A-Z, 0-9).</td>
     *      </tr>
     *      <tr>
     *      <td>&</td>
     *      <td>Any single alphanumeric character (a-z, A-Z, 0-9).</td>
     *      </tr>
     *      <tr>
     *      <td>[a-fQj]</td>
     *      <td>Any characters, range of characters, or combination of the two.
     *      The example to the left specifies a range extending from a to f and
     *      the characters Q and j.This code is case sensitive.</td>
     *      </tr>
     *      <tr>
     *      <td>(n)</td>
     *      <td>Repeating specification for any of the other codes. To repeat
     *      any code, precede the code with a number enclosed in parentheses to
     *      specify the number of repetitions.</td>
     *      </tr>
     *      <tr>
     *      <td><_></td>
     *      <td>Fills positions for which no value has been entered. Enter any
     *      character to override the default character, an underscore.</td>
     *      </tr>
     *      <tr>
     *      <td>!</td>
     *      <td>Indicates that the end-user can exit a field after having
     *      entered only partial data required by a template.</td>
     *      </tr>
     *      <tr>
     *      <td>\</td>
     *      <td>Forces the literal interpretation of any character. Spaces,
     *      slashes, colons, dashes, pluses, periods, and commas do not require
     *      the backslash for literal interpretation.</td>
     *      </tr>
     *      </table>
     * @param pForteCharacterTemplate
     *            The template in forte style
     */
    public static void setCharacterTemplate(final DataField pField, final String pForteCharacterTemplate) {
        String placeHolderChar = "_";
        @SuppressWarnings("unused")
    boolean allowPartial = false;

        StringBuilder aBuffer = new StringBuilder(pForteCharacterTemplate);

        int index = aBuffer.indexOf("!");
        while (index >= 0) {
            if (index == 0 || aBuffer.charAt(index - 1) != '\\') {
                aBuffer.deleteCharAt(index);
                allowPartial = true;
            }
            index = aBuffer.indexOf("!", index);
        }

        Matcher m = fillCharacter.matcher(aBuffer.toString());
        while (m.find()) {
            // we cannot use Matcher.replaceAll as this would remove the
            // preceeding character to the group too
            placeHolderChar = m.group(2);
            aBuffer.delete(m.start(2) - 1, m.end(2) + 1);
            m = fillCharacter.matcher(aBuffer.toString());
        }

        // See if there are character ranges (eg [0-9]) which are legal in
        // Forte but not in java
        m = optionalCharacters.matcher(aBuffer.toString());
        if (m.find()) {
            _log.debug("Java templates have no equivalent to character ranges in Forte (" + m.group(2) + " entered)");
            UsageException errorVar = new UsageException("Java templates have no equivalent to character ranges in Forte (" + m.group(2) + " entered)");
            ErrorMgr.addError(errorVar);
            throw errorVar;
        }

        // Look for any unescaped brackets
        m = repititionCount.matcher(aBuffer.toString());
        while (m.find()) {
            int count = Integer.parseInt(m.group(2));
            int end = m.end(2);
            char c = aBuffer.charAt(end + 1);
            char[] repeatingChar = new char[count];
            for (int i = 0; i < count; i++) {
                repeatingChar[i] = c;
            }
            aBuffer.replace(m.start(2) - 1, end + 2, new String(repeatingChar));
            m = repititionCount.matcher(aBuffer.toString());
        }

        // Now search through the string, looking for characters to
        // translate and removing escapre characters
        for (index = 0; index < aBuffer.length(); index++) {
            switch (aBuffer.charAt(index)) {
                case '\\':
                    // If the next character doesn't need escaping in the new
                    // mask then remove
                    // the escaping, else replace with the java escape character
                    // (')
                    switch (aBuffer.charAt(index + 1)) {
                        case '\\':
                        case 'a':
                        case '@':
                        case ')':
                        case '(':
                        case 'k':
                        case 'n':
                        case 'N':
                        case '&':
                        case '!':
                            aBuffer.deleteCharAt(index);
                            break;

                        default:
                            aBuffer.setCharAt(index, '\'');
                    }
                    break;

                case '?':
                    aBuffer.setCharAt(index, '*');
                    break;

                case 'a':
                    aBuffer.setCharAt(index, 'L');
                    break;

                case 'A':
                    aBuffer.setCharAt(index, 'U');
                    break;

                case '@':
                    aBuffer.setCharAt(index, '?');
                    break;

                case '&':
                    aBuffer.setCharAt(index, 'A');
                    break;

                case 'k':
                    UsageException errorVar = new UsageException("Java templates have no equivalent to the 'k' template character in Forte");
                    ErrorMgr.addError(errorVar);
                    throw errorVar;

                case 'n':
                    // n isn't really an A, but it's pretty close
                    _log.warn("Translated forte template character n to A which isn't an exact match");
                    aBuffer.setCharAt(index, 'A');
                    break;

                case 'N':
                    // n isn't really an A, but it's pretty close
                    _log.warn("Translated forte template character N to A which isn't an exact match");
                    aBuffer.setCharAt(index, 'A');
                    break;

                case '\'':
                case 'H':
                case 'U':
                case '*':
                    // These characters require escaping in java, but not in
                    // Forte
                    aBuffer.insert(index, '\'');
                    index++;
                    break;
            }
        }
        try {
            MaskFormatter aFormatter = new MaskFormatter(aBuffer.toString());
            aFormatter.setPlaceholderCharacter(placeHolderChar.charAt(0));
            aFormatter.setValueContainsLiteralCharacters(false);
            pField.setFormatterFactory(new DefaultFormatterFactory(aFormatter));
        }
        catch (Exception e) {
            _log.error("Could not set mask formatter to \"" + pForteCharacterTemplate + "\"", e);
        }
    }

    /**
     * Sets the template for the appropriate data field
     *
     * @see #setCharacterTemplate(DataField, String)
     * @param pField
     *            The data field to set the template of
     * @param pForteCharacterTemplate
     *            the character template to use
     */
    public static void setCharacterTemplate(final DataField pField, final TextData pForteCharacterTemplate) {
        UIutils.setCharacterTemplate(pField, pForteCharacterTemplate.getValue());
    }

    /**
     * Return the root node of the passed in tree as a display node. If the root
     * node is null or is not a display node, null will be returned.
     *
     * @param pTree -
     *            The tree whose root node is to be returned
     * @return the root node of the tree
     */
    public static DisplayNode getRootNode(final JTree pTree) {
        final ParameterHolder rootNode = new ParameterHolder();
        UIutils.invokeOnGuiThread(new Runnable() {
            public void run() {
                TreeModel aModel = pTree.getModel();
                if (aModel != null) {
                    rootNode.setObject(aModel.getRoot());
                }
            }
        });
        Object anObj = rootNode.getObject();
        if (anObj != null && anObj instanceof DisplayNode) {
            return (DisplayNode) anObj;
        }
        else {
            return null;
        }
    }

    /**
     * Return the root node of the passed in Outline as a display node. If the
     * root node is null or is not a display node, null will be returned.
     *
     * @param pField -
     *            The tree whose root node is to be returned
     * @return the root node of the tree
     */
    public static DisplayNode getRootNode(final OutlineField pField) {
        return pField.getRoot(true);
    }

    /**
     * @param comp
     * @return the window that comp in currently in.  Null for none.
     *
     * CraigM: 24/04/2008
     */
    public static JFrame getWindowForComponent(JComponent comp) {
        Container win = comp.getTopLevelAncestor();

        if (win == null) {
            JTable t = ArrayFieldCellHelper.getArrayField(comp);

            if (t != null) {
                // TF:25/9/07: Not sure why this is here -- if we leave this in, we
                // get the usage of the table, not the individual column if we passed in an individual column
                // comp = t;
                win = t.getTopLevelAncestor();
            }
        }

        // CraigM:24/06/2008 - PopupMenus do not have JFrames as parents.
        return win instanceof JFrame ? (JFrame)win : null;
    }

    public static JFrame getWindowForComponent(Component container) {
      //PM: added case for JComponent that is a container
      if (container instanceof JComponent){
        return getWindowForComponent((JComponent)container);
      } else {
        while (container != null && container instanceof JFrame == false) {
          container = container.getParent();
        }
        return (JFrame)container;
      }
    }

    /**
     * Implements the RenderAsImage method on Forte/UDS Widgets
     *
     * @param win
     * @return
     */
    public static ImageData renderAsImage(Component win, boolean includeFrame) {
        Dimension componentSize = win.getSize(); // Changed from getPreferredSize.  CraigM: 06/02/2008.
        win.setSize(componentSize);
        Border oldBorder = null;
        if (!includeFrame){
            oldBorder = ((JComponent)win).getBorder();
            ((JComponent)win).setBorder(null);
        }
        BufferedImage img = new BufferedImage(componentSize.width, componentSize.height, BufferedImage.TYPE_INT_RGB);
        Graphics2D grap = img.createGraphics();
        grap.fillRect(0, 0, img.getWidth(), img.getHeight());
        win.paint(grap);
        ImageData id = new ImageData(img);
        if (!includeFrame){
            ((JComponent)win).setBorder(oldBorder);
        }
        return id;
    }
    public static ImageData renderAsImage(Component win) {
        return renderAsImage(win, true);
    }
    /**
     * returns the format string for the default curency
     *
     * @return
     */
    public static String getCurrencyPattern() {
        DecimalFormat df = ((DecimalFormat) NumberFormat.getCurrencyInstance());
        String pattern = df.getDecimalFormatSymbols().getCurrencySymbol() + df.toPattern().substring(1);
        return pattern;
    }

    public static int getLineWeightInPixels(int pWeight) {
        switch (pWeight) {
            case Constants.W_NONE:
                return 0;
            case Constants.W_DEFAULT:
                return 1;
            case Constants.W_ONEPIXEL:
                return 1;
            case Constants.W_TWOPIXELS:
                return 2;
            case Constants.W_THREEPIXELS:
                return 3;
            case Constants.W_VERYTHIN:
                return 1;
            case Constants.W_THIN:
                return 2;
            case Constants.W_MEDIUM:
                return 3;
            case Constants.W_HEAVY:
                return 4;
            case Constants.W_VERYHEAVY:
                return 13;
            default:
                if (pWeight > 0) {
                    // Value explicitly in mils, use it.
                    return UIutils.milsToPixels(pWeight);
                }
                else {
                    return 1;
                }
        }
    }

    private static int maxWeight = 0;

    /**
     * Obtain the maximum weight any line can have, in pixels.
     *
     * @return the maximum weight
     */
    public static int getMaxLineWeightInPixels() {
        if (maxWeight > 0)
            return maxWeight;
        else
            return (maxWeight = UIutils.getLineWeightInPixels(Constants.W_VERYHEAVY));
    }

    /**
     * Creates a stroke used for line rendering
     *
     * @param weight
     * @param style
     * @return
     */
    public static BasicStroke makeStroke(int weight, int style) {
        return UIutils.makeStroke(weight, style, BasicStroke.CAP_BUTT);
    }

    /**
     * Creates a stroke used for line rendering
     *
     * @param weight
     * @param style
     * @return
     */
    public static BasicStroke makeStroke(int weight, int style, int capStyle) {
      BasicStroke stroke = null;
      int lineWidth = 1;
      float[] dashPat = { 10f };
      switch (style) {
      case Constants.LS_SOLID:
      case Constants.LS_DEFAULT:
        dashPat = null;
        break;
      // TF:Mar 4, 2010:Tests with Forte showed that default lines are solid
//      case Constants.LS_DEFAULT:
//        dashPat = new float[] { 10f, 10f };
//        break;
      case Constants.LS_DASH:
        dashPat = new float[] { 25f, 10f };
        break;
      case Constants.LS_DASHDOT:
        dashPat = new float[] { 14f, 8f, 4f, 8f };
        break;
      case Constants.LS_DASHDOTDOT:
        dashPat = new float[] { 14f, 4f, 4f, 4f, 4f, 4f };
        break;
      case Constants.LS_DOT:
        dashPat = new float[] { 4f, 4f };
        break;
      }
      lineWidth = UIutils.getLineWeightInPixels(weight);
      stroke = new BasicStroke(lineWidth, capStyle, BasicStroke.JOIN_MITER, 1.0f, dashPat, 5f);
      return stroke;
    }
   
    /**
     * Determines whether the passed jTextArea tabs to the next control upon
     * receiving the TAB keystroke, or if it uses this as part of it's input.
     *
     * @param pTextArea
     *            The text area on which to effect the change
     * @param pDoExit
     *            True if the field should change the focus to the next control
     *            on receiving a TAB, or false if it should consume the tab
     *            itself and treat it as the tab character
     *           
     * @deprecated Use ExitOnTab.set instead
     */
    public static void setExitOnTab(final JTextArea pTextArea, final boolean pDoExit) {
        ExitOnTab.set(pTextArea, pDoExit);
    }

    public static void traceWidget(Component comp) {
        _log.debug("===== Trace Widget =====");
        traceWidget(comp, 0);
    }

    public static void traceWidget(Component comp, int indent) {
        String tabs = "";
        for (int t = 0; t < indent; t++)
            tabs += "\t";
        _log.debug(tabs + "---- Name: " + comp.getName() + " Type: " + FrameworkUtils.getClassName(comp.getClass()));  
        _log.debug(tabs + "Visable: " + comp.isVisible());
        _log.debug(tabs + "Enabled: " + comp.isEnabled());
        _log.debug(tabs + "Focasable: " + comp.isFocusable());
        _log.debug(tabs + "Back Color: " + comp.getBackground());
        _log.debug(tabs + "Fore Color: " + comp.getForeground());
        _log.debug(tabs + "Size: " + comp.getSize());
        _log.debug(tabs + "Min Size: " + comp.getMinimumSize());
        _log.debug(tabs + "Prefered Size: " + comp.getPreferredSize());
        _log.debug(tabs + "Location: " + comp.getLocation());
        if (comp instanceof JComponent)
            _log.debug(tabs + "Layout: " + ((JComponent) comp).getLayout());
        _log.debug(tabs + "---- ");
        if (comp instanceof JComponent) {
            JComponent jcomp = (JComponent) comp;
            for (int k = 0; k < jcomp.getComponentCount(); k++) {
                traceWidget(jcomp.getComponent(k), indent + 1);
            }
        }
    }

    /**
     * Resizes a button to the Button text
     *
     * @param but
     * @return
     */
    public static Dimension packButton(JButton but) {
        Dimension size = but.getSize();
        String text = but.getText();
        Font f = but.getFont();
        FontMetrics fm = but.getFontMetrics(f);
        Insets ins = but.getInsets();
        int width = SwingUtilities.computeStringWidth(fm, text);
        but.setSize(ins.left + ins.right + width, size.height);
        return but.getSize();
    }

    /**
     * Resizes a Check Box to the text
     *
     * @param but
     * @return
     */
    public static Dimension packCheck(JCheckBox but) {
        Dimension size = but.getSize();
        String text = but.getText();
        Font f = but.getFont();
        FontMetrics fm = but.getFontMetrics(f);
        Insets ins = but.getInsets();
        int width = SwingUtilities.computeStringWidth(fm, text);
        int checkWidth = 15; // but.getComponent(0).getWidth();
        but.setSize(ins.left + ins.right + width + checkWidth, size.height);
        return but.getSize();
    }

    /*
     * causes all parent containers to relayout their components
     */
    public static void validateUp(Component comp) {
        if (comp == null)
            return;
        Component mum = comp.getParent();
        while (mum != null) {
            mum.validate();
            mum = mum.getParent();
        }
    }

    /**
     * this method is undocumented in Forte, but seems to return the next
     * display node in a tree irrespective of whether the node is visible or
     * expanded or not.
     *
     * @param pNode
     * @return
     */
    public static DisplayNode getNextLine(DisplayNode pNode) {
        DisplayNode result;
        if (pNode == null) {
            return null;
        }
        else if (pNode.getChildCount() > 0) {
            return (DisplayNode) pNode.getFirstChild();
        }
        else if ((result = (DisplayNode) pNode.getNextSibling()) != null) {
            return result;
        }
        else {
            // Ok, it's nothing we know about. Scan up our parents for siblings.
            DisplayNode aNode = (DisplayNode) pNode.getParent();
            while (aNode != null) {
                if ((result = (DisplayNode) aNode.getNextSibling()) != null) {
                    return result;
                }
                aNode = (DisplayNode) aNode.getParent();
            }
        }
        return null;
    }

    public static void setDataChangedFlag(Component comp) {
        if (comp == null)
            return;

        // CraigM:31/07/2008 - If the data changed flag was set due to a programatic data change, we don't actually want to set the flag
        if (EventManager.isPostingEnabled() == false) {
          return;
        }
       
        if (comp instanceof JComponent) {
            JComponent jc = (JComponent) comp;
            jc.putClientProperty("HasDataChanged", Boolean.valueOf(true));
            // TF:13/01/2009:Added in the posting of the hasDataChanged property to allow after value change events to be performed on grid fields
            jc.firePropertyChange("hasDataChanged", false, true);
            while ((jc.getParent() != null) && (jc.getParent() instanceof JComponent)) {
                jc = (JComponent) jc.getParent();
                jc.putClientProperty("HasDataChanged", Boolean.valueOf(true));
                // TF:13/01/2009:Added in the posting of the hasDataChanged property to allow after value change events to be performed on grid fields
                jc.firePropertyChange("hasDataChanged", false, true);

                // CraigM:05/01/2009 - Flag that the data has changed in the row.
                if (jc instanceof ArrayField) {
                  ((ArrayField)jc).setDataChangedInRow();
                }
            }
        }
    }

    public static int forteAlignmentToJava(int pAlignment) {
        // Translate the Forte Alignment into a java-valued alignment
        switch (pAlignment) {
            case Constants.TA_LEFT:
                return SwingConstants.LEFT;
            case Constants.TA_RIGHT:
                return SwingConstants.RIGHT;
            case Constants.TA_BOTTOM:
                return SwingConstants.BOTTOM;
            case Constants.TA_TOP:
                return SwingConstants.TOP;
            case Constants.TA_CENTER:
                return SwingConstants.CENTER;
            default:
                return SwingConstants.LEFT;
        }
    }

    public static int javaAlignementToForte(int pAlignment) {
        // Translate the Java Alignment into a forte-valued alignment
        switch (pAlignment) {
            case SwingConstants.LEFT:
                return Constants.TA_LEFT;
            case SwingConstants.RIGHT:
                return Constants.TA_RIGHT;
            case SwingConstants.BOTTOM:
                return Constants.TA_BOTTOM;
            case SwingConstants.TOP:
                return Constants.TA_TOP;
            case SwingConstants.CENTER:
                return Constants.TA_CENTER;
            default:
                return Constants.TA_DEFAULT;
        }
    }

    /**
     * Convenience method to obtain the component at a given cell in the passed
     * table
     *
     * @param table
     * @param row
     * @param col
     * @return
     */
    public static Component getTableCellRenderer(JTable table, int row, int col) {
        TableCellRenderer renderer = table.getCellRenderer(row, col);
        Object o = null;
        try {
            o = table.getValueAt(row, col);
        }
        catch (Exception e) {
            // Leave the value as null
        }
        return renderer.getTableCellRendererComponent(table, o, false, false, row, col);
    }

    /**
     * Bring the passed window to the front of the hierarchy, incluing restoring
     * it from an iconized state if applicable. This is always done on the GUI
     * thread and all pending actions are processed as a consequence of this
     * method.
     *
     * @param pWindow
     *            The window to bring to the front.
     */
    public static void toFront(final Frame pWindow) {
        // Process the pending actions. This cannot be done inside the
        // invokeOnGuiThread (unfortunately)
        // because processGUIActions processes the actions only for the current
        // thread (and there will
        // never be any pending actions on the EDT!)
        UIutils.processGUIActions();
        UIutils.invokeOnGuiThread(new Runnable() {
            public void run() {
                if (WindowDisplayState.get(pWindow) == Constants.DS_ICONIZED) {
                    WindowDisplayState.set(pWindow, Constants.DS_NORMAL);
                }
                pWindow.toFront();
            }
        });
    }

    /**
     * scrollToRow scroll the JTable to a particular row
     *
     * @param table
     *            The JTable
     * @param row
     *            the row to scroll to
     * @return
     */

    public static void scrollToRow(JTable t, int r) {
        JViewport viewport = (JViewport) t.getParent();
        viewport.setViewPosition(new java.awt.Point(0, t.getRowHeight() * r));
    }

    /**
     * This method returns the Window System Type
     * @return
     */
    public static int getWindowSystemType() {
        int osType = FrameworkUtils.getOSType();
        switch (osType){
        case Framework.Constants.OS_OT_WIN95:
            return Constants.WT_MSWINDOWS95;
        case Framework.Constants.OS_OT_NT:
            return Constants.WT_MSWINDOWS;
        case Framework.Constants.OS_OT_MACOS:
            return Constants.WT_MACINTOSH;
        case Framework.Constants.OS_OT_SOLARIS:
            return Constants.WT_XMOTIF;
        case Framework.Constants.OS_OT_HPUX:
            return Constants.WT_XMOTIF;
        case Framework.Constants.OS_OT_VMS:
            return Constants.WT_XMOTIF;
        case Framework.Constants.OS_OT_OSF1:
            return Constants.WT_XMOTIF;
        }
        return Constants.WT_MSWINDOWS;
    }

    /**
     * Converts a number of pixels to a number of rows based on
     * a components font metrics
     * @param pixels
     * @param comp
     * @return
     */
    public static int pixelsToRows(int pixels, JComponent pWidget) {
            FontMetrics fm = pWidget.getFontMetrics(pWidget.getFont());
            return pixels / fm.getHeight();//(fm.getMaxAscent() + fm.getMaxDescent());
    }

    /**
     * converts a KeyStroke to a string
     * @param key
     * @return
     */
    public static String keyStroke2String(KeyStroke key) {
      StringBuilder s = new StringBuilder(50);
        int m = key.getModifiers();

        if ((m & (InputEvent.SHIFT_DOWN_MASK|InputEvent.SHIFT_MASK)) != 0) {
            s.append("shift ");
        }
        if ((m & (InputEvent.CTRL_DOWN_MASK|InputEvent.CTRL_MASK)) != 0) {
            s.append("ctrl ");
        }
        if ((m & (InputEvent.META_DOWN_MASK|InputEvent.META_MASK)) != 0) {
            s.append("meta ");
        }
        if ((m & (InputEvent.ALT_DOWN_MASK|InputEvent.ALT_MASK)) != 0) {
            s.append("alt ");
        }
        if ((m & (InputEvent.BUTTON1_DOWN_MASK|InputEvent.BUTTON1_MASK)) != 0) {
            s.append("button1 ");
        }
        if ((m & (InputEvent.BUTTON2_DOWN_MASK|InputEvent.BUTTON2_MASK)) != 0) {
            s.append("button2 ");
        }
        if ((m & (InputEvent.BUTTON3_DOWN_MASK|InputEvent.BUTTON3_MASK)) != 0) {
            s.append("button3 ");
        }

        switch (key.getKeyEventType()) {
        case KeyEvent.KEY_TYPED:
            s.append("typed ");
            s.append(key.getKeyChar() + " ");
            break;
        case KeyEvent.KEY_PRESSED:
            s.append("pressed ");
            s.append(getKeyText(key.getKeyCode()) + " ");
            break;
        case KeyEvent.KEY_RELEASED:
            s.append("released ");
            s.append(getKeyText(key.getKeyCode()) + " ");
            break;
        default:
            s.append("unknown-event-type ");
            break;
        }

        return s.toString();
    }
    /**
     * Converts a key code to a string
     * @param keyCode
     * @return
     */
    public static String getKeyText(int keyCode) {
        if (keyCode >= KeyEvent.VK_0 && keyCode <= KeyEvent.VK_9 ||
            keyCode >= KeyEvent.VK_A && keyCode <= KeyEvent.VK_Z) {
            return String.valueOf((char)keyCode);
        }

        switch(keyCode) {
            case KeyEvent.VK_COMMA: return "COMMA";
            case KeyEvent.VK_PERIOD: return "PERIOD";
            case KeyEvent.VK_SLASH: return "SLASH";
            case KeyEvent.VK_SEMICOLON: return "SEMICOLON";
            case KeyEvent.VK_EQUALS: return "EQUALS";
            case KeyEvent.VK_OPEN_BRACKET: return "OPEN_BRACKET";
            case KeyEvent.VK_BACK_SLASH: return "BACK_SLASH";
            case KeyEvent.VK_CLOSE_BRACKET: return "CLOSE_BRACKET";

            case KeyEvent.VK_ENTER: return "ENTER";
            case KeyEvent.VK_BACK_SPACE: return "BACK_SPACE";
            case KeyEvent.VK_TAB: return "TAB";
            case KeyEvent.VK_CANCEL: return "CANCEL";
            case KeyEvent.VK_CLEAR: return "CLEAR";
            case KeyEvent.VK_SHIFT: return "SHIFT";
            case KeyEvent.VK_CONTROL: return "CONTROL";
            case KeyEvent.VK_ALT: return "ALT";
            case KeyEvent.VK_PAUSE: return "PAUSE";
            case KeyEvent.VK_CAPS_LOCK: return "CAPS_LOCK";
            case KeyEvent.VK_ESCAPE: return "ESCAPE";
            case KeyEvent.VK_SPACE: return "SPACE";
            case KeyEvent.VK_PAGE_UP: return "PAGE_UP";
            case KeyEvent.VK_PAGE_DOWN: return "PAGE_DOWN";
            case KeyEvent.VK_END: return "END";
            case KeyEvent.VK_HOME: return "HOME";
            case KeyEvent.VK_LEFT: return "LEFT";
            case KeyEvent.VK_UP: return "UP";
            case KeyEvent.VK_RIGHT: return "RIGHT";
            case KeyEvent.VK_DOWN: return "DOWN";

            // numpad numeric keys handled below
            case KeyEvent.VK_MULTIPLY: return "MULTIPLY";
            case KeyEvent.VK_ADD: return "ADD";
            case KeyEvent.VK_SEPARATOR: return "SEPARATOR";
            case KeyEvent.VK_SUBTRACT: return "SUBTRACT";
            case KeyEvent.VK_DECIMAL: return "DECIMAL";
            case KeyEvent.VK_DIVIDE: return "DIVIDE";
            case KeyEvent.VK_DELETE: return "DELETE";
            case KeyEvent.VK_NUM_LOCK: return "NUM_LOCK";
            case KeyEvent.VK_SCROLL_LOCK: return "SCROLL_LOCK";

            case KeyEvent.VK_F1: return "F1";
            case KeyEvent.VK_F2: return "F2";
            case KeyEvent.VK_F3: return "F3";
            case KeyEvent.VK_F4: return "F4";
            case KeyEvent.VK_F5: return "F5";
            case KeyEvent.VK_F6: return "F6";
            case KeyEvent.VK_F7: return "F7";
            case KeyEvent.VK_F8: return "F8";
            case KeyEvent.VK_F9: return "F9";
            case KeyEvent.VK_F10: return "F10";
            case KeyEvent.VK_F11: return "F11";
            case KeyEvent.VK_F12: return "F12";
            case KeyEvent.VK_F13: return "F13";
            case KeyEvent.VK_F14: return "F14";
            case KeyEvent.VK_F15: return "F15";
            case KeyEvent.VK_F16: return "F16";
            case KeyEvent.VK_F17: return "F17";
            case KeyEvent.VK_F18: return "F18";
            case KeyEvent.VK_F19: return "F19";
            case KeyEvent.VK_F20: return "F20";
            case KeyEvent.VK_F21: return "F21";
            case KeyEvent.VK_F22: return "F22";
            case KeyEvent.VK_F23: return "F23";
            case KeyEvent.VK_F24: return "F24";

            case KeyEvent.VK_PRINTSCREEN: return "PRINTSCREEN";
            case KeyEvent.VK_INSERT: return "INSERT";
            case KeyEvent.VK_HELP: return "HELP";
            case KeyEvent.VK_META: return "META";
            case KeyEvent.VK_BACK_QUOTE: return "BACK_QUOTE";
            case KeyEvent.VK_QUOTE: return "QUOTE";

            case KeyEvent.VK_KP_UP: return "KP_UP";
            case KeyEvent.VK_KP_DOWN: return "KP_DOWN";
            case KeyEvent.VK_KP_LEFT: return "KP_LEFT";
            case KeyEvent.VK_KP_RIGHT: return "KP_RIGHT";

            case KeyEvent.VK_DEAD_GRAVE: return "DEAD_GRAVE";
            case KeyEvent.VK_DEAD_ACUTE: return "DEAD_ACUTE";
            case KeyEvent.VK_DEAD_CIRCUMFLEX: return "DEAD_CIRCUMFLEX";
            case KeyEvent.VK_DEAD_TILDE: return "DEAD_TILDE";
            case KeyEvent.VK_DEAD_MACRON: return "DEAD_MACRON";
            case KeyEvent.VK_DEAD_BREVE: return "DEAD_BREVE";
            case KeyEvent.VK_DEAD_ABOVEDOT: return "DEAD_ABOVEDOT";
            case KeyEvent.VK_DEAD_DIAERESIS: return "DEAD_DIAERESIS";
            case KeyEvent.VK_DEAD_ABOVERING: return "DEAD_ABOVERING";
            case KeyEvent.VK_DEAD_DOUBLEACUTE: return "DEAD_DOUBLEACUTE";
            case KeyEvent.VK_DEAD_CARON: return "DEAD_CARON";
            case KeyEvent.VK_DEAD_CEDILLA: return "DEAD_CEDILLA";
            case KeyEvent.VK_DEAD_OGONEK: return "DEAD_OGONEK";
            case KeyEvent.VK_DEAD_IOTA: return "DEAD_IOTA";
            case KeyEvent.VK_DEAD_VOICED_SOUND: return "DEAD_VOICED_SOUND";
            case KeyEvent.VK_DEAD_SEMIVOICED_SOUND: return "DEAD_SEMIVOICED_SOUND";

            case KeyEvent.VK_AMPERSAND: return "AMPERSAND";
            case KeyEvent.VK_ASTERISK: return "ASTERISK";
            case KeyEvent.VK_QUOTEDBL: return "QUOTEDBL";
            case KeyEvent.VK_LESS: return "LESS";
            case KeyEvent.VK_GREATER: return "GREATER";
            case KeyEvent.VK_BRACELEFT: return "BRACELEFT";
            case KeyEvent.VK_BRACERIGHT: return "BRACERIGHT";
            case KeyEvent.VK_AT: return "AT";
            case KeyEvent.VK_COLON: return "COLON";
            case KeyEvent.VK_CIRCUMFLEX: return "CIRCUMFLEX";
            case KeyEvent.VK_DOLLAR: return "DOLLAR";
            case KeyEvent.VK_EURO_SIGN: return "EURO_SIGN";
            case KeyEvent.VK_EXCLAMATION_MARK: return "EXCLAMATION_MARK";
            case KeyEvent.VK_INVERTED_EXCLAMATION_MARK:
                    return "INVERTED_EXCLAMATION_MARK";
            case KeyEvent.VK_LEFT_PARENTHESIS: return "LEFT_PARENTHESIS";
            case KeyEvent.VK_NUMBER_SIGN: return "NUMBER_SIGN";
            case KeyEvent.VK_MINUS: return "MINUS";
            case KeyEvent.VK_PLUS: return "PLUS";
            case KeyEvent.VK_RIGHT_PARENTHESIS: return "RIGHT_PARENTHESIS";
            case KeyEvent.VK_UNDERSCORE: return "UNDERSCORE";

            case KeyEvent.VK_FINAL: return "FINAL";
            case KeyEvent.VK_CONVERT: return "CONVERT";
            case KeyEvent.VK_NONCONVERT: return "NONCONVERT";
            case KeyEvent.VK_ACCEPT: return "ACCEPT";
            case KeyEvent.VK_MODECHANGE: return "MODECHANGE";
            case KeyEvent.VK_KANA: return "KANA";
            case KeyEvent.VK_KANJI: return "KANJI";
            case KeyEvent.VK_ALPHANUMERIC: return "ALPHANUMERIC";
            case KeyEvent.VK_KATAKANA: return "KATAKANA";
            case KeyEvent.VK_HIRAGANA: return "HIRAGANA";
            case KeyEvent.VK_FULL_WIDTH: return "FULL_WIDTH";
            case KeyEvent.VK_HALF_WIDTH: return "HALF_WIDTH";
            case KeyEvent.VK_ROMAN_CHARACTERS: return "ROMAN_CHARACTERS";
            case KeyEvent.VK_ALL_CANDIDATES: return "ALL_CANDIDATES";
            case KeyEvent.VK_PREVIOUS_CANDIDATE: return "PREVIOUS_CANDIDATE";
            case KeyEvent.VK_CODE_INPUT: return "CODE_INPUT";
            case KeyEvent.VK_JAPANESE_KATAKANA: return "JAPANESE_KATAKANA";
            case KeyEvent.VK_JAPANESE_HIRAGANA: return "JAPANESE_HIRAGANA";
            case KeyEvent.VK_JAPANESE_ROMAN: return "JAPANESE_ROMAN";
            case KeyEvent.VK_KANA_LOCK: return "KANA_LOCK";
            case KeyEvent.VK_INPUT_METHOD_ON_OFF: return "INPUT_METHOD_ON_OFF";

            case KeyEvent.VK_AGAIN: return "AGAIN";
            case KeyEvent.VK_UNDO: return "UNDO";
            case KeyEvent.VK_COPY: return "COPY";
            case KeyEvent.VK_PASTE: return "PASTE";
            case KeyEvent.VK_CUT: return "CUT";
            case KeyEvent.VK_FIND: return "FIND";
            case KeyEvent.VK_PROPS: return "PROPS";
            case KeyEvent.VK_STOP: return "STOP";

            case KeyEvent.VK_COMPOSE: return "COMPOSE";
            case KeyEvent.VK_ALT_GRAPH: return "ALT_GRAPH";
        }

        if (keyCode >= KeyEvent.VK_NUMPAD0 && keyCode <= KeyEvent.VK_NUMPAD9) {
            char c = (char)(keyCode - KeyEvent.VK_NUMPAD0 + '0');
            return "NUMPAD"+c;
        }

        return "unknown(0x" + Integer.toString(keyCode, 16) + ")";
    }
    /**
     * List key bindings
     * @param map
     * @param keys
     */
    public static void listKeyBinding(InputMap map, KeyStroke[] keys) {
        if (keys == null) {
            return;
        }
        System.out.println("Key Bindings:");
        for (int i=0; i<keys.length; i++) {
            // This method is defined in e859 Converting a KeyStroke to a String
            // String keystrokeStr =  keyStroke2String(keys[i]);

            // Get the action name bound to this keystroke
            while (map.get(keys[i]) == null) {
                map = map.getParent();
            }
            if (map.get(keys[i]) instanceof String) {
                String actionName = (String)map.get(keys[i]);
                System.out.println(actionName);
            } else {
                Action action = (Action)map.get(keys[i]);
                System.out.println(action);
            }
        }
    }

    /**
     * Sometimes it is critical that we delay until the EDT has finished processing actions. This can be to
     * avoid race conditions where there are multiple events on the event queue which can affect the state
     * of variables. For example, gaining focus in a table via a mouse click will set the current row to
     * the correct row from the initial mouse click, 0 from the focus event, and then back to the correct
     * row. Obviously this has race condition implications if another thread tries to read this value whilst
     * the EDT is still adjusting it. <p>
     * <p>
     * This method halts the current thread until the EDT is idle and has finished processing all events in
     * it's stack.<p>
     * <p>
     * <b>Note:<b>If multiple windows invoke this method simultaneously, they will push their events onto the
     * queue, which will prevent the other thread from releasing, so it pushes another waiting event onto the EDT
     * preventing the first thread from leaving, etc. Hence, the delay should be long enough to reasonably allow
     * the EDT to finish processing all "are you waiting" requests from all threads. (The peekEvent must be
     * done on the EDT to ensure the EDT is not in the middle of processing an event with nothing in the queue)
     */
    public static void waitForEDTToBeIdle() {
      // CraigM:25/06/2008 - If we are already on the EDT, we can't wait for it to be idle.
      if (SwingUtilities.isEventDispatchThread()) {
        return;
      }
     
        final ParameterHolder holder = new ParameterHolder();
        do {
            try {
                Thread.sleep(20);
            } catch (InterruptedException e) {}
            UIutils.invokeOnGuiThread(new Runnable() {
                public void run() {
                    AWTEvent e = Toolkit.getDefaultToolkit().getSystemEventQueue().peekEvent();
                    holder.setBoolean(e != null);
                }
            });
        } while (holder.getBoolean());

    }
    /**
     * This converience method finds the JFrame a widget is defined in.
     * When a Window is running naturally the return value will be the same
     * as the top level ancestor.
     *
     * When the JFrame is nested in another window, the return value will be
     * the JFrame the widget is defined on;
     * @param name
     * @param comp
     * @return
     */
    public static JFrame getDeclaredFrame(Component comp) {
        if(comp == null)
            return null;

        if (comp instanceof MenuElement) {
          return getFrame((MenuElement)comp);
        }
        Container parent = comp.getParent();
        JFrame frame = null;
        while(parent != null){
            if (parent instanceof JComponent){
                frame = (JFrame)((JComponent)parent).getClientProperty("qq_DeclaredWindow");
                if (frame != null){
                    break;
                }
            }
            parent = parent.getParent();
        }
        if (frame == null)
            return UIutils.getWindowForComponent(comp);
        else
            return frame;
    }

    /**
     * returns the JFrame ancestor to this menu item
     *
     * @param menu
     * @return
     */
    public static JFrame getFrame(MenuElement menu) {
        Component target = menu.getComponent();
        // TF:07/01/2010:Added in a test to see if the declared frame has been explicitly set
        if (target instanceof JComponent) {
          JFrame frame = (JFrame)((JComponent)target).getClientProperty("qq_DeclaredWindow");
            if (frame != null){
                return frame;
            }
        }
        Container parent = menuParent(target);
        while(parent != null){
            parent = menuParent(parent);
            if (parent != null)
                target = parent;
        }
        if (target instanceof JFrame) {
          return (JFrame)target;
        }
        else {
          // TF:20/6/08:This is an unparented menu element, return null
          return null;
        }
    }

    private static Container menuParent(Component menu){
        Container parent = null;
        if (menu.getParent() instanceof JPopupMenu) {
            parent = (JMenu)((JPopupMenu)menu.getParent()).getInvoker();
        }
        else {
            parent = menu.getParent();
        }
        return parent;
    }

    private static void _setUsage(JComponent comp, int pState) {
        if (comp != null) {
            WidgetState.set(comp, pState);
            Component[] children = comp.getComponents();
            for (Component child : children) {
                _setUsage((JComponent)child, pState);
            }
        }
    }

    /**
     * The setUsage metho sets the State attribute for all a window�s child
     * widgets at once, providing collective widget State changes on a
     * predefined basis. A widget�s State attribute determines how the
     * widget reacts to mouse actions and how it displays itself. A widget
     * is always in some state.  <p>
     * <p>
     * @param frame
     * @param pState
     */
    public static void setUsage(JFrame frame, int pState) {
        Container container = frame.getContentPane();
        _setUsage((JComponent)container, pState);
    }
    /**
     * A utility method to produce invert {@link java.awt.image.BufferedImage} to a negative
     * @param buff
     * @return negative {@link java.awt.image.BufferedImage}
     */
    public static BufferedImage invert(BufferedImage buff){
        // create 256 color array and invert colors
        byte[] invertArray = new byte[ 256 ];
       
        for ( int counter = 0; counter < 256; counter++ )
           invertArray[ counter ] = ( byte )( 255 - counter );  
       
        // create filter to invert colors
        BufferedImageOp invertFilter = new LookupOp(
           new ByteLookupTable( 0, invertArray ), null );
       
        // apply filter to displayImage
        return invertFilter.filter( buff, null );

    }
    /**
     * A utility method to produce a gray scale {@link java.awt.image.BufferedImage}
     * @param buff
     * @return gray scale {@link java.awt.image.BufferedImage}
     */
    public static BufferedImage grayScale(BufferedImage buff){
      ColorConvertOp op = new ColorConvertOp(ColorSpace.getInstance(ColorSpace.CS_GRAY), null);
      BufferedImage grayImage = op.filter(buff, null);
      return grayImage;
    }
    /**
     * A utility method to produce a transparent {@link java.awt.image.BufferedImage}
     * @param buff
     * @return transparent {@link java.awt.image.BufferedImage}
     */
    public static BufferedImage transparentImage(BufferedImage buff){
    int transparentColour = buff.getRGB(0, 0);
    return transparentImage(buff, transparentColour);
    }
    /**
     * A utility method to produce a transparent {@link java.awt.image.BufferedImage}
     * @param buff
     * @param transparent {@link java.awt.Colour} value
     * @return transparent {@link java.awt.image.BufferedImage}
     */
    public static BufferedImage transparentImage(BufferedImage buff, Color transparentColour){
    return transparentImage(buff, transparentColour.getRGB());
    }
    /**
     * A utility method to produce a transparent {@link java.awt.image.BufferedImage}
     * @param buff
     * @param transparent Colour incoded RGB integer value
     * @return transparent {@link java.awt.image.BufferedImage}
     */
    public static BufferedImage transparentImage(BufferedImage buff, int transparentColour){
    for (int y = 0; y < buff.getHeight(); y++) {
      for (int x = 0; x < buff.getWidth(); x++) {
        int target = buff.getRGB(x, y);
        if (target == transparentColour) {
          target &= 0x00FFFFFF; // set the alpha value to 0x00
          buff.setRGB(x, y, target);
        }
      }
    }
    return buff;
    }

    /**
     * Get the data object for any component. This method is primarily for use with compound fields
     * (panels, grid fields, tab folders, etc) but should be able to be called for any component that
     * has been bound with the binding manager
     * @param component
     * @return
     */
    public static Object getDataObject(JComponent component) {
      // CraigM:14/01/2009 - Handle nested windows
      // Container owner = UIutils.getWindowForComponent(component);
      Container owner = UIutils.getDeclaredFrame(component);
      Method bindingManagerMethod; //PM:5 Nov 2008:changed to used the method in place of the field
    try {
      bindingManagerMethod = owner.getClass().getDeclaredMethod("getBindingManager", new Class[0]);
      bindingManagerMethod.setAccessible(true);
        BindingManager bindingManager = (BindingManager)bindingManagerMethod.invoke(owner, new Object[0]);
        return bindingManager.getDataObject(component);
    }
    catch (Exception e) {
      return null;
    }
    }
   
    /**
     * Get the data object for any component. This method is primarily for use with compound fields
     * (panels, grid fields, tab folders, etc) but should be able to be called for any component that
     * has been bound with the binding manager
     * @param component
     * @return
     */
    public static Object getDataObject(CompoundField component) {
      return getDataObject((JComponent)component);
  }

  /**
   * Determine whether the passed object is an instance of a "simple field" as
   * defined by Forte. A simple field maps to scalar data and simple data types
   * such as date, integer, float and string.
   *
   * @param object
   * @return true if this object is a simple field, false otherwise
   */
  public static boolean isSimpleField(Object object) {
      return  object instanceof CharacterField ||
          object instanceof JTextComponent ||
        object instanceof ListField ||
        ((object instanceof JList) && !(object instanceof MenuList))  ||
        object instanceof PictureField ||
        object instanceof JScrollBar ||
        object instanceof JCheckBox ||
        object instanceof JComboBox ||
        object instanceof OutlineField ||
        object instanceof JTree ||
        object instanceof ListView;
    }

  /**
   * Determine whether the passed object is an instance of a "variable field" as
   * defined by Forte. A sVariableField is an abstract class that defines all widgets
   * that can be associated with underlying data, such as text fields and array fields.
   *
   * @param object
   * @return true if this object is a variable field, false otherwise
   */
  public static boolean isVariableField(Object object) {
    return isSimpleField(object) || object instanceof CompoundField;
  }

  /**
   * Determine whether the passed object is an instance of a "static field" as
   * defined by Forte. A static field is an abstract class representing all
   * static fields. Static fields are not associated with underlying data.
   *
   * @param object
   * @return true if this object is a static field, false otherwise
   */
  public static boolean isStaticField(Object object) {
    return object instanceof Graphic || object instanceof JButton;
  }
 
  /**
   * This method installs a bunch of defaults that are required to make the converted
   * application look and behave like the original Forte system
   * @throws UnsupportedLookAndFeelException
   */
  public static AppletConnectionInfo initialiseGuiSystem() throws UnsupportedLookAndFeelException {
        // Install our own focus manager. MUST be done prior to setting the
        // UIManager, otherwise you'll run into issues like things have the wrong focus.
        KeyboardFocusManager.setCurrentKeyboardFocusManager(new ForteKeyboardFocusManager());
        RepaintManager.setCurrentManager(new ForteRepaintManager());
        // CONV:TF:Check the type of the operating system before loading the look and feel
        int type = FrameworkUtils.getOSType();
        if (type == Framework.Constants.OS_OT_NT ||
            type == Framework.Constants.OS_OT_WIN95) {
          UIManager.setLookAndFeel(new Win32LookAndFeel());
        }
       
        // TF:20/11/2009:Load the glassPane so it attaches itself to the event queue
        GlassPaneWithEvents.getCurrentEvent();
       
    // Forte never dismissed tool tips, so mirror this.
    ToolTipManager.sharedInstance().setDismissDelay(Integer.MAX_VALUE);

        return UserWindow.postAPPLETStarted();
  }
 
  /**
   * Display the popup menu in a thread-safe manner. This method will also process the GUI
   * actions prior to showing the popup to ensure that the menu is in the correct state.
   * @param menu - the menu to display
   * @param parent - the component that will own the menu
   * @param xPos - the x position of the menu, in the parent's coordinate system in mils
   * @param yPos - the y position of the menu, in the parent's coordinate system in mils
   */
  public static void showPopupMenu(final JPopupMenu menu, final Component parent, final int xPos, final int yPos) {
    if (menu != null) {
      UIutils.processGUIActions();
      UIutils.invokeOnGuiThread(new Runnable() {
        public void run() {
          menu.show(parent, UIutils.milsToPixels(xPos), UIutils.milsToPixels(yPos));
        }
      });
    }
  }
  /**
   * Gets all focusable components of the component including all the child components.
   * Recurcivelly checks isFocusable flag for all the child components.
   * @param component component to be checked.
   * @return list of focusable components or empty list.
   */
  public static List<Component> getFocusableChildren(Component component) {
    ArrayList<Component> result = new ArrayList<Component>();
    if (component.isFocusable()) {
      result.add(component);
    }
    if (component instanceof Container) {
      for (Component c : ((Container)component).getComponents()) {
        result.addAll(getFocusableChildren(c));
      }
    }
    return result;
  }
 
  /**
   * Gets all cild components of the component including themself.
   * @param component a component to be looked for child components.
   * @return list of child components or list with only one omponent if the component do not have child components.
   */
  public static List<Component> getAllChildren(Component component) {
    ArrayList<Component> result = new ArrayList<Component>();
    result.add(component);
    if (component instanceof Container) {
      for (Component c : ((Container)component).getComponents()) {
        result.addAll(getAllChildren(c));
      }
    }
    return result;
  }
 
  /**
   * Adds th mouse listener to all child components including the incoming component.
   * @param component a component
   * @param mouseListener mouse listener to be added
   */
  public static void addMouseListenerToAllChildren(Component component, MouseListener mouseListener) {
    List<Component> children = getAllChildren(component);
    for (Component c : children) {
      c.addMouseListener(mouseListener);
    }
  }
 
 
    /**
     * Adjusts location of the component to take into account of the
     * desktop bounds, taskbar and multi-monitor configuration.
     * @param component a component to be adjusted
     */
  public static void adjustComponentLocationToFitScreen(Component component) {
    Point p = component.getLocation();

    Toolkit toolkit = Toolkit.getDefaultToolkit();
    Rectangle screenBounds;
    Insets screenInsets;
    GraphicsConfiguration gc = null;
    // Try to find GraphicsConfiguration, that includes the component top left corner.
    GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
    GraphicsDevice[] gd = ge.getScreenDevices();
    for(int i = 0; i < gd.length; i++) {
      if(gd[i].getType() == GraphicsDevice.TYPE_RASTER_SCREEN) {
        GraphicsConfiguration dgc = gd[i].getDefaultConfiguration();
        if(dgc.getBounds().contains(p)) {
          gc = dgc;
          break;
        }
      }
    }

    // If not found comonent about his gc
    if(gc == null) {
      gc = component.getGraphicsConfiguration();
    }

    if(gc != null) {
      // If we have GraphicsConfiguration use it to get
      // screen bounds and insets
      screenInsets = toolkit.getScreenInsets(gc);
      screenBounds = gc.getBounds();
    } else {
      // If we don't have GraphicsConfiguration use primary screen
      // and empty insets
      screenInsets = new Insets(0, 0, 0, 0);
      screenBounds = new Rectangle(toolkit.getScreenSize());
    }

    int scrWidth = screenBounds.width - Math.abs(screenInsets.left+screenInsets.right);
    int scrHeight = screenBounds.height - Math.abs(screenInsets.top+screenInsets.bottom);

    Dimension size = component.getSize();

    // Use long variables to prevent overflow
    long pw = (long) p.x + (long) size.width;
    long ph = (long) p.y + (long) size.height;

    if( pw > screenBounds.x + scrWidth )
      p.x = screenBounds.x + scrWidth - size.width;

    if( ph > screenBounds.y + scrHeight)
      p.y = screenBounds.y + scrHeight - size.height;

    // Change is made to the desired (X,Y) values, when the
        // component is too tall OR too wide for the screen
    
    if( p.x < screenBounds.x )
      p.x = screenBounds.x ;
    if( p.y < screenBounds.y )
      p.y = screenBounds.y;

    component.setLocation(p);
  }
 
  /**
   * Get the background colour of the parent of the passed component. This is necessary in case the component does not actually
   * have the background colour set, we need to find out the background colour of the parent. If the parent of the component
   * does not have a background color set we need the background colour of the parent's parent, and so on. If none of the ancestors
   * of the components have a background colour set, this method will return null, a signal for the underlying component to return
   * the default colour it wants to appear. 
   * @param comp
   * @return
   */
  public static Color getParentBackgroundColor(final JComponent comp) {
    if (comp == null) {
      return null;
    }
    Component oldComponent = comp;
      Container parent = comp.getParent();
      // TF:10/01/2010:DET-140:Made this array-field aware
      while (true) {
        // Keep going up until we find a parent with the background set. We don't care about
        // JScrollPanes or JViewports, because these should derive their colour from the control,
        // not the other way around
        while (parent != null && (!parent.isBackgroundSet() || parent instanceof JScrollPane || parent instanceof JViewport)) {
          // TF:19/01/2010:DET-140:If our parent is an array field EditorLayoutPanel then set the parent to null
          if (parent instanceof EditorLayoutPanel) {
            parent = null;
          }
          else {
            oldComponent = parent;
            parent = parent.getParent();
          }
        }
        if (parent == null && ArrayFieldCellHelper.isInArrayField(oldComponent)) {
          parent = ArrayFieldCellHelper.getArrayField(oldComponent);
        }
        else {
          break;
        }
      }
      if (parent != null && !(parent instanceof Window)) {
        return parent.getBackground();
      }
      return null;
  }
 
  /**
   * Instantiate a window class on the EDT and invoke any init method it has going. The instantiation is done
   * on the EDT, but the init method is called from the thread that called this method. Note that in order to
   * simulate normal constructor behaviour, the init methods must call
   * @param <T>
   * @param pClassType
   * @return
   */
  @SuppressWarnings("unchecked")
  public <T extends JFrame> T instantiateWindow(final Class<T> pClassType) {
    final ParameterHolder ph = new ParameterHolder();
    UIutils.invokeOnGuiThread(new Runnable()  {
      public void run() {
        try {
          ph.setObject(FrameworkUtils.newInstance(pClassType));
        }
        catch (Exception e) {
          ph.setObject(e);
        }
      }
    });
    if (ph.getObject() instanceof RuntimeException) {
      throw (RuntimeException)ph.getObject();
    }
    else {
      return (T)ph.getObject();
    }
  }
}
TOP

Related Classes of DisplayProject.UIutils$NodeRemoved

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.