package oracle.forms.fd;

import java.awt.Color;
import java.awt.Component;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Image;
import java.awt.event.FocusEvent;
import java.awt.event.FocusListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;

import java.text.DateFormat;
import java.text.DecimalFormat;
import java.text.DecimalFormatSymbols;
import java.text.NumberFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;

import java.util.Date;
import java.util.HashMap;
import java.util.Locale;
import java.util.StringTokenizer;

import javax.swing.DefaultCellEditor;
import javax.swing.ImageIcon;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.JTextField;
import javax.swing.ListSelectionModel;
import javax.swing.SwingConstants;
import javax.swing.border.LineBorder;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import javax.swing.table.AbstractTableModel;
import javax.swing.table.DefaultTableCellRenderer;
import javax.swing.table.TableColumn;

import oracle.forms.handler.IHandler;
import oracle.forms.properties.ID;
import oracle.forms.ui.CustomEvent;
import oracle.forms.ui.VBean;

import sun.misc.BASE64Encoder;
import sun.misc.BASE64Decoder;
/*
 uncomment the following 2 imports to
 use the Oracle Look and Feel
*/ 
//import javax.swing.UIManager;
//import oracle.bali.ewt.olaf.OracleLookAndFeel;

  /**
   * A javabean that displays a JTable
   * inside or outside the Forms frame
   *
   * @author Francois Degrelle
   * @version 1.4.1
   * 
   * this version allows to update the cells
   * and fire events to Forms when Row or Cell change
   * like When-new-Record-Instance 
   * and  When-New-Item-Instance
   * can set format on Integer/Number/Date cells
   * and other cell properties like colors, alignement and font.
   * can also display images from the database Blob columns
   * 
   * May 2008 : bug correction with CHAR cells that
   * do not show correctly BG_COLOR,FG_COLOR, ALIGNMENT, etc...
   */

public class FJTable extends VBean implements FocusListener{
    public final static ID SETHEADER        = ID.registerProperty("SETHEADER");  
    public final static ID SETFORMATS       = ID.registerProperty("SETFORMATS");
    public final static ID SETCOLSTYPE      = ID.registerProperty("SET_COLS_TYPE");      
    public final static ID SETCELLPROP      = ID.registerProperty("SET_CELL_PROPERTY");
    public final static ID SETCELLVALUE     = ID.registerProperty("SET_CELL_VALUE");    
    public final static ID SETCURCELLVALUE  = ID.registerProperty("SET_CURRENT_CELL_VALUE");    
    public final static ID SETROWPROP       = ID.registerProperty("SET_ROW_PROPERTY");
    public final static ID SETDATA          = ID.registerProperty("SETDATA");    
    public final static ID SETDATEFORMAT    = ID.registerProperty("SET_DATE_FORMAT");    
    public final static ID SETNUMFORMAT     = ID.registerProperty("SET_NUM_FORMAT");        
    public final static ID SETINTFORMAT     = ID.registerProperty("SET_INT_FORMAT");        
    public final static ID ADD_ROW          = ID.registerProperty("ADD_ROW");    
    public final static ID SETTITLE         = ID.registerProperty("SETTITLE");      
    public final static ID SETARRAYSIZE     = ID.registerProperty("SETARRAYSIZE");
    public final static ID SETBOUNDS        = ID.registerProperty("SETBOUNDS");              
    public final static ID SETHEADBG        = ID.registerProperty("SETHEADBG");    
    public final static ID SETHEADFG        = ID.registerProperty("SETHEADFG");    
    public final static ID SETDATABG        = ID.registerProperty("SETDATABG");        
    public final static ID SETDATAFG        = ID.registerProperty("SETDATAFG");    
    public final static ID SETGRIDFG        = ID.registerProperty("SETGRIDFG");        
    public final static ID SETUPDATE        = ID.registerProperty("SETUPDATE"); 
    public final static ID SETCELLPOS       = ID.registerProperty("SETCELLPOS");    
    public final static ID SETROWPOS        = ID.registerProperty("SETROWPOS");        
    public final static ID SETSEPARATOR     = ID.registerProperty("SETSEPARATOR");    
    public final static ID SETIMAGESIZE     = ID.registerProperty("SET_IMAGE_SIZE");
    public final static ID SETREORDER       = ID.registerProperty("SET_REORDER_COLUMNS");    
    public final static ID SETRESIZE        = ID.registerProperty("SET_RESIZE_COLUMNS");    
    public final static ID SETSELECTBACK    = ID.registerProperty("SET_SELECTION_BACKGROUND");        
    public final static ID SETSELECTFORE    = ID.registerProperty("SET_SELECTION_FOREGROUND");        
    public final static ID SETDECSEPARATORS = ID.registerProperty("SET_DECIMAL_SEPARATORS");            
    public final static ID SETLOCALE        = ID.registerProperty("SET_LOCALE");            
    public final static ID SETVLINE         = ID.registerProperty("SET_VERTICAL_LINE");        
    public final static ID SETHLINE         = ID.registerProperty("SET_HORIZONTAL_LINE");            
    public final static ID SETLOG           = ID.registerProperty("SETLOG");        
    public final static ID GETCELLVAL       = ID.registerProperty("GETCELLVAL");    
    public final static ID GETROWVAL        = ID.registerProperty("GETROWVAL");        
    public final static ID INIT             = ID.registerProperty("INIT");    
    public final static ID SHOW             = ID.registerProperty("SHOW");      
    public final static ID TRG_WNRI         = ID.registerProperty("NEW_RECORD_INSTANCE");          
    public final static ID TRG_WNII         = ID.registerProperty("NEW_ITEM_INSTANCE");
    public final static ID TRG_WMC          = ID.registerProperty("WHEN-MOUSE-CLICK");
    public final static ID TRG_WMDC         = ID.registerProperty("WHEN-MOUSE-DOUBLECLICK");
    public final static ID TABLE_EVENT      = ID.registerProperty("POST_CHANGE");    
    public final static ID TABLE_EVENT_MSG  = ID.registerProperty("TABLE_EVENT_MSG");    
    public final static ID GETROWSCHANGED   = ID.registerProperty("GET_ROWS_CHANGED");        
    public final static ID SETIMAGE         = ID.registerProperty("SET_IMAGE");  

    private StringBuffer sbImage =new StringBuffer();
    private boolean bSeperateFrame = false ;       // popup in a seperate frame
    private boolean bUpdatable = false ;           // can update the table
    private boolean bReorder = true ;              // can reorder the columns
    private boolean bResize = true ;               // can resize the columns
    private boolean bLog = false ;                 // output to java console
    private int     x=10, y=10, w=500, h=100 ;     // separate frame bounding box
    private int     iNbRows = 0, iNbCols = 0 ;     // table dimensions
    private int     iCurLine = 0 ;                 // current line selected
    private int     iRowPos = 0, iCellPos = 0 ;    // current row, cell selected
    private int     iCurRow = 0, iCurCell = 0 ;    // current row, cell
    private int     iRowHeight = -1 ;              // current row height
    private int     iCurImageRow  = -1 ;
    private int     iCurImageCell = -1 ;
    private int     iImageWidth  = 100 ;
    private int     iImageHeight = -1 ;
    private String  separator = "^" ;              // current separator
    private String  sTitle = "" ;                  // separate frame title
    private String  sDateFormat = "dd/MM/yyyy" ;   // default date format
    private String  sIntFormat  = "#" ;            //  default integer format    
    private String  sNumFormat  = "#.##" ;         //  default number format
    private Locale  locale = Locale.getDefault();
    private DecimalFormatSymbols DecimalSymbols = new DecimalFormatSymbols(locale); 
    private Color   HeadBGColor, HeadFGColor, DataBGColor, DataFGColor, GridColor;
    private Color   SelBGColor = new Color(206,232,255), SelFGColor=new Color(0,64,128) ;
    private HashMap hCellProps = new HashMap() ;
    private ListSelectionModel listSelectionModel;    
    private IHandler           m_handler; 
    private Container          contentpane ;
    private JScrollPane        scrollPane ;
    private JTable             table ;
    private MyTableModel       model ;    
    private JFrame             frame ;
    private int[] iRowsChanged ;
    private int[] iColWidth ;
    private Font[] fColFont ;
    private String[] colnames ;
    private Object[][] data ;
    private String[] coltypes ;
    private int     iImageIndex = 0 ;
    private String  sCellValue = "" ;
    private KeyListener kl ;
    private MouseListener ml ;
    private   java.io.OutputStream os;

    public FJTable() {
        super();
        //
        //  uncomment the following lines to
        //  use the Oracle Look and Feel
        //  (must add the share.jar and jewt4.jar files to the archive/archive_jini tags)
        /*
        try{
           // use the Oracle Look and Feel
           UIManager.setLookAndFeel(new OracleLookAndFeel());
        }
        catch(Exception e) {}        
        */
        contentpane = this ;
        model = new MyTableModel(); 
        table = new JTable(model);
        table.setAutoResizeMode(table.AUTO_RESIZE_OFF);
        table.setPreferredScrollableViewportSize(new Dimension(400, 70));
        table.setAutoCreateColumnsFromModel(true);        
        table.setSelectionBackground(SelBGColor);
        table.setSelectionForeground(SelFGColor);
        listSelectionModel = table.getSelectionModel();
        listSelectionModel.addListSelectionListener(new SharedListSelectionHandler());
        table.setSelectionModel(listSelectionModel);        
        scrollPane = new JScrollPane(table);        
        add(scrollPane);
    }
    
  public void init(IHandler handler)
  {
    m_handler = handler;
    super.init(handler);
    addFocusListener(this);
    setKeyListener() ;
    setMouseListener() ;
  }      
      

  /**
   *  Method to print the table's content
   */
  private void printDebugData(JTable table) {
        int numRows = table.getRowCount();
        int numCols = table.getColumnCount();
        javax.swing.table.TableModel model = table.getModel();

        log("Value of data: ");
        for (int i=0; i < numRows; i++) {
            log("    row " + i + ":");
            for (int j=0; j < numCols; j++) {
                log("  " + model.getValueAt(i, j));
            }
            log("");
        }
        log("--------------------------");
    }

  /*-----------------------------------*
   *  All the properties you can set
   *-----------------------------------*/
  public boolean setProperty(ID property, Object value)
  {
    if(property != SETIMAGE)log(property+":"+value);
    
    //
    // set the header
    //
    if (property == SETHEADER) 
    {
      hCellProps = new HashMap() ;
      String label = value.toString();
      StringTokenizer st ;
      int i = 0 ; String title ;
      //st = new StringTokenizer(label,",");
      st = new StringTokenizer(label, separator);
      while (st.hasMoreTokens()) {
         title = st.nextToken() ;
         i++ ;
      }
      i = 0 ;
      st = new StringTokenizer(label, separator);
      while (st.hasMoreTokens()) {
         colnames[i] = (st.nextToken()) ;
         CellProp cp = new CellProp(colnames[i]);
         hCellProps.put(colnames[i],cp);
         i++;
      }

      return true;
    }
    //
    // set the image
    //
    else if(property==SETIMAGE)
    {
      
      String sImage = value.toString();
      if(sImage.startsWith("[INDEX_IMAGE]"))
      {
        StringTokenizer st ;
        String sValue = "" ;
        int iRow = 0, iCell = 0 ;
        st = new StringTokenizer(sImage,",");
        st.nextToken() ;
        if(st.hasMoreTokens())
        {
          try{iRow = Integer.parseInt(st.nextToken());}
          catch(Exception e){System.out.println("Set_Image() Unable to get the Row index"); return false ;}
        } else return false ;
        if(st.hasMoreTokens())
        {
          try{iCell = Integer.parseInt(st.nextToken());}
          catch(Exception e){System.out.println("Set_Image() Unable to get the Cell index"); return false ;}
        } else return false ;
        if((iRow-1) < 0 || (iRow > iNbRows)) return false ;
        if((iCell-1) < 0 || (iCell > iNbCols)) return false ;
        iCurImageRow  = iRow - 1 ;
        iCurImageCell = iCell - 1 ;
      }
      else if(!sImage.equalsIgnoreCase("[END_IMAGE]"))
      {
        sbImage.append(sImage) ;
      }
      else
      {
        BASE64Encoder encoder = new BASE64Encoder();
        BASE64Decoder decoder = new BASE64Decoder();
        try{
          byte[] decodedStr = decoder.decodeBuffer(sbImage.toString());
          ImageIcon ii = new ImageIcon(decodedStr);
          Image img = ii.getImage() ;     
          // scale the image
          ii = new ImageIcon(img.getScaledInstance(iImageWidth, iImageHeight, Image.SCALE_SMOOTH));
          if(iCurImageRow > -1 && iCurImageCell > -1)
          {
            log("Set Image: "+ii.getIconWidth()+"*"+ii.getIconHeight());
            data[iCurImageRow][iCurImageCell] = ii ;
          }  
        } catch(Exception e){}
        finally{ 
           sbImage =new StringBuffer(); 
           iCurImageRow = iCurImageCell = -1 ;
        }
      }
      return true ;
    }
    
    //
    // image size
    //
    else if (property == SETIMAGESIZE)
    {
      String label = value.toString();
      StringTokenizer st ;
      int iW = 0, iH = 0 ;
      st = new StringTokenizer(label,",");
      if(st.hasMoreTokens()) 
      {
        try{
          iW = Integer.parseInt(st.nextToken());
        } catch(Exception e){System.out.println("SetImageSize Unable to set the image width"); return false;}  
      } else return false ;
      if(st.hasMoreTokens()) 
      {
        try{
          iH = Integer.parseInt(st.nextToken());
        } catch(Exception e){System.out.println("SetImageSize Unable to set the image height"); return false;}  
      } else return false ;
      iImageWidth  = iW ;
      iImageHeight = iH ;
      return true ;
    }
    //
    // set the columns type
    //
    else if (property == SETCOLSTYPE)
    {
      String label = value.toString();
      StringTokenizer st ;
      int i = 0 ; String title ;
      st = new StringTokenizer(label, separator);
      while (st.hasMoreTokens()) {
         coltypes[i] = (st.nextToken()) ;
         i++;
      }

      return true;
    }    
 
    //
    // set the current cell value
    //
    if (property == SETCURCELLVALUE) 
    {
      int iRow = iCurRow + 1 ;
      int iCell = iCurCell + 2 ;
      String sValue = "^" + iRow + "^" + iCell + "^" + value.toString();
      setProperty(SETCELLVALUE,sValue);
      table.repaint();
      return true ;
    }
     
    //
    // set the Cell value
    //
    if (property == SETCELLVALUE) 
    {
        // params Row and Cell given
        // are starting at 1,1
        // JTable starts at 0,0 so we have
        // to supress 1 from arguments
        String s = value.toString();
        String s1="", s2="", s3="", s4="" ;
        int iRow=0, iCell=0 ;
        Double   fValue = new Double(0d) ;
        Integer  iValue = new Integer(0);
        DateFormat sdf = null ;
        Date   dValue ;        
        boolean bFocus = false ;
        String sep = "" + s.charAt(0);
        StringTokenizer st = new StringTokenizer(s,sep);
        s = s.substring(1,s.length());
        st = new StringTokenizer(s,sep);
        // row index
        if(st.hasMoreTokens()) s1 = st.nextToken() ;
        else return false ;
        // cell index
        if(st.hasMoreTokens()) s2 = st.nextToken() ;
        else return false ;
        // value
        if(st.hasMoreTokens()) s3 = st.nextToken() ;
        else return false ;      
        // focus
        if(st.hasMoreTokens())
        {
          s4 = st.nextToken() ;
          if(s4.equalsIgnoreCase("true")) bFocus = true ;
        }  
        try{
          iRow  = Integer.parseInt(s1);
          iCell = Integer.parseInt(s2);
        }
        catch(Exception e){
            System.out.println("SetCellValue: Unable to get row,cell ccordinate");
        }
        iRow--;
        iCell--;
        log("setCellValue() set value:"+s3+" for "+iRow+","+iCell);        
        if((iRow  < 0 || iRow  > iNbRows)
        || (iCell < 0 || iCell > iNbCols))
          return false ;
        CellProp cp = getCellProp(iCell);
        try{
        //
        // NUMBER column
        //
        if(coltypes[iCell].equalsIgnoreCase("NUMBER"))
        {
          if(!s3.equalsIgnoreCase(" "))
            fValue = new Double(Double.parseDouble(s3)) ;
          data[iRow][iCell] = fValue ;
        }
        //
        // INTEGER column
        //
        else if(coltypes[iCell].equalsIgnoreCase("INTEGER"))
        {
          if(!s3.equalsIgnoreCase(" "))
            iValue = new Integer(Integer.parseInt(s3)) ;
          data[iRow][iCell] = iValue ;
        }           
        //
        // DATE column
        //
        else if(coltypes[iCell].equalsIgnoreCase("DATE"))
        {
          if((cp.sFormat != null) && (!cp.sFormat.equalsIgnoreCase(" ")))
            sdf = new SimpleDateFormat(cp.sFormat);
          else
            sdf = new SimpleDateFormat(sDateFormat);
          if(!s3.equalsIgnoreCase(" ")) 
          {
           try{
             dValue = sdf.parse(s3); 
             data[iRow][iCell] = dValue ;
            } catch (Exception e){
                System.out.println("SetCellValue:Unable to format Date value:"+s3);
            };            
          }
        }
        // CHAR column
        else
          data[iRow][iCell] = s3 ;
        }
        catch(Exception e){System.out.println(property+":"+e.getMessage());}
        if(bFocus)
        {
          table.changeSelection(iRow,iCell,true,true);
          table.setRowSelectionInterval(iRow,iRow);          
          iRowPos = iRow; iCurRow = iRow ;
          iCellPos = iCell; iCurCell = iCell ;
        }    
        return true;
    }
    
    //
    // set the row properties
    //
    if (property == SETROWPROP) 
    {
      String s = value.toString();
      String s1="", s2="", s3="", s4="" ;
      int iVal = -1 ;
      StringTokenizer st = new StringTokenizer(s,"|");
      if(st.hasMoreTokens()) s1= st.nextToken() ;
      else return false ;
      if(st.hasMoreTokens()) s2 = st.nextToken() ;
      else return false ;
      if(s1.equalsIgnoreCase("HEIGHT"))
      {
         try { 
           iVal = Integer.parseInt(s2);
           if(iVal > 0) iRowHeight = iVal ;
         }
         catch(Exception e){ return false ;}        
      }
      return true ;
    }
    
    //
    // set the cell properties
    //
    if (property == SETCELLPROP) 
    {
      String sColName="" ;
      String s = value.toString();
      String s1="", s2="", s3="", s4="" ;
      int iVal = -1 ;
      StringTokenizer st = new StringTokenizer(s,"|");
      int iColPos = -1 ;
      if(st.hasMoreTokens()) sColName = st.nextToken() ;
      else return false ;
      if(st.hasMoreTokens()) s1 = st.nextToken() ;
      else return false ;
      if(st.hasMoreTokens()) s2 = st.nextToken() ;
      else return false ;
      if(st.hasMoreTokens()) s3 = st.nextToken() ;      
      if(st.hasMoreTokens()) s4 = st.nextToken() ;      
      log("prop="+s1+"  value:"+s2);
      // search column position
      for(int i=0; i<colnames.length;i++)
        {
          if(colnames[i].equalsIgnoreCase(sColName))
          {
            iColPos = i ;
            break;
          }
      }
      if(iColPos < 0)
      {
        System.out.println("Colulmn: "+sColName+" not found. Unable to set property");
        return false ; // column not found
      }  
      CellProp cp = (CellProp)hCellProps.get(sColName);
      if(cp != null)
      {
        // enable property
        if(s1.equalsIgnoreCase("ENABLE"))
        {
           if(s2.equalsIgnoreCase("true")) cp.bEnabled = true ; 
           else if(s2.equalsIgnoreCase("false")) cp.bEnabled = false ; 
        }
        // resizable property
        else if(s1.equalsIgnoreCase("RESIZE"))
        {
           if(s2.equalsIgnoreCase("true")) cp.bResize = true ; 
           else if(s2.equalsIgnoreCase("false")) cp.bResize = false ; 
        }
        // width property
        else if(s1.equalsIgnoreCase("WIDTH"))
        {
           try { 
             iVal = Integer.parseInt(s2);
             if(iVal >0) cp.iWidth = iVal ;
           }
           catch(Exception e){ return false ;}
        }
        // minimum width property
        else if(s1.equalsIgnoreCase("MIN_WIDTH"))
        {
           try { 
             iVal = Integer.parseInt(s2);
             if(iVal >0) cp.iMinWidth = iVal ;
           }
           catch(Exception e){ return false ;}
        }        
        // maximum width property
        else if(s1.equalsIgnoreCase("MAX_WIDTH"))
        {
           try { 
             iVal = Integer.parseInt(s2);
             if(iVal >0) cp.iMaxWidth = iVal ;
           }
           catch(Exception e){ return false ;}
        }        
        // height property
        else if(s1.equalsIgnoreCase("HEIGHT"))
        {
           try { 
             iVal = Integer.parseInt(s2);
             if(iVal >0) cp.iHeight = iVal ;
           }
           catch(Exception e){ return false ;}
        }
        // format property
        else if(s1.equalsIgnoreCase("FORMAT"))
        {
           cp.sFormat = s2 ;
        }
        // title property
        if(s1.equalsIgnoreCase("TITLE"))
        {
           cp.sHeader = s2 ;
        }
        // background color property
        else if(s1.equalsIgnoreCase("BG_COLOR"))
        {
           cp.cBack = getColor(s2) ;
        }
        // foreground color property
        else if(s1.equalsIgnoreCase("FG_COLOR"))
        {
           cp.cFore = getColor(s2) ;
        }                
        // alignment property
        else if(s1.equalsIgnoreCase("ALIGNMENT"))
        {
           if(s2.equalsIgnoreCase("LEFT"))        cp.iAlign = SwingConstants.LEFT ;
           else if(s2.equalsIgnoreCase("CENTER")) cp.iAlign = SwingConstants.CENTER ;
           else if(s2.equalsIgnoreCase("RIGHT"))  cp.iAlign = SwingConstants.RIGHT ;
        }      
        // font property
        else if(s1.equalsIgnoreCase("FONT"))
        {
           int iFontSize ;
           Font fFont ;
           try{ iFontSize= Integer.parseInt(s3) ;}
           catch (Exception e){ return false ;}
           int iWeight = Font.PLAIN ;
           if( s4.equalsIgnoreCase("N")) iWeight = Font.PLAIN ;
           else if( s4.equalsIgnoreCase("B"))  iWeight = Font.BOLD ;
           else if( s4.equalsIgnoreCase("I"))  iWeight = Font.ITALIC ;
           else if( s4.equalsIgnoreCase("BI")) iWeight = Font.BOLD + Font.ITALIC ; 
           if( s2 != null ) 
           { 
             try{
                fFont = new Font(s2, iWeight, iFontSize) ; 
                cp.fFont = fFont ;
                fColFont[iColPos] = fFont ;
             }
             catch (Exception e) {
               System.out.println("SetCellProperty:Unable to set Font:"+value);
             };
           }           
        }                
        
        hCellProps.put(sColName,cp);
      }
      else
          System.out.println("Header column not found: "+sColName);
      return true ;
    }

    //
    // set the data
    //
    else if (property == SETDATA) 
    {
      String label = value.toString();
      StringTokenizer st ;
      String sValue ;
      String sFormatedValue = "" ;
      Double   fValue = new Double(0d) ;
      Integer  iValue = new Integer(0);
      DateFormat sdf = null ;
      Date   dValue ;
      int i = 0 ;
      st = new StringTokenizer(label, separator);
      while (st.hasMoreTokens()) {
         sValue = st.nextToken() ;
         fValue = null ;
         dValue = null ;
         iValue = null;
         CellProp cp = getCellProp(i);

         try{
         //
         // IMAGE column
         //
         if(coltypes[i].equalsIgnoreCase("IMAGE"))
         {
           //data[iCurLine][i] = new ImageIcon();
         }
         //
         // NUMBER column
         //
         else if(coltypes[i].equalsIgnoreCase("NUMBER"))
         {
           if(!sValue.equalsIgnoreCase(" "))
             fValue = new Double(Double.parseDouble(sValue)) ;
           data[iCurLine][i] = fValue ;
           sFormatedValue = fValue.toString() ;
         }
         //
         // INTEGER column
         //
         else if(coltypes[i].equalsIgnoreCase("INTEGER"))
         {
           if(!sValue.equalsIgnoreCase(" "))
             iValue = new Integer(Integer.parseInt(sValue)) ;
           data[iCurLine][i] = iValue ;
           sFormatedValue = iValue.toString() ;
         }           
         //
         // DATE column
         //
         else if(coltypes[i].equalsIgnoreCase("DATE"))
         {
           if(cp.sFormat != null)
             sdf = new SimpleDateFormat(cp.sFormat);
           else
             sdf = new SimpleDateFormat(sDateFormat);
           if(!sValue.equalsIgnoreCase(" ")) 
           {
            try{
              dValue = sdf.parse(sValue); 
              data[iCurLine][i] = dValue ;
              sFormatedValue = sValue ;
             } catch (Exception e){
                 System.out.println("SetData:Unable to format Date value:"+sValue);
             };            
           }
         }
         // CHAR column
         else
          {
           data[iCurLine][i] = sValue ;
           sFormatedValue = sValue ;
          }
         // real data width
         FontMetrics fm = getFontMetrics(fColFont[i]);
	       int width = fm.stringWidth( sFormatedValue );
         if(width > iColWidth[i])
         {
           iColWidth[i] = width ;
         }
         }
         catch(Exception e){System.out.println(property+":"+e.getMessage());}
         i++;
      }
      iCurLine++ ;

      return true;
    }
    //
    // set the default date format
    //
    else if (property == SETDATEFORMAT)
    {
      sDateFormat = (String)value ;
      return true ;
    }    
    //
    // set the default number format
    //
    else if (property == SETNUMFORMAT)
    {
      sNumFormat = (String)value ;
      return true ;
    }    
    //
    // set the default integer format
    //
    else if (property == SETINTFORMAT)
    {
      sIntFormat = (String)value ;
      return true ;
    }        
    //
    // add a blank row
    //
    else if (property == ADD_ROW) 
    {
      //model.insertRow(0, new Object[]{""});
      return true ;
    }
    //
    // set the log trace
    //
    else if (property == SETLOG) 
    {
      if(value.toString().equalsIgnoreCase("true")) bLog = true ;
      else bLog = false ;
      return true ;
    }
    //
    // set the vertical lines
    //
    else if (property == SETVLINE) 
    {
      if(value.toString().equalsIgnoreCase("true")) table.setShowVerticalLines(true);
      else if(value.toString().equalsIgnoreCase("false")) table.setShowVerticalLines(false);
      return true ;
    }    
    //
    // set the vertical lines
    //
    else if (property == SETHLINE) 
    {
      if(value.toString().equalsIgnoreCase("true")) table.setShowHorizontalLines(true);
      else if(value.toString().equalsIgnoreCase("false")) table.setShowHorizontalLines(false);
      return true ;
    }    
    //
    // set the title
    //
    else if (property == SETTITLE) 
    {
      sTitle = value.toString();
      return true ;
    }
    //
    // set the reorder flag
    //
    else if (property == SETREORDER) 
    {
      String s = value.toString();
      if(s.equalsIgnoreCase("true"))       bReorder = true ;
      else if(s.equalsIgnoreCase("false")) bReorder = false ;
      return true ;
    }    
    //
    // set the resize flag
    //
    else if (property == SETRESIZE) 
    {
      String s = value.toString();
      if(s.equalsIgnoreCase("true"))       bResize = true ;
      else if(s.equalsIgnoreCase("false")) bResize = false ;
      return true ;
    }        
    //
    // set the array size
    //
    else if (property == SETARRAYSIZE) // set the number of columns
    {                                  // (nbCols, nbRows)
      String label = value.toString();
      StringTokenizer st ;
      st = new StringTokenizer(label,",");
      x = Integer.parseInt(st.nextToken()) ;
      y = Integer.parseInt(st.nextToken()) ;
      iNbCols = ( x > 0 ? x : 1 );
      iNbRows = ( y > 0 ? y : 1 );      
      colnames = new String[iNbCols] ;
      coltypes = new String[iNbCols] ;
      iColWidth = new int[iNbCols] ;
      fColFont  = new Font[iNbCols] ;
      data = new Object[iNbRows][iNbCols] ;
      for(int i =0; i<iNbCols;i++)
      {
        coltypes[i]  = "CHAR" ;
        iColWidth[i] = 0 ;
        fColFont[i]  = table.getFont();
      }  
      log("ArraySize : "+iNbCols+" columns  "+iNbRows+" rows");
      return true ;
    }        
    //
    // set the frame bounds
    //
    else if (property == SETBOUNDS) 
    {
      String label = value.toString();
      StringTokenizer st ;
      st = new StringTokenizer(label,",");
      x = Integer.parseInt(st.nextToken()) ;
      y = Integer.parseInt(st.nextToken()) ;
      w = Integer.parseInt(st.nextToken()) ;
      h = Integer.parseInt(st.nextToken()) ;     
      log("x="+x+" y="+y+" w="+w+" h="+h);
      return true ;
    }    
    //
    // set the selection background color
    //
    else if (property == SETSELECTBACK) 
    {
      SelBGColor = getColor(value.toString()) ;
      table.setSelectionBackground(SelBGColor);
      return true ;
    }
    //
    // set the selection foreground color
    //
    else if (property == SETSELECTFORE) 
    {
      SelFGColor = getColor(value.toString()) ;
      table.setSelectionForeground(SelFGColor);      
      return true ;
    } 
    //    
    // set the header background color
    //
    else if (property == SETHEADBG) 
    {
      HeadBGColor = getColor(value.toString()) ;
      return true ;
    }
    //
    // set the header foreground color
    //
    else if (property == SETHEADFG) 
    {
      HeadFGColor = getColor(value.toString()) ;
      return true ;
    }    
    //
    // set the header background color
    //
    else if (property == SETDATABG) 
    {
      DataBGColor = getColor(value.toString()) ;
      return true ;
    }
    //
    // set the header foreground color
    //
    else if (property == SETDATAFG) 
    {
      DataFGColor = getColor(value.toString()) ;
      return true ;
    } 
    //
    // set the grid color
    //
    else if (property == SETGRIDFG) 
    {
      GridColor = getColor(value.toString()) ;
      return true ;
    } 
    //
    // can update the table ?
    //
    else if (property == SETUPDATE) 
    {
      if( value.toString().toUpperCase().equals("TRUE") )
        bUpdatable = true ;
      return true ;
    } 
    //
    // raz the values
    //
    else if (property == INIT) 
    {
      raz() ;
      return true ;
    } 
    //
    // set the separator character
    //
    else if (property == SETSEPARATOR) 
    {
      separator = value.toString() ;
      return true ;
    } 
    //
    // get the value of a particular cell
    //
    else if (property == SETCELLPOS) 
    {
      StringTokenizer st ;
      int row, cell ;
      st = new StringTokenizer(value.toString(),",");
      row  = Integer.parseInt(st.nextToken()) ;
      cell = Integer.parseInt(st.nextToken()) ;
      if( ((row < 0)  || (row > table.getRowCount()))  ||
          ((cell < 0) || (cell > table.getColumnCount())) )
      {
        return false ;
      }
      else
      { 
        iRowPos = row - 1;
        iCellPos = cell - 1 ;
        iCurRow = iRowPos ;
        iCurCell = iCellPos ;
      }
      log("SETCELLPOS row="+iCurRow+" cell="+iCurCell);
      table.changeSelection(iRowPos,iCellPos,true,true);
      return true ;
    }     
    //
    // set the pointer on a particular row
    //
    else if (property == SETROWPOS) 
    {
      try{
        iRowPos = Integer.parseInt(value.toString()) ;
      }
      catch(Exception e)
      {
        System.out.println("setRowPos : Unable to set Row position");
        return false ;
      }
      if( (iRowPos < 1) || (iRowPos > table.getRowCount()) ) return false ;
      else iRowPos-- ;
      iCurRow = iRowPos ;
      table.changeSelection(iRowPos,iCellPos,true,true);
      table.setRowSelectionInterval(iRowPos,iRowPos);
      return true ;
    }    
    //
    // set the locale
    //
    else if (property == SETLOCALE)     
    {
      try
      {
        locale = new Locale(value.toString());
        Locale.setDefault(locale);
        DecimalSymbols = new DecimalFormatSymbols(locale); 
      }
      catch (Exception e) {System.out.println("Unable to set locale:"+value);}
      return true;
    }
    //
    // set the decimal separators
    //
    else if (property == SETDECSEPARATORS)     
    {
      String label = value.toString();
      char c1 = label.charAt(0) ; 
      char c2 = label.charAt(1) ;
      DecimalSymbols.setDecimalSeparator(c1);
      DecimalSymbols.setGroupingSeparator(c2);
      return true ;
    }
    
    //
    // show the JTable
    // 
    else if (property == SHOW) 
    {
        TableColumn tabcol = null ; 
        model = new MyTableModel(data,colnames) ;
        table.setModel(model); 
        // set the reorder flag
        table.getTableHeader().setReorderingAllowed(bReorder);
        // set the resize flag
        table.getTableHeader().setResizingAllowed(bResize);
        // set the row height
        if(iRowHeight > 0) table.setRowHeight(iRowHeight);
        
        // set special cell format
        for(int z=0; z<colnames.length; z++)
        {
          CellProp cp = getCellProp(z) ;
          tabcol = table.getColumnModel().getColumn(z) ;
          // adjust cell width
          tabcol.setPreferredWidth(iColWidth[z]+15);
          if(coltypes[z].equalsIgnoreCase("IMAGE"))
          {
            tabcol.setCellRenderer(new ImageTableRenderer());
          }
          // general properties
          if(cp != null)
          {
            if(cp.iWidth > -1) tabcol.setPreferredWidth(cp.iWidth);
            if(cp.iMinWidth > -1) tabcol.setMinWidth(cp.iMinWidth);
            if(cp.iMaxWidth > -1) tabcol.setMaxWidth(cp.iMaxWidth);
            if(cp.sHeader != null) tabcol.setHeaderValue(cp.sHeader);
            tabcol.setResizable(cp.bResize);
          }
          if(cp.sFormat != null)
          {
            log("set format for "+colnames[z]+" format:"+cp.sFormat);
            if(coltypes[z].equalsIgnoreCase("DATE"))
            {
              DateColumnFormat dateColumnFormat = new DateColumnFormat(cp.sFormat,cp.sFormat,colnames[z]); 
              tabcol.setCellRenderer(dateColumnFormat.getRenderer());
              tabcol.setCellEditor(dateColumnFormat.getEditor());
            }
            else if(coltypes[z].equalsIgnoreCase("NUMBER"))
            {
              NumberColumnFormat numColumnFormat = new NumberColumnFormat(cp.sFormat,cp.sFormat); 
              tabcol.setCellRenderer(numColumnFormat.getRenderer());
              tabcol.setCellEditor(numColumnFormat.getEditor());
            }
            else if(coltypes[z].equalsIgnoreCase("INTEGER"))
            {
              tabcol.setCellRenderer(new IntegerRenderer(cp.sFormat));
            }            
          }
          else
          {
            if(coltypes[z].equalsIgnoreCase("DATE"))
            {
              DateColumnFormat dateColumnFormat = new DateColumnFormat(sDateFormat,sDateFormat,colnames[z]); 
              tabcol.setCellRenderer(dateColumnFormat.getRenderer());
              tabcol.setCellEditor(dateColumnFormat.getEditor());
            }  
            else if(coltypes[z].equalsIgnoreCase("NUMBER"))
            {
              NumberColumnFormat numColumnFormat = new NumberColumnFormat(sNumFormat,sNumFormat,colnames[z]); 
              tabcol.setCellRenderer(numColumnFormat.getRenderer());
              tabcol.setCellEditor(numColumnFormat.getEditor());            
            }
            else if(coltypes[z].equalsIgnoreCase("INTEGER"))
            {
              tabcol.setCellRenderer(new IntegerRenderer(sIntFormat,colnames[z]));
            }             
            else if(coltypes[z].equalsIgnoreCase("CHAR"))
            {
              tabcol.setCellRenderer(new CharRenderer(colnames[z]));
            }             
          }
        }
                
        iRowsChanged = new int[iNbRows]; 
        
        // seperate frame ?
        log("seperate="+value.toString().toUpperCase());
        if( value.toString().toUpperCase().equals("TRUE") )
          bSeperateFrame = true ;

        if( HeadBGColor != null )
          table.getTableHeader().setBackground(HeadBGColor);
        if( HeadFGColor != null )          
          table.getTableHeader().setForeground(HeadFGColor);
        if( DataBGColor != null )
          table.setBackground(DataBGColor);
        if( DataFGColor != null )          
          table.setForeground(DataFGColor);          
        if( GridColor != null )                    
          table.setGridColor(GridColor);
        if( bUpdatable )
          table.setEnabled(true);
        else
          table.setEnabled(false);

        table.setRowSelectionAllowed(true);
        // set the focus on current cell
        table.changeSelection(iCurRow,iCurCell,true,true);
        table.setRowSelectionInterval(iRowPos,iRowPos);
        
        //
        // add a mouse and key listener to the table
        //
        try{
          table.removeKeyListener(kl);
          table.removeMouseListener(ml);
        }
        catch(Exception e){}
        table.addKeyListener(kl);
        table.addMouseListener(ml);

        scrollPane.repaint();

        // if Seperate frame
        if( bSeperateFrame )
        {
          frame = new JFrame();
          frame.setTitle(sTitle);
          frame.setContentPane(contentpane);
          frame.setBounds(x,y,w,h);
          frame.pack();
          frame.setVisible(true);
          //frame.show() ;
        }
      return true ;
    }
    else
    {
     return super.setProperty(property, value);
    }
  }

   /*---------------------------------------*
    *   create a KeyListener for the table
    *---------------------------------------*/
   void setKeyListener()
   {
        kl = new KeyListener(){
	       public void keyPressed(KeyEvent e) {
           int key = e.getKeyCode() ;
           log( "Key:    " + key);
           int modifiersEx;           
           if(System.getProperty("java.version").startsWith("1.3"))
             modifiersEx = e.getModifiers();
           else
             modifiersEx = e.getModifiersEx();
           log("ActionKey:"+e.isActionKey());
           switch(key)
           {
             case KeyEvent.VK_PAGE_DOWN: break;
             case KeyEvent.VK_PAGE_UP: break;
             case KeyEvent.VK_HOME: 
               if(modifiersEx != KeyEvent.CTRL_DOWN_MASK)
               {
                 iCurCell = 0 ; 
                 SendMessage(TRG_WNII, ""+(iCurCell+1)); 
               }  
               break ;
             case KeyEvent.VK_END: 
               if(modifiersEx != KeyEvent.CTRL_DOWN_MASK)
               {               
                 iCurCell = table.getColumnCount()-1 ; 
                 SendMessage(TRG_WNII, ""+(iCurCell+1));
               }  
               break ;
             case KeyEvent.VK_UP: 
                if(iCurRow > 0) 
                { 
                  iCurRow-- ; 
                  SendMessage(TRG_WNRI, ""+(iCurRow+1)); 
                  SendMessage(TRG_WNII, ""+(iCurCell+1));
                } break ;
             case KeyEvent.VK_DOWN: 
                if(iCurRow < table.getRowCount()) 
                { 
                  iCurRow++ ; 
                  SendMessage(TRG_WNRI, ""+(iCurRow+1));
                  SendMessage(TRG_WNII, ""+(iCurCell+1));
                } break ;
             case KeyEvent.VK_RIGHT:
                  if(iCurCell < table.getColumnCount()-1) 
                  { 
                    iCurCell++ ; SendMessage(TRG_WNII, ""+(iCurCell+1)); 
                  }
                  break ;
             case KeyEvent.VK_LEFT:
                  if(iCurCell > 0)
                  { 
                    iCurCell-- ; SendMessage(TRG_WNII, ""+(iCurCell+1)); 
                  }
                  break ;
             default: // send key to Forms
                  if(  
                        (key == KeyEvent.VK_TAB) 
                     || (key >= KeyEvent.VK_F1 && key <= KeyEvent.VK_F24) 
                     || (e.isActionKey())
                    )
                  {
                      try
                       {
                         m_handler.setProperty(KEY_EVENT, e);
                       }
                       catch ( Exception ex ){ System.out.println("Unable to send key to Forms");}                
                  }
           }
           }
           public void keyReleased(KeyEvent e) {
           }
           public void keyTyped(KeyEvent e) {
           }
        };             
   }
   
   /*-----------------------------------------*
    *   create a MouseListener for the table
    *-----------------------------------------*/
   void setMouseListener()
   {
         ml = new MouseListener(){
          public void mouseClicked (MouseEvent me) 
          {
            int iButton = 1 ;
            if(System.getProperty("java.version").startsWith("1.3"))
              iButton = 1 ;
            else
              iButton = me.getButton() ;
            if(me.getClickCount() > 1)
              // send multiple click event
              SendMessage(TRG_WMDC, ""+iButton);
            else
              // send single click event
              SendMessage(TRG_WMC, ""+iButton);
            
          }
          public void mouseEntered (MouseEvent me) {}
          public void mousePressed (MouseEvent me) 
          {
           //int iBut = me.getButton() ;
           int iRow = table.rowAtPoint(me.getPoint());
           int iCell = table.columnAtPoint(me.getPoint());
           if(iRow != iCurRow)
           {
             iCurRow = iRow ;
             SendMessage(TRG_WNRI, ""+(iCurRow+1));
           }
           if(iCell != iCurCell)
           {
             iCurCell = iCell ;
             SendMessage(TRG_WNII, ""+(iCurCell+1));
           }           
           log( "Row:  " + iCurRow );
           log( "Col:  " + iCurCell );                   
          }
          public void mouseReleased (MouseEvent me) {} 
          public void mouseExited (MouseEvent me) {} 
        };     
   }
   
   /*-----------------------*
    *  Get the properties
    *-----------------------*/
    public Object getProperty(ID pId) // Get the current cell value
    {
      
      //
      // get the current cell value
      //
      if (pId == GETCELLVAL)
      {
        sCellValue = "" ;
        String sValue = "" ;
        log("GetCellVal:"+iCellPos);
        DateFormat df = new SimpleDateFormat(sDateFormat);
        DecimalFormat nf = new DecimalFormat(sNumFormat,DecimalSymbols);
        Double db = null ;
        if( (iRowPos > -1) && (iCellPos > -1) )
        {
          if(coltypes[iCellPos].equalsIgnoreCase("DATE"))
          {
            Date d = (Date)data[iRowPos][iCellPos] ;
            sValue += df.format(d);
          }
          else if(coltypes[iCellPos].equalsIgnoreCase("NUMBER"))
          {
            Double f = (Double)data[iRowPos][iCellPos] ;
            if(f == null) sValue += "null";
            else 
            {
              if(data[iRowPos][iCellPos] instanceof Long) db = Double.valueOf(data[iRowPos][iCellPos].toString());
              else db = (Double)data[iRowPos][iCellPos] ;
              sValue += nf.format(db);
            }  
          }
          else if(!coltypes[iCellPos].equalsIgnoreCase("IMAGE"))
            sValue += data[iRowPos][iCellPos] ; 
          return "" + sValue ;    
        }  
        return "" ;
      }
      //
      // get the current row values
      //
      else if (pId == GETROWVAL) 
      {
        StringBuffer sb = new StringBuffer();
        DateFormat df = new SimpleDateFormat(sDateFormat);
        DecimalFormat nf = new DecimalFormat(sNumFormat,DecimalSymbols);
        Double db = null ;
        if( iRowPos > -1 )
        {
          for( int i=0 ; i<table.getColumnCount(); i++ )
          {
            db = null ;
            CellProp cp = getCellProp(i) ;
            if( (i>0) && (!coltypes[i].equalsIgnoreCase("IMAGE"))) sb.append(separator);
            if(coltypes[i].equalsIgnoreCase("DATE"))
            {
              if(cp.sFormat != null) df = new SimpleDateFormat(cp.sFormat);
              else df = new SimpleDateFormat(sDateFormat);
              if(data[iRowPos][i] == null) sb.append("null");
              else
              {
                Date d = (Date)data[iRowPos][i] ;
                sb.append(df.format(d));
              }  
            }
            else if(coltypes[i].equalsIgnoreCase("NUMBER"))
            {
              if(cp.sFormat != null) nf = new DecimalFormat(cp.sFormat,DecimalSymbols);
              else nf = new DecimalFormat(sNumFormat,DecimalSymbols);
              if(data[iRowPos][i] == null || data[iRowPos][i].equals(" ")) sb.append("null");
              else 
              {
                if(data[iRowPos][i] instanceof Long) db = Double.valueOf(data[iRowPos][i].toString());
                else db = (Double)data[iRowPos][i] ;
                sb.append(nf.format(db));
              }  
            }
            else if(!coltypes[i].equalsIgnoreCase("IMAGE")) sb.append(data[iRowPos][i]);
          }
        }
        return sb.toString();
      }      
      //
      // get the list of updated rows
      //
      else if (pId == GETROWSCHANGED) 
      {
        boolean bFirst = true ;
        StringBuffer sb = new StringBuffer();
        for(int i=0 ; i<iRowsChanged.length;i++)
        {
          if(iRowsChanged[i] > 0)
          {
           if(bFirst) {bFirst=false ;sb.append(""+i);}
           else sb.append(","+i);
          }
        }
        return sb.toString() ;
      }
      else
      {
        return super.getProperty(pId);
      }
    } 

    // expects r,g,b values separated by commas  
    public Color getColor(String colourValue) 
    {    
      try{      
        int r,g,b;      
        int rPos, gPos;      
        rPos = colourValue.indexOf(",");      
        gPos = colourValue.indexOf(",", rPos + 1);      
        if (rPos < 1 || gPos < 1 || gPos + 1 == colourValue.length()) {        
            throw new Exception("Invalid colour");
        }      
        r = Integer.parseInt(colourValue.substring(0, rPos));      
        g = Integer.parseInt(colourValue.substring(rPos + 1, gPos));      
        b = Integer.parseInt(colourValue.substring(gPos + 1));        
        if (r < 0 || r > 255 || g < 0 || g > 255 || b < 0 || b > 255) {        
           throw new Exception("Invalid colour");
        } 
    
        return new Color(r,g,b);
       } 
      catch(Exception e) {      
        return new Color(0,0,0);
      }  
    } 

    /*----------------------*
     *  reset the variables
     *----------------------*/
    public void raz()
    {
        log("*** raz ***");
        x=10; y=10; w=500; h=100 ;
        iNbRows = 0; iNbCols = 0 ;
        iCurLine = 0 ;
        iRowPos = iCellPos = 0 ;
        iCurCell = iCurRow = 0 ;
        sTitle = "" ; separator = "^" ;
        HeadBGColor =  HeadFGColor = DataBGColor=  DataFGColor =  GridColor = null ;
        bSeperateFrame = false ;
        bUpdatable = false ;
    }


 /*---------------------------------------
  *  TableModel class to allow updates
  *--------------------------------------*/
 class MyTableModel extends AbstractTableModel {


        private String[] columnNames = {" "};
        private Object[][] datas = {{" "," "}};
        
        public MyTableModel()
        {
          super();
        }
        
        public MyTableModel(Object[][] dataVector,Object[] columnIdentifiers)
        {
            super();
            columnNames = (String[])columnIdentifiers ;
            datas = dataVector;
        }
        
        public int getColumnCount() {
            return columnNames.length;
        }

        public int getRowCount() {
            if (datas != null) return datas.length;
            else return 0;
        }

        public String getColumnName(int col) {
            return columnNames[col];
        }

        public Object getValueAt(int row, int col) {
            return datas[row][col];
        }
        
        public void setDataVector(Object[][] dataVector,
                          Object[] columnIdentifiers) {
            columnNames = (String[])columnIdentifiers ;
            datas = dataVector;
        }

        public Class getColumnClass(int c) {
            Object o = getValueAt(0, c);
            if(o == null) {
                if("INTEGER".equalsIgnoreCase(coltypes[c])) return Integer.class;
                else if("DATE".equalsIgnoreCase(coltypes[c])) return Date.class;
                else return Double.class;
            }
            return o.getClass();
        }

        public boolean isCellEditable(int row, int col) {
            CellProp cp = (CellProp)hCellProps.get(colnames[col]);
            if (!cp.bEnabled) {
                return false;
            } else {
                return true;
            }
        }

        public void setValueAt(Object value, int row, int col) {
            datas[row][col] = value;
            iRowsChanged[row] = 1 ;
            SendMessage(TABLE_EVENT, ""+(row+1)+","+(col+1));

        }
        
        private void printDebugData() {
            int numRows = getRowCount();
            int numCols = getColumnCount();

            for (int i=0; i < numRows; i++) {
                log("    row " + i + ":");
                for (int j=0; j < numCols; j++) {
                    log("  " + data[i][j]);
                }
                log("");
            }
            log("--------------------------");
        }

    }

  
  /*-------------------------------
   *  send message back to Forms
   *------------------------------*/
  public void SendMessage( ID id1, String sMessage )
  {
    try{
      CustomEvent ce = new CustomEvent(m_handler, id1);
      m_handler.setProperty( TABLE_EVENT_MSG, sMessage );
      dispatchCustomEvent(ce);  
    }
    catch (Exception e)
    {
      e.printStackTrace();
    }    
  }

    
  void log(String sMessage)
  {
    if(bLog) System.out.println(sMessage);
  }

  class ImageTableRenderer extends DefaultTableCellRenderer {
    public Component getTableCellRendererComponent
    (
       JTable table,
       Object value,
       boolean isSelected,
       boolean hasFocus,
       int row,
       int column
    ) 
    {
      ImageIcon icon = (ImageIcon)value;
      if(icon != null)
      {
        setIcon(icon);
        setSize(icon.getIconWidth(),icon.getIconHeight());
        setHorizontalAlignment(SwingConstants.LEFT);
      }
      return this;
    }
  }

 
  /*---------------------------
   *  set the Integer renderer
   *-------------------------*/  
  class IntegerRenderer extends DefaultTableCellRenderer {
      NumberFormat nf = NumberFormat.getInstance();
      String sFormat = sIntFormat ;
      String sColName = null ;
      
      public IntegerRenderer() { super(); }
      
      public IntegerRenderer(String sFormat) 
      { 
        super(); 
        this.sFormat = sFormat;
      }
      
      public IntegerRenderer(String sFormat, String sCol) 
      { 
        super(); 
        this.sFormat = sFormat;
        this.sColName = sCol ;
      }      
  
      public void setValue(Object value) {
          String s = "" ;
          setHorizontalAlignment(RIGHT);
          if(sColName != null)
          {
            CellProp cp = (CellProp)hCellProps.get(sColName);
            if(cp != null)
            {
              if(cp.cBack != null) setBackground(cp.cBack);
              if(cp.cFore != null) setForeground(cp.cFore);
              if(cp.iAlign != -1)  setHorizontalAlignment(cp.iAlign);
              if(cp.fFont != null) setFont(cp.fFont);
            }
          }
          if (sFormat.equalsIgnoreCase("")) {
              s = (value == null) ? "" : value.toString() ;
          }
          else
          {
             nf = new DecimalFormat(sFormat);
             s = (value == null) ? "" : nf.format(value) ;
          }   
          setText((value == null) ? "" : s);
      }
  }

    /*---------------------------
     *  set the Char renderer
     *-------------------------*/  
    class CharRenderer extends DefaultTableCellRenderer {
        String sFormat = sIntFormat ;
        String sColName = null ;
        
        public CharRenderer() { super(); }
        
        public CharRenderer(String sCol) 
        { 
          super(); 
          this.sColName = sCol ;
        }

        public void setValue(Object value) {
            String s = "" ;
            setHorizontalAlignment(RIGHT);
            if(sColName != null)
            {
              CellProp cp = (CellProp)hCellProps.get(sColName);
              if(cp != null)
              {
                if(cp.cBack != null) setBackground(cp.cBack);
                if(cp.cFore != null) setForeground(cp.cFore);
                if(cp.iAlign != -1)  setHorizontalAlignment(cp.iAlign);
                if(cp.fFont != null) setFont(cp.fFont);
              }
              else{System.out.println("--> CharRenderer.setValue "+sColName+" cp not found ***");}
            }
            else{System.out.println("--> CharRenderer.setValue : sColName = NULL ***");}
            s = (value == null) ? "" : value.toString() ;
            /*
            if (sFormat.equalsIgnoreCase("")) {
                s = (value == null) ? "" : value.toString() ;
            }
            else
            {
               nf = new DecimalFormat(sFormat);
               s = (value == null) ? "" : nf.format(value) ;
            } 
            */
            setText((value == null) ? "" : s);
        }
    }
 
  /*-----------------------------------
   *  Class to render the Date values
   *----------------------------------*/
  class DateColumnFormat { 
      private SimpleDateFormat formatterR, formatterE; 
      private DefaultTableCellRenderer renderer; 
      private DefaultCellEditor editor; 
      private String sColName = null ;

      public DateColumnFormat(String pattern, String sCol){ 
          this(pattern, pattern,sCol); 
      } 

      public DateColumnFormat(String patternR, String patternE, String sCol){ 
          if(patternR == null) patternR = sDateFormat; 
          formatterR = new SimpleDateFormat(patternR); 
          formatterR.setLenient(false); 
          if(patternE == null) patternE = sDateFormat; 
          formatterE = new SimpleDateFormat(patternE); 
          formatterE.setLenient(false); 
          renderer = new DateRenderer(); 
          editor = new DateEditor(); 
          sColName = sCol ;
      } 
      
      public DefaultTableCellRenderer getRenderer(){ 
          return renderer; 
      } 

      public DefaultCellEditor getEditor(){ 
          return editor; 
      } 

      private class DateRenderer extends DefaultTableCellRenderer { 
          public DateRenderer() { 
              super();
          } 

      public void setValue(Object value) { 
              setHorizontalAlignment(CENTER);
              if(sColName != null)
              {
                CellProp cp = (CellProp)hCellProps.get(sColName);
                if(cp != null)
                {
                  if(cp.cBack != null) setBackground(cp.cBack);
                  if(cp.cFore != null) setForeground(cp.cFore);
                  if(cp.iAlign != -1)  setHorizontalAlignment(cp.iAlign);
                  if(cp.fFont != null) setFont(cp.fFont);
                }
              }
              setText((value == null) ? "" : formatterR.format(value)); 
          } 
      } 

      private class DateEditor extends DefaultCellEditor { 
          public DateEditor() { 
              super(new JTextField()); 
          } 

          public boolean stopCellEditing() { 
              String value = ((JTextField)getComponent()).getText(); 
              if(!value.equals("")) { 
                  try { 
                      formatterE.parse(value); 
                  } catch (ParseException e) { 
                      ((JComponent)getComponent()).setBorder(new LineBorder(Color.red)); 
                      return false; 
                  } 
              } 
              return super.stopCellEditing(); 
          } 
          public Component getTableCellEditorComponent(final JTable table, final Object value, 
          final boolean isSelected, final int row, final int column) { 
              JTextField tf =((JTextField)getComponent()); 
              tf.setBorder(new LineBorder(Color.black));                     
              try { 
                  tf.setText(formatterE.format(value)); 
              } catch (Exception e) { 
                  tf.setText(""); 
              } 
              return tf; 
          } 
          public Object getCellEditorValue() { 
              try { 
                  Date value = formatterE.parse(((JTextField)getComponent()).getText()); 
                  return value; 
              } catch (ParseException ex) { 
                  return null; 
              } 
          } 
      } 
   }



  /*-------------------------------------
   *  Class to render the Number values
   *------------------------------------*/
  class NumberColumnFormat { 
      private DecimalFormat formatterR, formatterE; 
      private DefaultTableCellRenderer renderer; 
      private DefaultCellEditor editor; 
      private String sColName = null ;

      public NumberColumnFormat(){ 
          this(null,null,null); 
      } 

      public NumberColumnFormat(String pattern, String sCol){ 
          this(pattern, pattern, sCol); 
      } 

      public NumberColumnFormat(String patternR, String patternE, String sCol){ 
          String spatR = patternR == null ? sNumFormat : patternR ;
          String spatE = patternE == null ? sNumFormat : patternE ;
          formatterR = new DecimalFormat(spatR,DecimalSymbols); 
          formatterE = new DecimalFormat(spatE,DecimalSymbols); 
          renderer = new NumRenderer(); 
          editor = new NumEditor(); 
          sColName = sCol ;
      } 

      public DefaultTableCellRenderer getRenderer(){ 
          return renderer; 
      } 

      public DefaultCellEditor getEditor(){ 
          return editor; 
      } 

      private class NumRenderer extends DefaultTableCellRenderer { 
          public NumRenderer() { 
              super();
          } 

      public void setValue(Object value) { 
              setHorizontalAlignment(RIGHT);
              if(sColName != null)
              {
                CellProp cp = (CellProp)hCellProps.get(sColName);
                if(cp != null)
                {
                  if(cp.cBack != null) setBackground(cp.cBack);
                  if(cp.cFore != null) setForeground(cp.cFore);
                  if(cp.iAlign != -1)  setHorizontalAlignment(cp.iAlign);
                  if(cp.fFont != null) setFont(cp.fFont);
                }
              }
              setText((value == null) ? "" : formatterR.format(value)); 
          } 
      } 

      private class NumEditor extends DefaultCellEditor { 
          public NumEditor() { 
              super(new JTextField()); 
          } 

          public boolean stopCellEditing() { 
              String value = ((JTextField)getComponent()).getText(); 
              if(!value.equals("")) { 
                  try { 
                      formatterE.parse(value); 
                  } catch (ParseException e) { 
                      ((JComponent)getComponent()).setBorder(new LineBorder(Color.red)); 
                      return false; 
                  } 
              } 
              return super.stopCellEditing(); 
          } 
          public Component getTableCellEditorComponent(final JTable table, final Object value, 
          final boolean isSelected, final int row, final int column) { 
              JTextField tf =((JTextField)getComponent()); 
              tf.setBorder(new LineBorder(Color.black)); 
              try { 
                  tf.setText(formatterE.format(value)); 
              } catch (Exception e) { 
                  tf.setText(""); 
              } 
              return tf; 
          } 
          public Object getCellEditorValue() { 
              try { 
                  Number value = formatterE.parse(((JTextField)getComponent()).getText()); 
                  return value; 
              } catch (ParseException ex) { 
                  return null; 
              } 
          } 
      } 
    }


    /*-----------------------------------------*
     *   Object to handle cell properties      *
     *-----------------------------------------*/
    class CellProp extends Object 
    {
        public String      sName      = "" ;
        public String      sHeader    = null ;        
        public boolean     bEnabled   = true ;
        public boolean     bResize    = true ;        
        public String      sFormat    = null ;
        public int         iAlign     = -1 ;
        public int         iWidth     = -1 ;
        public int         iMinWidth  = -1 ;
        public int         iMaxWidth  = -1 ;
        public int         iHeight    = -1 ;        
        public Color       cBack      = null ;
        public Color       cFore      = null ;
        public Font        fFont      = null ;
        
        CellProp(String sName) { this.sName = sName ; }
    }    

    CellProp getCellProp( int iNumCol )
    {
      String sColName = colnames[iNumCol] ;
      return (CellProp)hCellProps.get(sColName);
    }
    
    /*----------------------------
     *  Table selection listener
     *---------------------------*/
    class SharedListSelectionHandler implements ListSelectionListener {
            public void valueChanged(ListSelectionEvent e) { 
                ListSelectionModel lsm = (ListSelectionModel)e.getSource();
                if(lsm.getMinSelectionIndex() >= 0)
                {
                  iCurRow = lsm.getMinSelectionIndex() ;
                  SendMessage(TRG_WNRI, ""+(iCurRow+1)); 
                }
            }
        }

    public void focusGained(FocusEvent e)
     {
         if (e.getComponent() == this)
         {
             table.requestFocus();
         }
    
         try
         {
             m_handler.setProperty(FOCUS_EVENT, e);
         }
         catch ( Exception ex ){}
     }
    
    
     public void focusLost(FocusEvent e)
     {
     }  


}
