home *** CD-ROM | disk | FTP | other *** search
/ Symantec Visual Cafe for Java 2.5 / symantec-visual-cafe-2.5-database-dev-edition.iso / VCafe / prosrc.bin / TableView.java < prev    next >
Encoding:
Java Source  |  1998-03-18  |  187.6 KB  |  6,315 lines

  1. /*
  2.  * Copyright (c) 1997 Krumel & Associates, Inc. All Rights Reserved.
  3.  *
  4.  * www.krumel.com - controls@krumel.com
  5.  *
  6.  * Permission is given to the buyer of this package for one software
  7.  * developer to use this software on one CPU (one workstation) and to make
  8.  * one backup copy.  You may uitilize and/or modify this class for use in your
  9.  * projects.  You may distribute or sell any executable which results from
  10.  * using this code in yur application, except a utility or class of similar
  11.  * nature to this product.  You may distribute this product in compiled
  12.  * form only, but soley to be used with your cmpiled executable product
  13.  * for the puposes of dynamic loading. You may NOT redistribute the source
  14.  * code in any form or make it accessible through a network or other
  15.  * distribution media to others. Please refer to the file "copyright.html"
  16.  * for further important copyright and licensing information.
  17.  *
  18.  * The source code is the confidential and proprietary information
  19.  * of Krumel & Associates, Inc. ("Confidential Information").  You shall
  20.  * not disclose such Confidential Information and shall use it only in
  21.  * accordance with the terms of the license agreement you entered into
  22.  * with Krumel & Associates, Inc..
  23.  
  24.  * KRUMEL & ASSOCIATES MAKES NO REPRESENTATIONS OR WARRANTIES ABOUT THE
  25.  * SUITABILITY OF THE SOFTWARE, EITHER EXPRESS OR IMPLIED, INCLUDING BUT
  26.  * NOT LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
  27.  * PARTICULAR PURPOSE, OR NON-INFRINGEMENT. KRUMEL & ASSOCIATES SHALL NOT
  28.  * BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING,
  29.  * MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES.
  30.  */
  31.  
  32. package symantec.itools.db.awt;
  33.  
  34. import java.awt.*;
  35. import java.util.*;
  36. import java.io.*;
  37. import symantec.itools.db.awt.genutil.*;
  38. import java.awt.event.*;
  39. import symantec.itools.db.awt.event.*;
  40. import symantec.itools.db.awt.awt.Scroller;
  41. import symantec.itools.db.awt.genutil.Out;
  42. import symantec.itools.db.awt.awt.Spacer;
  43.  
  44. import java.sql.SQLException;
  45. import java.util.ResourceBundle;
  46.  
  47. /**
  48.  * A spreadsheet style control.<p>
  49.  *
  50.  * All column and row numbers are one relative.<p>
  51.  *
  52.  * The TableView supports column and row headings.  The row headings may be blank or
  53.  * autonumbered based on a user defined base number.<p>
  54.  *
  55.  * The TableView provides support for a toolbar along the bottom row to the right
  56.  * of the horizontal scrollbar.  Any type of component may be added to the toolbar
  57.  * or pre-defined buttons may be added using the available addXXXXButton methods.<p>
  58.  *
  59.  * To increase the modularity of the TableView, events and exceptions are passed to
  60.  * an EventHandler object when set.  Event IDs have been defined for the table
  61.  * and cells.  Additional events are generated by the toolbar components and
  62.  * forwarded to the EventHandler as well.  Of course the tradional event model
  63.  * of JDK 1.0.2 is also supported but tends to make GUI code functional.
  64.  * All highlighting, inserts, gotos, ... are performed by the EventHandler. <p>
  65.  *
  66.  * To further increase modularity, data is kept in DataSources.  A default
  67.  * DataSource if one is not defined that simply stores the data in a Matrix
  68.  * instance.  If a RelationView is specified in the constructor, then a special
  69.  * DataSource is created to drive the TableView off of the database query.<p>
  70.  *
  71.  * A number of APIs are defined to allow the TableView color, font, and other visual
  72.  * styles to be effected.
  73.  *
  74.  * @version 1.0   12 Jan 1997
  75.  * @author  Andy Krumel - Krumel & Associates, Inc
  76.  */
  77. public class TableView extends Panel
  78.                        implements /*Notifiable,*/ AdjustmentListener, FocusListener
  79. {
  80.     //BS:added for backward compatibility
  81.     //private int m_NumberOfRows = 5;
  82.     //private int m_NumberOfColumns = 5;
  83.  
  84.     public String   name = "";
  85.     boolean         autoRedraw = true;
  86.     boolean         disableDrawing = false;
  87.     Panel           toolbar;
  88.     Panel           bottomPanel;
  89.     Vector          toolbarComponents = new Vector();
  90.     TvEventHandler  eventHandler;
  91.     Matrix          cells;
  92.     Matrix          colHeadings;
  93.     Matrix          cellAttributes;      //cell hints
  94.     Matrix          headingAttributes;   //col heading hints
  95.     int             preferredRowCount = 10;
  96.     int             preferredPixelWidth = -1;
  97.     /**
  98.      * The bounds of each column. There are cols+1 elements.
  99.      */
  100.     int             splitters[];
  101.     /**
  102.      * Determines if column is hidden. Use true to indicate do not show so when
  103.      * array created, all columns are visible by default.
  104.      */
  105.     boolean         colHidden[];
  106.     /**
  107.      * Specified whether last column should fill all remaining space.
  108.      */
  109.     boolean         fillLastColumn;
  110.     Scroller        vsb;
  111.     Scroller        hsb;
  112.     Spacer          spacer;
  113.     int             cursor = Frame.DEFAULT_CURSOR;
  114.     long            clickTime;
  115.     int             topRow;
  116.     int             lockedColumn = -1;
  117.     int             leftCol = lockedColumn+1/*next col*/ +1 /*one relative*/+1;
  118.     int             dragColumn = -1;
  119.     int             xDragLast = -1;
  120.     boolean         isDragging;
  121.     int             headingHeight;
  122.     int             cellHeight;
  123.     int             clickMargin = 5;
  124.     int             currentCursor = Frame.DEFAULT_CURSOR;
  125.     transient Image           im;
  126.     transient Graphics        gg;
  127.     int             height;
  128.     int             width;
  129.     int             hsbPosition=1;
  130.     long            scrollbarTimer;
  131.     boolean         fetchMode = false;
  132.  
  133.     DataSource              dataSource;
  134.     DataSource              headingSource;
  135.     DefaultDataSource       rowHeadingSource;
  136.  
  137.     /**
  138.      * Hints used to draw cells. Prevents extra heap allocation
  139.      */
  140.     transient CellHints       hints;
  141.     /**
  142.      * Cell that has the keyboard focus.
  143.      */
  144.     TableCell       currSelectedCell = null;
  145.     /**
  146.      * Cell that has the mouse focus.
  147.      */
  148.     TableCell       currCaptureCell = null;
  149.       /**
  150.        * The default cell used when none is specified. Default is BasicCell.
  151.        */
  152.       TableCell       defaultCell;
  153.  
  154.  
  155. //-----------------------------------------------------------------------------
  156. //                          Column Heading Variables
  157. //-----------------------------------------------------------------------------
  158.     boolean         useRowHeadings = true;
  159.     int             rowHeadingWidth = 30;
  160.     CellHints       rowHeadingHints;
  161.     boolean         autoCreate = true;
  162.     int             rowHeadingLabelStyle = BLANK;
  163.     int             firstNumber = 1;    //used for autonumbering
  164.     TableCell       headingCell;        //the default row heading cell
  165.     TableCell       currHeadingCell;    //the one currently being pressed
  166.                                         //this is null if not in use
  167.     TableCell       cornerCell;         //the default row heading cell
  168.  
  169.  
  170.     //row heading styles
  171.  
  172.     /**
  173.      * Autonumber row heading style
  174.      */
  175.     public final static int AUTONUMBER = 0;
  176.     /**
  177.      * Blank row headings - the default
  178.      */
  179.     public final static int BLANK = 1;
  180.  
  181.     /**
  182.      * User defined style - not currently supported
  183.      */
  184.     public final static int USER_DEFINED = 2;
  185.  
  186.     /**
  187.      * TableCell type as returned by TableCell.type()
  188.      */
  189.     public final static Integer TABLE_CELL = new Integer(1);
  190.     /**
  191.      * The corner cell type as returned by TableCell.type()
  192.      */
  193.     public final static Integer CORNER_CELL = new Integer(2);
  194.     /**
  195.      * Column heading type as returned by TableCell.type()
  196.      */
  197.     public final static Integer COLUMN_HEADING = new Integer(3);
  198.     /**
  199.      * Row heading cell type as returned by TableCell.type()
  200.      */
  201.     public final static Integer ROW_HEADING = new Integer(4);
  202.  
  203.     /**
  204.      * default append row toolbar button label
  205.      */
  206.     public static String appendRowLabel;
  207.     /**
  208.      * default delete row toolbar button label
  209.      */
  210.     public static String deleteRowLabel;
  211.     /**
  212.      * default insert row toolbar button label
  213.      */
  214.     public static String insertRowLabel;
  215.     /**
  216.      * default goto row toolbar button label
  217.      */
  218.     public static String gotoRowLabel;
  219.     /**
  220.      * default save row toolbar button label
  221.      */
  222.     public static String saveLabel;
  223.     /**
  224.      * default restart row toolbar button label
  225.      */
  226.     public static String restartLabel;
  227.     /**
  228.      * default undo row toolbar button label
  229.      */
  230.     public static String undoRowLabel;
  231.     /**
  232.      * default undelete row toolbar button label
  233.      */
  234.     public static String undeleteRowLabel;
  235.  
  236.  
  237.     /**
  238.      * The name assigned to goto toolbar components.
  239.      */
  240.     public static final String gotoName = "GOTO";
  241.     /**
  242.      * The name assigned to delete toolbar components.
  243.      */
  244.     public static final String deleteName = "DELETE";
  245.     /**
  246.      * The name assigned to insert toolbar components.
  247.      */
  248.     public static final String insertName = "INSERT";
  249.     /**
  250.      * The name assigned to save toolbar components.
  251.      */
  252.     public static final String saveName = "SAVE";
  253.     /**
  254.      * The name assigned to undo toolbar components.
  255.      */
  256.     public static final String restartName = "RESTART";
  257.     /**
  258.      * The name assigned to undo toolbar components.
  259.      */
  260.     public static final String undoName = "UNDO";
  261.     /**
  262.      * The name assigned to undelete toolbar components.
  263.      */
  264.     public static final String undeleteName = "UNDELETE";
  265.     /**
  266.      * The name assigned to append toolbar components.
  267.      */
  268.     public static final String appendName = "APPEND";
  269.  
  270.  
  271. //-----------------------------------------------------------------------------
  272. //                          Constant IDs
  273. //-----------------------------------------------------------------------------
  274.     /**
  275.      * Time to register a double click (in milliseconds).
  276.      */
  277.     public final static long CLICKTHRESHOLD = 250;
  278.     /**
  279.      * Left-justify constant.
  280.      */
  281.     public final static int LEFT = 0;
  282.     /**
  283.      * Center-justify constant.
  284.      */
  285.     public final static int CENTER = 1;
  286.     /**
  287.      * Right-justify constant.
  288.      */
  289.     public final static int RIGHT = 2;
  290.  
  291.     //Cell line styles
  292.  
  293.     /**
  294.      * Line style specifies that no line should be drawn.
  295.      */
  296.     public final static int NO_LINE = 0;
  297.     /**
  298.      * Line style specifies that a thin line should be drawn.
  299.      */
  300.     public final static int THIN_LINE = 1;
  301.     /**
  302.      * Line style specifies that a thick line (3 pixels wide) should be drawn.
  303.      */
  304.     public final static int THICK_LINE = 2;
  305.     /**
  306.      * This one is not implemented yet, but it will be soon.
  307.      */
  308.     final static int DASHED_LINE = 3;
  309.  
  310.     //Cell vertical align styles
  311.     final static int TOP = 0;
  312. //    public final static int CENTER = 1;  //already defined
  313.     final static int BOTTOM = 2;
  314.  
  315.  
  316.  
  317.     //Cell fill styles
  318.  
  319.     static TableCell defaultHeadingCell_ = new ButtonCell();
  320.     static boolean defaultsInitialized = false;
  321.  
  322.     static void initDefaults() {
  323.         if (!defaultsInitialized) {
  324.             defaultHeadingCell_.setCoordinates(new Coordinate(0,0));
  325.             defaultHeadingCell_.type(TableCell.ROW_HEADING);
  326.             defaultsInitialized = true;
  327.         }
  328.     }
  329.  
  330.     /**
  331.      * Default constructor for new TableView.
  332.      */
  333.     public TableView()  {
  334.         this(0, Color.white);
  335.        // System.out.println("into tableview()");
  336.     }
  337.  
  338.     /**
  339.      * Constructs a new TableView with the specified number of columns.
  340.      * @param cols the number of columns
  341.      */
  342.     public TableView(int cols) {
  343.  
  344.         this(cols, Color.white);
  345.  
  346.         //System.out.println("cols");
  347.     }
  348.  
  349.     /**
  350.      * Constructs a new TableView with the preferred height based on
  351.      * specified number of rows.
  352.      * @param rows the number of rows to show
  353.      */
  354.     public TableView(long rows)  {
  355.  
  356.         this(rows, 0);
  357.  
  358.         //System.out.println("rows");
  359.     }
  360.  
  361.     /**
  362.      * Constructs a new TableView with the spcified number of columns
  363.      * and whether multiple row selection allowed.
  364.      * @param rows the number of rows to show
  365.      * @param cols the number of columns
  366.      */
  367.     public TableView(long rows, int cols) {
  368.         //this(cols, Color.white);
  369.         ResourceBundle res = ResourceBundle.getBundle("symantec.itools.db.resources.ResBundle");
  370.  
  371.         appendRowLabel = res.getString("Append");
  372.         deleteRowLabel = res.getString("Delete");
  373.         insertRowLabel = res.getString("Insert");
  374.         gotoRowLabel = res.getString("Goto");
  375.         saveLabel = res.getString("Save");
  376.         restartLabel = res.getString("Restart");
  377.         undoRowLabel = res.getString("Undo");
  378.         undeleteRowLabel = res.getString("Undelete");
  379.  
  380.         //System.out.println("rows,cols");
  381.  
  382.         dataSource = new DefaultDataSource(this);
  383.         assignDefaults();
  384.         dataSource.setDefaultData();
  385.         createColumns(cols);
  386.         setupAutonumbering(1);
  387.         setBackground(Color.white);
  388.  
  389.         //BS
  390.         installDefaultEventHandler();
  391.  
  392.     try
  393.         {
  394.         for( int i=0; i < rows; i++)
  395.             {
  396.             appendRow();
  397.             }
  398.  
  399.         for(int i=0; i< cols;i++)
  400.             {
  401.             setHeading( "Column:"+(i+1), i+1, 10);
  402.             }
  403.         } catch( Exception e)
  404.         {System.out.println( "EXCEPTION " + e);}
  405.  
  406.         preferredRowCount = (int)rows;
  407.     }
  408.  
  409.     /**
  410.      * Constructs a new TableView with the spcified number of columns
  411.      * and whether multiple row selection allowed, and background color.
  412.      * @param cols the number of columns
  413.      * @bg Color instance for background color
  414.      */
  415.     public TableView(int cols, Color bg) {
  416.  
  417.         ResourceBundle res = ResourceBundle.getBundle("symantec.itools.db.resources.ResBundle");
  418.  
  419.         appendRowLabel = res.getString("Append");
  420.         deleteRowLabel = res.getString("Delete");
  421.         insertRowLabel = res.getString("Insert");
  422.         gotoRowLabel = res.getString("Goto");
  423.         saveLabel = res.getString("Save");
  424.         restartLabel = res.getString("Restart");
  425.         undoRowLabel = res.getString("Undo");
  426.         undeleteRowLabel = res.getString("Undelete");
  427.  
  428.         dataSource = new DefaultDataSource(this);
  429.         assignDefaults();
  430.         dataSource.setDefaultData();
  431.         createColumns(cols);
  432.         //setupAutonumbering(1);
  433.         setBackground(bg);
  434.  
  435.         //BS
  436.         installDefaultEventHandler();
  437.  
  438.     }
  439.  
  440.  
  441.  
  442.  
  443.  
  444.  
  445.     /**
  446.      * Constructs a TableView using the specified DataSource instance.  If the
  447.      * DataSource supports meta data then it will be used to setup the TableView.
  448.      * @param ds The DataSource used to keep the TableView's data
  449.      */
  450.     public TableView(DataSource ds) {
  451.         dataSource = ds;
  452.         dataSource.setDefaultData();
  453.         assignDefaults();
  454.         dataSource.setTableView(this);
  455.         if (dataSource.supportsMeta()) {
  456.             try { dataSource.setupTableView(this); } catch(Exception e) {
  457.                 e.printStackTrace();
  458.             }
  459.         }
  460.     }
  461.  
  462.     boolean guiConstructed = false;
  463.  
  464.     void assignDefaults() {
  465.         initDefaults();
  466.         if (!guiConstructed) {
  467.             //enable mouse events and key events.
  468.             enableEvents(AWTEvent.MOUSE_MOTION_EVENT_MASK
  469.                          | AWTEvent.MOUSE_EVENT_MASK
  470.                          | AWTEvent.KEY_EVENT_MASK
  471.                          | AWTEvent.FOCUS_EVENT_MASK);
  472.             String osName = System.getProperty("os.name");
  473.             setLayout(new BorderLayout());
  474.             setFont(CellHints.stdFont);
  475.             setBackground(Color.white);
  476.             setForeground(Color.black);
  477.             vsb = new Scroller(Scrollbar.VERTICAL);
  478.             vsb.hide();
  479.             vsb.addAdjustmentListener(this);
  480.  
  481.               toolbar = new Panel();
  482.                toolbar.setLayout(new FlowLayout(FlowLayout.LEFT, 0, 0));
  483.                toolbar.setBackground(Color.lightGray);
  484.  
  485.             hsb = new Scroller(Scrollbar.HORIZONTAL);
  486.             hsb.addAdjustmentListener(this);
  487.             spacer = new Spacer();
  488.             bottomPanel = new Panel();
  489.             bottomPanel.setBackground(Color.lightGray);
  490.             bottomPanel.setLayout(new BorderLayout());
  491.             bottomPanel.add("West", toolbar);
  492.             Panel padding = new Panel();
  493.             padding.setLayout(new BorderLayout());
  494.             padding.add("North", hsb);
  495.             bottomPanel.add("Center", padding);
  496.             bottomPanel.add("East", spacer);
  497.  
  498.             add("East",vsb);
  499.             add("South", bottomPanel);
  500.  
  501.             guiConstructed = true;
  502.         }
  503.  
  504.         hints = new CellHints(this);
  505.         defaultCell = new BasicCell(this, dataSource);
  506.         defaultCell.setCoordinates(new Coordinate(0, 0));
  507.         defaultCell.setDefaultFlag();
  508.         headingHeight = getFontMetrics(CellHints.stdFont).getHeight() + 4;
  509.         cellHeight = headingHeight;
  510.  
  511.         cells = new Matrix();
  512.         colHeadings = new Matrix();
  513.         cellAttributes = new Matrix();      //cell hints
  514.         headingAttributes = new Matrix();   //col heading hints
  515.         headingSource = new DefaultDataSource(this);
  516.         rowHeadingSource = new DefaultDataSource(this, true);
  517.  
  518.         //create row heading hints with default bg of light gray
  519.         rowHeadingHints = new CellHints(this);
  520.         rowHeadingHints.bg = Color.lightGray;
  521.         setCornerCell(defaultHeadingCell_);
  522.         setDefaultRowHeadingCell(defaultHeadingCell_);
  523.         try {
  524.             rowHeadingSource.setData(0, 1, new ImageStringData(dataSource, ""));
  525.             rowHeadingSource.setDefaultData(new ImageStringData(dataSource));
  526.         } catch(TypeNotSupported ex) {}
  527.     }
  528.  
  529.     public void setToolbarBackground(Color c) { toolbar.setBackground(c); }
  530.  
  531.     public Color getToolbarBackground() { return toolbar.getBackground(); }
  532.  
  533.     /**
  534.      * Sets the DataSource for keeping the TableView's data.  Replaces the previous
  535.      * DataSource if previously set.
  536.      * @param ds The DataSource to keep the TableView's data.
  537.      */
  538.     public void setDataSource(DataSource ds) {
  539.         clear();
  540.         dataSource = ds;
  541.         dataSource.setDefaultData();
  542.         assignDefaults();
  543.         dataSource.setTableView(this);
  544.         if (dataSource.supportsMeta()) {
  545.             try { dataSource.setupTableView(this); } catch(Exception e) {
  546.                 e.printStackTrace();
  547.             }
  548.         }
  549.     }
  550.  
  551.     /**
  552.      * Sets the DataSource for keeping the TableView's data.  Replaces the previous
  553.      * DataSource if previously set.
  554.      * @param ds The DataSource to keep the TableView's data.
  555.      */
  556.     public void setDataSource(DataSource ds, int first) {
  557.         setDataSource(ds);
  558.         setupAutonumbering(first);
  559.     }
  560.  
  561.     /**
  562.      * Gets the current DataSource for cell data
  563.      */
  564.     public DataSource getDataSource() {
  565.         return dataSource;
  566.     }
  567.  
  568.     /**
  569.      * Sets the automatic redraw behavior of the TableView.  If auto redraw is
  570.      * turned on then adding rows or changing data will cause the TableView to
  571.      * automatically redraw.  Turning it off can improve performance when
  572.      * making many changes at one time.
  573.      * @param redraw true to turn on automatic redrawing
  574.      */
  575.     public void setAutoRedraw(boolean redraw) {
  576.         autoRedraw = redraw;
  577.     }
  578.  
  579.     /**
  580.      * Gets the automatic redraw behavior of the TableView.  If auto redraw is
  581.      * turned on then adding rows or changing data will cause the TableView to
  582.      * automatically redraw.  Turning it off can improve performance when
  583.      * making many changes at one time.
  584.      */
  585.     public boolean getAutoRedraw() {
  586.         return autoRedraw;
  587.     }
  588.  
  589.     /**
  590.      * Disables all drawing of the TableView.  This can greatly increase performance
  591.      * if intensive methods occur by decreasing the algorithmic calculations.
  592.      */
  593.     public void disableDrawing() {
  594.         disableDrawing = true;
  595.     }
  596.  
  597.     /**
  598.      * Enables drawing functions.
  599.      */
  600.     public void enableDrawing() {
  601.         disableDrawing = false;
  602.     }
  603.  
  604.     /**
  605.      * Returns whether the TableView is currently performing drawing functions.
  606.      */
  607.     public boolean isDrawingEnabled() {
  608.         return !disableDrawing;
  609.     }
  610.  
  611.     /**
  612.      * Installs the TableView's default event handler used to handle cell and
  613.      * table level events and perform actions required when exception occur.
  614.      */
  615.     public void installDefaultEventHandler() {
  616.         installEventHandler(new DefaultTvEventHandler());
  617.     }
  618.  
  619.     /**
  620.      * Installs an event handler used to handle cell and
  621.      * table level events and perform actions required when exception occur.
  622.      */
  623.     public void installEventHandler(TvEventHandler h) {
  624.         eventHandler = h;
  625.         eventHandler.setupView(this);
  626.     }
  627.  
  628.     //-------------------------------------------------------------------------
  629.     //    Toolbar button functions
  630.     //-------------------------------------------------------------------------
  631.     /**
  632.      * Adds an add button to the TableView's toolbar.
  633.      */
  634.     public void addAppendButton() {
  635.         addToolbarButton(appendName, appendRowLabel);
  636.         m_HasAppendButton = true;
  637.     }
  638.  
  639.     /**
  640.      * Adds an add button to the TableView's toolbar with the specified label.
  641.      */
  642.     public void addAppendButton(String label) {
  643.         removeAppendButton();
  644.         appendRowLabel = label;
  645.         addToolbarButton(appendName, label);
  646.         m_HasAppendButton = true;
  647.     }
  648.  
  649.     /**
  650.      * Removes the add button from the toolbar.
  651.      */
  652.     public void removeAppendButton() {
  653.         removeToolbarButton(appendName);
  654.         m_HasAppendButton = false;
  655.     }
  656.  
  657.     /**
  658.      * Adds an insert button to the TableView's toolbar.
  659.      */
  660.     public void addInsertButton() {
  661.         addToolbarButton(insertName, insertRowLabel);
  662.         m_HasInsertButton = true;
  663.     }
  664.  
  665.     /**
  666.      * Adds an insert button to the TableView's toolbar.
  667.      */
  668.     public void addInsertButton(String label) {
  669.         removeInsertButton();
  670.         insertRowLabel = label;
  671.         addToolbarButton(insertName, label);
  672.         m_HasInsertButton = true;
  673.     }
  674.  
  675.     /**
  676.      * Removes the insert button to the TableView's toolbar.
  677.      */
  678.     public void removeInsertButton() {
  679.         removeToolbarButton(insertName);
  680.         m_HasInsertButton = false;
  681.     }
  682.  
  683.     /**
  684.      * Adds a delete button to the TableView's toolbar.
  685.      */
  686.     public void addDeleteButton() {
  687.         addToolbarButton(deleteName, deleteRowLabel);
  688.         m_HasDeleteButton = true;
  689.     }
  690.  
  691.     /**
  692.      * Adds a delete button to the TableView's toolbar with the specified label.
  693.      */
  694.     public void addDeleteButton(String label) {
  695.         removeDeleteButton();
  696.         deleteRowLabel = label;
  697.         addToolbarButton(deleteName, label);
  698.         m_HasDeleteButton = true;
  699.     }
  700.  
  701.     /**
  702.      * Removes the delete button to the TableView's toolbar.
  703.      */
  704.     public void removeDeleteButton() {
  705.         removeToolbarButton(deleteName);
  706.         m_HasDeleteButton = false;
  707.     }
  708.  
  709.     /**
  710.      * Adds a save button to the TableView's toolbar.
  711.      */
  712.     public void addSaveButton() {
  713.         addToolbarButton(saveName, saveLabel);
  714.         m_HasSaveButton = true;
  715.     }
  716.  
  717.     /**
  718.      * Adds a save button to the TableView's toolbar with the specified label.
  719.      */
  720.     public void addSaveButton(String label) {
  721.         removeSaveButton();
  722.         saveLabel = label;
  723.         addToolbarButton(saveName, label);
  724.         m_HasSaveButton = true;
  725.     }
  726.  
  727.     /**
  728.      * Removes the save button to the TableView's toolbar.
  729.      */
  730.     public void removeSaveButton() {
  731.         removeToolbarButton(saveName);
  732.         m_HasSaveButton = false;
  733.     }
  734.  
  735.     /**
  736.      * Adds a "restart row" button to the TableView's toolbar.
  737.      * @see #removeRestartButton
  738.      */
  739.     public void addRestartButton() {
  740.         addToolbarButton(restartName, restartLabel);
  741.         m_HasRestartButton = true;
  742.     }
  743.  
  744.     /**
  745.      * Adds a "restart row" button with the specified label to the TableView's toolbar.
  746.      * @param label the button label
  747.      * @see #removeRestartButton
  748.      */
  749.     public void addRestartButton(String label) {
  750.         removeRestartButton();
  751.         restartLabel = label;
  752.         addToolbarButton(restartName, label);
  753.         m_HasRestartButton = true;
  754.     }
  755.  
  756.     /**
  757.      * Removes the "restart row" button to the TableView's toolbar.
  758.      * @see #addRestartButton
  759.      */
  760.     public void removeRestartButton() {
  761.         removeToolbarButton(restartName);
  762.         m_HasRestartButton = false;
  763.     }
  764.  
  765.     /**
  766.      * Adds a delete button to the TableView's toolbar.
  767.      */
  768.     public void addUndeleteButton() {
  769.         addToolbarButton(undeleteName, undeleteRowLabel);
  770.         m_HasUndeleteButton = true;
  771.     }
  772.  
  773.     /**
  774.      * Adds a delete button to the TableView's toolbar with the specified label.
  775.      */
  776.     public void addUndeleteButton(String label) {
  777.         removeUndeleteButton();
  778.         undeleteRowLabel = label;
  779.         addToolbarButton(undeleteName, label);
  780.         m_HasUndeleteButton = true;
  781.     }
  782.  
  783.     /**
  784.      * Removes the delete button to the TableView's toolbar.
  785.      */
  786.     public void removeUndeleteButton() {
  787.         removeToolbarButton(undeleteName);
  788.         m_HasUndeleteButton = false;
  789.     }
  790.  
  791.     /**
  792.      * Adds the undo button to the TableView's toolbar.
  793.      */
  794.     public void addUndoButton() {
  795.         addToolbarButton(undoName, undoRowLabel);
  796.         m_HasUndoButton = true;
  797.     }
  798.  
  799.     /**
  800.      * Adds a undo button to the TableView's toolbar with the specified label.
  801.      */
  802.     public void addUndoButton(String label) {
  803.         removeUndoButton();
  804.         undoRowLabel = label;
  805.         addToolbarButton(undoName, label);
  806.         m_HasUndoButton = true;
  807.     }
  808.  
  809.      /**
  810.      * Removes the undo button to the TableView's toolbar.
  811.      */
  812.    public void removeUndoButton() {
  813.         removeToolbarButton(undoName);
  814.         m_HasUndoButton = false;
  815.     }
  816.  
  817.  
  818.     Panel gotoPanel;
  819.     TextField gotoTextField;
  820.     Button gotoButton;
  821.  
  822.     /**
  823.      * Add a goto button to the TableView's toolbar.
  824.      */
  825.     public void addGotoButton() {
  826.         if (gotoPanel == null) {
  827.             gotoPanel = new Panel();
  828.             gotoPanel.setLayout(new FlowLayout(FlowLayout.LEFT, 5, 0));
  829.             gotoPanel.add(gotoButton = new Button(gotoRowLabel));
  830.             gotoPanel.add(gotoTextField = new TextField(4));
  831.             gotoTextField.setName(gotoName);
  832.             tbAdapter.add(gotoTextField);
  833.             gotoButton.setName(gotoName);
  834.             tbAdapter.add(gotoButton);
  835.         } else {
  836.             return;
  837.         }
  838.  
  839.         addToToolbar(gotoPanel);
  840.         m_HasGotoButton = true;
  841.     }
  842.  
  843.     /**
  844.      * Removes the goto button to the TableView's toolbar.
  845.      */
  846.     public void removeGotoButton() {
  847.         if (gotoPanel == null) {
  848.             return;
  849.         } else {
  850.             removeFromToolbar(gotoPanel);
  851.             tbAdapter.remove(gotoTextField);
  852.             tbAdapter.remove(gotoButton);
  853.             gotoPanel = null;
  854.         }
  855.         m_HasGotoButton = false;
  856.     }
  857.  
  858.     ToolbarAdapter tbAdapter = new ToolbarAdapter(this);
  859.  
  860.     /**
  861.      * Adds a button to the TableView's toolbar using the specified label.  An adapter
  862.      * is used to automatically register the button created such that when the button
  863.      * is pushed, the event will be routed to the event handler, the data source, and
  864.      * to any registered objects interested in TableEvents.
  865.      */
  866.     public void addToolbarButton(String name, String label) {
  867.         Enumeration e = toolbarComponents.elements();
  868.         Component c;
  869.  
  870.         while(e.hasMoreElements()) {
  871.             c = (Component)e.nextElement();
  872.             if (c instanceof Button && ((Button)c).getLabel().equals(label)) {
  873.                 return;
  874.             }
  875.         }
  876.  
  877.         Button button = new Button(label);
  878.         button.setName(name);
  879.         tbAdapter.add(button);
  880.  
  881.         addToToolbar(button);
  882.     }
  883.  
  884.     /**
  885.      * Removes a button to the TableView's toolbar using the specified label. The
  886.      * button will no longer notify the TableView via the adapter after this method.
  887.      */
  888.     public void removeToolbarButton(String name) {
  889.         Enumeration e = toolbarComponents.elements();
  890.         Component c;
  891.  
  892.         while(e.hasMoreElements()) {
  893.             c = (Component)e.nextElement();
  894.             if (c instanceof Button && ((Button)c).getName().equals(name)) {
  895.                 //BS: did not remove the button from the toolbar
  896.                 removeFromToolbar(c);
  897.                 //toolbarComponents.removeElement(c);
  898.                 tbAdapter.remove((Button)c);
  899.                 return;
  900.             }
  901.         }
  902.     }
  903.  
  904.     /**
  905.      * Returns whether the specified component is located on the toolbar
  906.      * @param c The component to check the toolbar for containment
  907.      */
  908.     public boolean isToolbarComponent(Object c) {
  909.         return toolbarComponents.contains(c) || c == gotoTextField || c == gotoButton;
  910.     }
  911.  
  912.     /**
  913.      * Adds a component to the toolbar. If it is desired that events generate a TableEvent
  914.      * and be routed to the event handler, a ToolbarAdapter should be created and the
  915.      * the object registered with it. If the component is not a Button or TextField, the
  916.      * adapter class will need to be subclassed and specialized.
  917.      * @param c The component to add
  918.      */
  919.     public void addToToolbar(Component c) {
  920.         toolbarComponents.addElement(c);
  921.         toolbar.add(c);
  922.     }
  923.  
  924.     /**
  925.      * Removes an item from the toolbar
  926.      */
  927.     public void removeFromToolbar(Component c) {
  928.         toolbarComponents.removeElement(c);
  929.         toolbar.remove(c);
  930.     }
  931.  
  932.     /**
  933.      * Sets the column which does not scroll. All columns to the left of the
  934.      * locked column do not scroll, all of the columns to the right are
  935.      * scrollable.
  936.      * @param col The column to be locked, 0 if all columns should be scrollable.
  937.      */
  938.     public void setLockedColumn(int col) {
  939.         lockedColumn = col - 1;
  940.         showScrollbars();
  941.         redrawAsync();
  942.     }
  943.  
  944.     /**
  945.      * Gets the column which does not scroll. All columns to the left of the
  946.      * locked column do not scroll, all of the columns to the right are
  947.      * scrollable.
  948.      * @return The locked column, 0 if all columns are scrollable.
  949.      */
  950.     public int getLockedColumn() { return lockedColumn+1; }
  951.  
  952.     /**
  953.      * Gets whether a column is within the range of locked columns.
  954.      */
  955.     public boolean isColumnLocked(int col) {
  956.         return lockedColumn!=-1 && col<=lockedColumn+1;
  957.     }
  958.  
  959.     /**
  960.      * Sets whether the last column should be filled to the end of the visible
  961.      * space of the TableView
  962.      */
  963.     public void setFillLastColumn(boolean fill) {
  964.         fillLastColumn = fill;
  965.     }
  966.  
  967.     /**
  968.      * Gets whether the last column should be filled to the end of the visible
  969.      * space of the TableView
  970.      */
  971.     public boolean getFillLastColumn() {
  972.         return fillLastColumn;
  973.     }
  974.  
  975.     /**
  976.      * Set heading text and width for a column. The cell type created will be a ButtonCell.
  977.      * @param cell The cell to used for the heading.
  978.      * @param h string for heading text
  979.      * @param i number of column (one relative)
  980.      * @param chars width of column in characters
  981.      */
  982.     public /*synchronized */void setHeading(TableCell cell, String h, int col, int chars) {
  983.         cell.type(TableCell.COL_HEADING);
  984.         cell.setTableView(this, headingSource);
  985.         colHeadings.updateElement(0, col-1, cell);
  986.         try {
  987.             headingSource.setData(cell.getCoordinates(), new ImageStringData(dataSource, h));
  988.         } catch(TypeNotSupported ex) {}
  989.         setHeadingSize(col, chars);
  990.         if (autoRedraw) {
  991.             redrawAsync();
  992.         }
  993.     }
  994.  
  995.     /**
  996.      * Set heading text and width for a column. The cell type created will be a ButtonCell.
  997.      * @param h string for heading text
  998.      * @param i number of column (one relative)
  999.      * @param chars width of column in characters
  1000.      */
  1001.     public /*synchronized*/ void setHeading(String h, int col, int chars) {
  1002.         ButtonCell cell = new ButtonCell(1, col);
  1003.         setHeading(cell, h, col, chars);
  1004.     }
  1005.  
  1006.     /**
  1007.      * Set column width of a column.
  1008.      * @param col column number to set width
  1009.      * @param chars width of column in characters
  1010.      */
  1011.     public /*synchronized*/ void setHeadingSize(int col, int chars) {
  1012.         CellHints hints = getHeadingHints(0, col);
  1013.         int width = getFontMetrics(hints.font).charWidth('W') * chars;
  1014.         setColumnSize(col, width);
  1015.     }
  1016.  
  1017.     /**
  1018.      * Sets the preferred row count. Used to determine the preferred size
  1019.      */
  1020.      public void setPreferredRowCount(int c) { preferredRowCount = c; }
  1021.  
  1022.     /**
  1023.      * Gets the preferred row count. Used to determine the preferred size
  1024.      */
  1025.     public int getPreferredRowCount() { return preferredRowCount; }
  1026.  
  1027.     /**
  1028.      * Sets the preferred width in pixels used to calculate preferredSize.
  1029.      * @param pixels Number of pixels for preferred width. Use -1 to calculate
  1030.      *      preferred width based on column widths.
  1031.      */
  1032.     public void setPreferredWidth(int pixels) {
  1033.         preferredPixelWidth = pixels;
  1034.     }
  1035.  
  1036.     /**
  1037.      * Gets the number of pixels specified as the desired width of the TableView.
  1038.      * @return The number of pixel specified using setPreferredWidth, -1 otherwise.
  1039.      */
  1040.     public int getPreferredWidth() { return preferredPixelWidth; }
  1041.  
  1042.     /**
  1043.      * Returns the preferred size of this component.
  1044.      * @see #minimumSize
  1045.      */
  1046.     public Dimension preferredSize() {
  1047.         return getPreferredSize();
  1048.     }
  1049.  
  1050.     /**
  1051.      * Returns the preferred size of this component.
  1052.      * @see #getMinimumSize
  1053.      */
  1054.     public Dimension getPreferredSize() {
  1055.         int w=0, h=0;
  1056.         w = splitters[splitters.length-1] + rowHeadingWidth;
  1057.         h = (preferredRowCount + 1) * cellHeight;
  1058.  
  1059.         //compensate for hidden columns
  1060.         int cols = cols();
  1061.         for (int i=0; i<cols; i++) {
  1062.             if (isColumnVisible(i+1)) { w -= getColumnWidth(i+1); }
  1063.         }
  1064.  
  1065.         Dimension toolsize = toolbar.preferredSize();
  1066.  
  1067.         return new Dimension(Math.max(w, toolsize.width),
  1068.                              h + toolsize.height);
  1069.     }
  1070.  
  1071.     /**
  1072.      * Returns the minimum size of this component.
  1073.      * @see #getPreferredSize
  1074.      * @see java.awt.LayoutManager
  1075.      */
  1076.     public Dimension getMinimumSize() {
  1077.         return getPreferredSize();
  1078.     }
  1079.  
  1080.     /**
  1081.      * Returns the minimum size of this component.
  1082.      * @see #preferredSize
  1083.      * @see LayoutManager
  1084.      */
  1085.     public Dimension minimumSize() {
  1086.         return getPreferredSize();
  1087.     }
  1088.  
  1089.     /**
  1090.      * Create specified number of columns for TableView.
  1091.      * @param i number of columns for TableView
  1092.      */
  1093.     public /*synchronized*/ void createColumns(int i) {
  1094.         cellAttributes.removeAllElements();
  1095.         headingAttributes.removeAllElements();
  1096.  
  1097.         //set the corner cell hints
  1098.         headingAttributes.addElement(0, 0, new CellHints(this));
  1099.  
  1100.         //set cell and heading hints
  1101.         for(int col=1;col<=i;col++) {
  1102.             //always a valid cell hints for each column
  1103.             cellAttributes.addElement(0, col, new CellHints(this));
  1104.  
  1105.             //set the heading hints with default color of black on lightGray
  1106.             CellHints headingHints = new CellHints(this);
  1107.             headingHints.bg = Color.lightGray;
  1108.             headingAttributes.addElement(0, col, headingHints);
  1109.         }
  1110.  
  1111.         splitters = new int[i+1];
  1112.         colHidden = new boolean[i];
  1113.     }
  1114.  
  1115.     /**
  1116.      * Determines if a column is showable or hidden.
  1117.      * @return True if column is showable, false if it has been designated a
  1118.      *      hidden column.
  1119.      */
  1120.     public boolean isColumnVisible(int col) {
  1121.         return !colHidden[col-1];
  1122.     }
  1123.  
  1124.     /**
  1125.      * Sets the showable/hidden flag for a column.
  1126.      * @param col The column number to set the flag.
  1127.      * @param show True if the column should be showable, false to hide it.
  1128.      */
  1129.     public void showColumn(int col, boolean show) {
  1130.         colHidden[col-1] = !show;
  1131.         redrawAsync();
  1132.     }
  1133.  
  1134. //-----------------------------------------------------------------------------
  1135. //                          Heading APIs
  1136. //-----------------------------------------------------------------------------
  1137.  
  1138.     /**
  1139.      * Sets the cell to be used by the corner cell.  The corner cell is in
  1140.      * the upper left and is only visible if row headings are present.
  1141.      */
  1142.     public /*synchronized*/ void setCornerCell(TableCell c) {
  1143.         cornerCell = c.cloneCell();
  1144.         cornerCell.setTableView(this, rowHeadingSource);
  1145.         cornerCell.setCoordinates(new Coordinate(0, 1));
  1146.         cornerCell.type(TableCell.CORNER_CELL);
  1147.     }
  1148.  
  1149.     /**
  1150.      * Sets the cell type used to display the row headings.  All row headings
  1151.      * must be of the same type.
  1152.      */
  1153.     public /*synchronized*/ void setDefaultRowHeadingCell(TableCell c) {
  1154.         headingCell = c.cloneCell();
  1155.         headingCell.setTableView(this, rowHeadingSource);
  1156.     }
  1157.  
  1158.     /**
  1159.      * Sets the width of the row headings
  1160.      */
  1161.     public /*synchronized*/ void setRowHeadingWidth(int w) {
  1162.         rowHeadingWidth = w;
  1163.     }
  1164.  
  1165.     /**
  1166.      * Gets the width of the row headings
  1167.      */
  1168.     public /*synchronized*/ int getRowHeadingWidth() {
  1169.         return rowHeadingWidth;
  1170.     }
  1171.  
  1172.     /**
  1173.      * Sets the row heading style.
  1174.      * @param s The style and must be one of BLANK or AUTONUMBER
  1175.      */
  1176.     public /*synchronized*/ void setHeadingHeight(int h) {
  1177.         headingHeight = h;
  1178.         if (autoRedraw) {
  1179.             redrawAsync();
  1180.         }
  1181.     }
  1182.  
  1183.     /**
  1184.      * Sets whether row headings should be displayed.
  1185.      */
  1186.     public void useRowHeadings(boolean use) {
  1187.         useRowHeadings = use;
  1188.     }
  1189.  
  1190.     /**
  1191.      * Gets whether row headings should be displayed.
  1192.      */
  1193.     public boolean isUsingRowHeadings() {
  1194.         return useRowHeadings;
  1195.     }
  1196.  
  1197.     /**
  1198.      * Sets the display height of cells.
  1199.      */
  1200.     public /*synchronized*/ void setCellHeight(int h) {
  1201.         int stdHeight = getFontMetrics(CellHints.stdFont).getHeight() + 4;
  1202.  
  1203.         if (h < stdHeight) {
  1204.             cellHeight = stdHeight;
  1205.         } else {
  1206.             cellHeight = h;
  1207.         }
  1208.         if (autoRedraw) { redrawAsync(); }
  1209.     }
  1210.  
  1211.     /**
  1212.      * Sets the row heading style.
  1213.      * @param s The style and must be one of BLANK or AUTONUMBER
  1214.      */
  1215.     public /*synchronized*/ void setRowLabelHeadingStyle(int s) {
  1216.         if (s < AUTONUMBER || s > USER_DEFINED) {
  1217.             throw new IllegalArgumentException("Illegal heading label style");
  1218.         }
  1219.  
  1220.         rowHeadingLabelStyle = s;
  1221.         if (s == AUTONUMBER) {
  1222.              rowHeadingSource.doAutoNumbering(true);
  1223.         }
  1224.     }
  1225.  
  1226.     /**
  1227.      * Sets the row heading label alignment style.
  1228.      * @param a The alignment style: LEFT, CENTER, RIGHT
  1229.      */
  1230.     public /*synchronized*/ void setRowHeadingAlignment(int a) {
  1231.         if (a < LEFT || a > RIGHT) {
  1232.             throw new IllegalArgumentException("Illegal alignment style");
  1233.         }
  1234.  
  1235.         rowHeadingHints.align = a;
  1236.     }
  1237.  
  1238.     /**
  1239.      * Gets the row heading alignment style
  1240.      * @return The alignment style: LEFT, CENTER, RIGHT
  1241.      */
  1242.     public int getRowHeadingAlignment() {
  1243.         return rowHeadingHints.align;
  1244.     }
  1245.  
  1246.     /**
  1247.      * Gets the row heading label style
  1248.      * @return The alignment style: LEFT, CENTER, RIGHT
  1249.      */
  1250.     public int getRowLabelHeadingStyle() {
  1251.         return rowHeadingLabelStyle;
  1252.     }
  1253.  
  1254.     /**
  1255.      * Gets the number of the first row in the TableView
  1256.      */
  1257.     public int getFirstAutoNumber() {
  1258.         return rowHeadingWidth;
  1259.     }
  1260.  
  1261.     /**
  1262.      * Causes row headings to be visible displaying row numbers starting with
  1263.      * the specified value.
  1264.      * @param first The number of the first row
  1265.      */
  1266.     public void setupAutonumbering(int first) {
  1267.         setupAutonumbering(first, rowHeadingWidth);
  1268.     }
  1269.  
  1270.     /**
  1271.      * Causes row headings to be visible displaying row numbers starting with
  1272.      * the specified value and sets the row headings to a fixed width to start.
  1273.      * @param first The number of the first row
  1274.      * @param pixels The starting width of the row headings
  1275.      */
  1276.     public /*synchronized*/ void setupAutonumbering(int first, int pixels) {
  1277.         rowHeadingLabelStyle = AUTONUMBER;
  1278.         rowHeadingSource.doAutoNumbering(true, first);
  1279.         useRowHeadings = true;
  1280.         rowHeadingWidth = pixels;
  1281.     }
  1282.  
  1283.     /**
  1284.      * Sets the default value used when the row headings do not contain
  1285.      * data for the row
  1286.      */
  1287.     public /*synchronized*/ void setDefaultRowData(String s) {
  1288.         rowHeadingSource.setDefaultData(new ImageStringData(dataSource, s));
  1289.     }
  1290.  
  1291.     /**
  1292.      * Sets the default data used when the row headings do not contain
  1293.      * data for the row
  1294.      */
  1295.     public /*synchronized*/ void setDefaultRowData(Data d) {
  1296.         rowHeadingSource.setDefaultData(d);
  1297.     }
  1298.  
  1299.     /**
  1300.      * Return heading text of specified column.
  1301.      */
  1302.     public String getHeading(int col) throws DataNotAvailable {
  1303.         col--;
  1304.         return headingSource.getData(0, col).toString();
  1305.     }
  1306.  
  1307.     /**
  1308.      * Set the font of the heading text.
  1309.      * @param f font instance for heading text.
  1310.      * @param col the heading column to set (1 relative).
  1311.      */
  1312.     public /*synchronized*/ void setHeadingFont(Font f, int col) {
  1313.         CellHints hints = getHeadingHints(0, col);
  1314.         hints.font = f;
  1315.         headingHeight = getFontMetrics(f).getHeight();
  1316.         if (autoRedraw) { redrawAsync(); }
  1317.     }
  1318.     /**
  1319.      * Returns the font of the heading text
  1320.      * @param col the heading column to get (1 relative).
  1321.      */
  1322.     public Font getHeadingFont(int col) {
  1323.         return getHeadingHints(0, col).font();
  1324.     }
  1325.  
  1326.  
  1327.  
  1328. //-----------------------------------------------------------------------------
  1329. //                          Line style and line color Control APIs
  1330. //-----------------------------------------------------------------------------
  1331.  
  1332.     /**
  1333.      * Sets the horizontal line style for a column.
  1334.      * @param col The column number to set the style.
  1335.      * @param style One of NO_LINE, THIN_LINE, THICK_LINE, DASHED_LINE.
  1336.      */
  1337.     public void setColumnHorizontalLineStyle(int col, int style) {
  1338.         if (style < NO_LINE || style > DASHED_LINE) {
  1339.             throw new IllegalArgumentException("Line style " + style + " is not valid");
  1340.         }
  1341.         col--;
  1342.         CellHints hints = getColHints(col);
  1343.         hints.setTopLineStyle(style);
  1344.         hints.setBottomLineStyle(style);
  1345.     }
  1346.  
  1347.     /**
  1348.      * Gets the horizontal line style for a column.
  1349.      * @param col The column number to set the style.
  1350.      * @return The horizontal line style.
  1351.      */
  1352.     public int getColumnHorizontalLineStyle(int col) {
  1353.         col--;
  1354.         CellHints hints = getColHints(col);
  1355.         return hints.lineTopStyle;
  1356.     }
  1357.  
  1358.     /**
  1359.      * Sets the horizontal line style for a column.
  1360.      * @param col The column number to set the style.
  1361.      * @param c The horizontal line color.
  1362.      */
  1363.     public void setColumnHorizontalLineColor(int col, Color c) {
  1364.         col--;
  1365.         CellHints hints = getColHints(col);
  1366.         hints.setTopLineColor(c);
  1367.         hints.setBottomLineColor(c);
  1368.     }
  1369.  
  1370.     /**
  1371.      * Gets the horizontal line style for a column.
  1372.      * @param col The column number to set the style.
  1373.      * @return The color used for horizontal lines.
  1374.      */
  1375.     public Color getColumnHorizontalLineColor(int col) {
  1376.         col--;
  1377.         CellHints hints = getColHints(col);
  1378.         return hints.lineTopColor;
  1379.     }
  1380.  
  1381.     /**
  1382.      * Sets the left line style for a column. This method is equivalant to calling
  1383.      * setColumnRightLineStyle() for the previous column.
  1384.      * @param col The column number to set the style.
  1385.      * @param style One of NO_LINE, THIN_LINE, THICK_LINE, DASHED_LINE.
  1386.      */
  1387.     public void setColumnLeftLineStyle(int col, int style) {
  1388.         if (style < NO_LINE || style > DASHED_LINE) {
  1389.             throw new IllegalArgumentException("Line style " + style + " is not valid");
  1390.         }
  1391.         col--;
  1392.         CellHints hints = getColHints(col);
  1393.         hints.setLeftLineStyle(style);
  1394.  
  1395.         if (col >= 1) {
  1396.             col--;
  1397.             hints = getColHints(col);
  1398.             hints.setRightLineStyle(style);
  1399.         }
  1400.     }
  1401.  
  1402.     /**
  1403.      * Gets the left line style for a column. This method is equivalant to calling
  1404.      * getColumnRightLineStyle() for the previous column.
  1405.      * @param col The column number to set the style.
  1406.      * @return One of NO_LINE, THIN_LINE, THICK_LINE, DASHED_LINE.
  1407.      */
  1408.     public int getColumnLeftLineStyle(int col) {
  1409.         col--;
  1410.         CellHints hints = getColHints(col);
  1411.         return hints.lineLeftStyle;
  1412.     }
  1413.  
  1414.     /**
  1415.      * Sets the left line color for a column. This method is equivalant to calling
  1416.      * setColumnRightLineStyle() for the previous column.
  1417.      * @param col The column number to set the style.
  1418.      * @param c The line color for the left side of the column.
  1419.      */
  1420.     public void setColumnLeftLineColor(int col, Color c) {
  1421.         col--;
  1422.         CellHints hints = getColHints(col);
  1423.         hints.setLeftLineColor(c);
  1424.         if (col >= 1) {
  1425.             col--;
  1426.             hints = getColHints(col);
  1427.             hints.setRightLineColor(c);
  1428.         }
  1429.     }
  1430.  
  1431.     /**
  1432.      * Gets the left line color for a column. This method is equivalant to calling
  1433.      * getColumnRightLineColor() for the previous column.
  1434.      * @param col The column number to set the style.
  1435.      * @return The line color for the left side of the column.
  1436.      */
  1437.     public Color getColumnLeftLineColor(int col) {
  1438.         col--;
  1439.         CellHints hints = getColHints(col);
  1440.         return hints.lineLeftColor;
  1441.     }
  1442.  
  1443.     /**
  1444.      * Sets the right line style for a column. This method is equivalant to calling
  1445.      * setColumnLeftLineStyle() for the next column.
  1446.      * @param col The column number to set the style.
  1447.      * @param style One of NO_LINE, THIN_LINE, THICK_LINE, DASHED_LINE.
  1448.      */
  1449.     public void setColumnRightLineStyle(int col, int style) {
  1450.         if (style < NO_LINE || style > DASHED_LINE) {
  1451.             throw new IllegalArgumentException("Line style " + style + " is not valid");
  1452.         }
  1453.         col--;
  1454.         CellHints hints = getColHints(col);
  1455.         hints.setRightLineStyle(style);
  1456.         if (col < cols()-1) {
  1457.             col++;
  1458.             hints = getColHints(col);
  1459.             hints.setLeftLineStyle(style);
  1460.         }
  1461.     }
  1462.  
  1463.     /**
  1464.      * Gets the right line style for a column. This method is equivalant to calling
  1465.      * getColumnLeftLineStyle() for the next column.
  1466.      * @param col The column number to set the style.
  1467.      * @return style One of NO_LINE, THIN_LINE, THICK_LINE, DASHED_LINE.
  1468.      */
  1469.     public int getRightLineStyle(int col) {
  1470.         col--;
  1471.         CellHints hints = getColHints(col);
  1472.         return hints.lineRightStyle;
  1473.     }
  1474.  
  1475.     /**
  1476.      * Sets the right line color for a column. This method is equivalant to calling
  1477.      * setColumnLeftLineStyle() for the next column.
  1478.      * @param col The column number to set the style.
  1479.      * @param c The line color for the right side of the column.
  1480.      */
  1481.     public void setColumnRightLineColor(int col, Color c) {
  1482.         col--;
  1483.         CellHints hints = getColHints(col);
  1484.         hints.setRightLineColor(c);
  1485.         if (col < cols()-1) {
  1486.             col++;
  1487.             hints = getColHints(col);
  1488.             hints.setLeftLineColor(c);
  1489.         }
  1490.     }
  1491.  
  1492.     /**
  1493.      * Gets the right line color for a column. This method is equivalant to calling
  1494.      * getColumnLeftLineColor() for the previous column.
  1495.      * @param col The column number to set the style.
  1496.      * @return The line color for the right side of the column.
  1497.      */
  1498.     public Color getColumnRightLineColor(int col) {
  1499.         col--;
  1500.         CellHints hints = getColHints(col);
  1501.         return hints.lineRightColor;
  1502.     }
  1503.  
  1504.  
  1505.     /**
  1506.      * Sets the horizontal line style for a view.
  1507.      * @param row The row number to set the style.
  1508.      * @param style One of NO_LINE, THIN_LINE, THICK_LINE, DASHED_LINE.
  1509.      */
  1510.     public void setHorizontalLineStyle(int style) {
  1511.         if (style < NO_LINE || style > DASHED_LINE) {
  1512.             throw new IllegalArgumentException("Line style " + style + " is not valid");
  1513.         }
  1514.  
  1515.         for(int col=0; col<cols(); col++) {
  1516.             CellHints hints = getColHints(col);
  1517.             hints.setTopLineStyle(style);
  1518.             hints.setBottomLineStyle(style);
  1519.         }
  1520.     }
  1521.  
  1522.  
  1523.     /**
  1524.      * Sets the bottom line style for a view.
  1525.      * @param row The row number to set the style.
  1526.      * @param style One of NO_LINE, THIN_LINE, THICK_LINE, DASHED_LINE.
  1527.      */
  1528.     public void setSideLineStyle(int style) {
  1529.         if (style < NO_LINE || style > DASHED_LINE) {
  1530.             throw new IllegalArgumentException("Line style " + style + " is not valid");
  1531.         }
  1532.  
  1533.         for(int col=0; col<cols(); col++) {
  1534.             CellHints hints = getColHints(col);
  1535.             hints.setLeftLineStyle(style);
  1536.             hints.setRightLineStyle(style);
  1537.         }
  1538.     }
  1539.  
  1540.     /**
  1541.      * Sets the top line style for a row. This method is equivalant to calling
  1542.      * setRowBottomLineStyle() for the previous row.
  1543.      * @param row The row number to set the style.
  1544.      * @param style One of NO_LINE, THIN_LINE, THICK_LINE, DASHED_LINE.
  1545.      */
  1546.     public void setRowTopLineStyle(int row, int style) {
  1547.         if (style < NO_LINE || style > DASHED_LINE) {
  1548.             throw new IllegalArgumentException("Line style " + style + " is not valid");
  1549.         }
  1550.  
  1551.         row--;
  1552.         CellHints hints = getRowHints(row);
  1553.         if (hints == null) {
  1554.             hints = new CellHints(this);
  1555.             addRowHint(row,  hints);
  1556.         }
  1557.         hints.setTopLineStyle(style);
  1558.  
  1559.         //set the bottom style of the cell above
  1560.         row--;
  1561.         hints = getRowHints(row);
  1562.         if (hints == null) {
  1563.             hints = new CellHints(this);
  1564.             addRowHint(row, hints);
  1565.         }
  1566.         hints.setBottomLineStyle(style);
  1567.     }
  1568.  
  1569.     /**
  1570.      * Sets the top line color for a row. This method is equivalant to calling
  1571.      * setRowBottomLineColor() for the previous row.
  1572.      * @param row The row number to set the style.
  1573.      * @param c The color of the row line.
  1574.      */
  1575.     public void setRowTopLineColor(int row, Color c) {
  1576.         row--;
  1577.         CellHints hints = getRowHints(row);
  1578.         if (hints == null) {
  1579.             hints = new CellHints(this);
  1580.             addRowHint(row,  hints);
  1581.         }
  1582.         hints.setTopLineColor(c);
  1583.  
  1584.         //set the bottom color of the cell above
  1585.         if (row >= 1) {
  1586.             row--;
  1587.             hints = getRowHints(row);
  1588.             if (hints == null) {
  1589.                 hints = new CellHints(this);
  1590.                 addRowHint(row, hints);
  1591.             }
  1592.             hints.setBottomLineColor(c);
  1593.         }
  1594.     }
  1595.  
  1596.     /**
  1597.      * Sets the bottom line style for a row. This method is equivalant to calling
  1598.      * setRowTopLineStyle() for the next row.
  1599.      * @param row The row number to set the style.
  1600.      * @param style One of NO_LINE, THIN_LINE, THICK_LINE, DASHED_LINE.
  1601.      */
  1602.     public void setRowBottomLineStyle(int row, int style) {
  1603.         if (style < NO_LINE || style > DASHED_LINE) {
  1604.             throw new IllegalArgumentException("Line style " + style + " is not valid");
  1605.         }
  1606.  
  1607.         row--;
  1608.         CellHints hints = getRowHints(row);
  1609.         if (hints == null) {
  1610.             hints = new CellHints(this);
  1611.             addRowHint(row,  hints);
  1612.         }
  1613.         hints.setBottomLineStyle(style);
  1614.  
  1615.         //set the line color for the row below
  1616.         row++;
  1617.         hints = getRowHints(row);
  1618.         if (hints == null) {
  1619.             hints = new CellHints(this);
  1620.             addRowHint(row, hints);
  1621.         }
  1622.         hints.setTopLineStyle(style);
  1623.     }
  1624.  
  1625.     /**
  1626.      * Sets the bottom line color for a row. This method is equivalant to calling
  1627.      * setRowTopLineColor() for the next row.
  1628.      * @param row The row number to set the style.
  1629.      * @param c The color of the row line.
  1630.      */
  1631.     public void setRowBottomLineColor(int row, Color c) {
  1632.         row--;
  1633.         CellHints hints = getRowHints(row);
  1634.         if (hints == null) {
  1635.             hints = new CellHints(this);
  1636.             addRowHint(row,  hints);
  1637.         }
  1638.         hints.setBottomLineColor(c);
  1639.  
  1640.         //set the line color for the row below
  1641.         row--;
  1642.         hints = getRowHints(row);
  1643.         if (hints == null) {
  1644.             hints = new CellHints(this);
  1645.             addRowHint(row, hints);
  1646.         }
  1647.         hints.setTopLineColor(c);
  1648.     }
  1649.  
  1650.     /**
  1651.      * Sets the vertical line style for a row.
  1652.      * @param row The row number to set the style.
  1653.      * @param style One of NO_LINE, THIN_LINE, THICK_LINE, DASHED_LINE.
  1654.      */
  1655.     public void setRowVerticalLineStyle(int row, int style) {
  1656.         if (style < NO_LINE || style > DASHED_LINE) {
  1657.             throw new IllegalArgumentException("Line style " + style + " is not valid");
  1658.         }
  1659.  
  1660.         row--;
  1661.         CellHints hints = getRowHints(row);
  1662.         if (hints == null) {
  1663.             hints = new CellHints(this);
  1664.             addRowHint(row,  hints);
  1665.         }
  1666.         hints.setLeftLineStyle(style);
  1667.         hints.setRightLineStyle(style);
  1668.     }
  1669.  
  1670.     /**
  1671.      * Gets the vertical line style for a row.
  1672.      * @param row The row number to set the style.
  1673.      * @param style One of NO_LINE, THIN_LINE, THICK_LINE, DASHED_LINE; or -1 if row line
  1674.      *      style has not been overriden.
  1675.      */
  1676.     public int getRowVerticalLineStyle(int row, int style) {
  1677.         if (style < NO_LINE || style > DASHED_LINE) {
  1678.             throw new IllegalArgumentException("Line style " + style + " is not valid");
  1679.         }
  1680.  
  1681.         row--;
  1682.         CellHints hints = getRowHints(row);
  1683.  
  1684.         if (hints != null) {
  1685.             return hints.lineLeftStyle;
  1686.         } else {
  1687.             return -1;
  1688.         }
  1689.     }
  1690.  
  1691.     /**
  1692.      * Sets the vertical line color for a row.
  1693.      * @param row The row number to set the style.
  1694.      * @param c The color of the row line.
  1695.      */
  1696.     public void setRowVerticalLineColor(int row, Color c) {
  1697.         row--;
  1698.         CellHints hints = getRowHints(row);
  1699.         if (hints == null) {
  1700.             hints = new CellHints(this);
  1701.             addRowHint(row,  hints);
  1702.         }
  1703.         hints.setLeftLineColor(c);
  1704.         hints.setRightLineColor(c);
  1705.     }
  1706.  
  1707.     /**
  1708.      * Gets the vertical line color for a row.
  1709.      * @param row The row number to set the style.
  1710.      * @return The color of the row line.
  1711.      */
  1712.     public Color getRowVerticalLineColor(int row, int style) {
  1713.         row--;
  1714.         CellHints hints = getRowHints(row);
  1715.  
  1716.         if (hints != null) {
  1717.             return hints.lineLeftColor;
  1718.         } else {
  1719.             return null;
  1720.         }
  1721.     }
  1722.  
  1723.     /**
  1724.      * Sets the line styles for all of the sides for a cell.
  1725.      * @param row The row of the cell.
  1726.      * @param col The column of the cell.
  1727.      * @param t The style for the top of the cell.
  1728.      * @param l The style for the left of the cell.
  1729.      * @param b The style for the bottom of the cell.
  1730.      * @param r The style for the right of the cell.
  1731.      */
  1732.     public void setCellLineStyles(int row, int col, int t, int l, int b, int r) {
  1733.         row--; col--;
  1734.  
  1735.         CellHints h = getCellHints(row, col);
  1736.         if (h == null) {
  1737.             h = new CellHints(this);
  1738.             addCellHint(row, col,  h);
  1739.         }
  1740.         h.setTopLineStyle(t);
  1741.         h.setLeftLineStyle(l);
  1742.         h.setBottomLineStyle(b);
  1743.         h.setRightLineStyle(r);
  1744.  
  1745.         //set style of cell above if not on first row
  1746.         if (row >= 1) {
  1747.             if ((h=getCellHints(row-1, col)) == null) {
  1748.                 h = new CellHints(this);
  1749.                 addCellHint(row-1, col, h);
  1750.             }
  1751.             h.setBottomLineStyle(t);
  1752.         }
  1753.  
  1754.         //set style of cell to left if not first column
  1755.         if (col >= 1) {
  1756.             if ((h=getCellHints(row, col-1)) == null) {
  1757.                 h = new CellHints(this);
  1758.                 addCellHint(row, col-1, h);
  1759.             }
  1760.             h.setRightLineStyle(l);
  1761.         }
  1762.  
  1763.         //set style of cell to cell below
  1764.         if ((h=getCellHints(row+1, col)) == null) {
  1765.             h = new CellHints(this);
  1766.             addCellHint(row+1, col, h);
  1767.         }
  1768.         h.setTopLineStyle(b);
  1769.  
  1770.         //set style of cell to right
  1771.         if ((h=getCellHints(row, col+1)) == null) {
  1772.             h = new CellHints(this);
  1773.             addCellHint(row, col+1, h);
  1774.         }
  1775.         h.setLeftLineStyle(r);
  1776.     }
  1777.  
  1778.     /**
  1779.      * Sets the line colors for all of the sides for a cell.
  1780.      * @param row The row of the cell.
  1781.      * @param col The column of the cell.
  1782.      * @param t The color for the top of the cell.
  1783.      * @param l The color for the left of the cell.
  1784.      * @param b The color for the bottom of the cell.
  1785.      * @param r The color for the right of the cell.
  1786.      */
  1787.     public void setCellLineStyles(int row, int col, Color t, Color l, Color b, Color r) {
  1788.         row--; col--;
  1789.  
  1790.         CellHints hints = getCellHints(row, col);
  1791.         if (hints == null) {
  1792.             hints = new CellHints(this);
  1793.             addCellHint(row, col,  hints);
  1794.         }
  1795.         hints.setTopLineColor(t);
  1796.         hints.setLeftLineColor(l);
  1797.         hints.setBottomLineColor(b);
  1798.         hints.setRightLineColor(r);
  1799.  
  1800.         //set style of cell above if not on first row
  1801.         if (row >= 1) {
  1802.             if ((hints=getCellHints(row-1, col)) == null) {
  1803.                 hints = new CellHints(this);
  1804.                 addCellHint(row-1, col, hints);
  1805.             }
  1806.             hints.setBottomLineColor(t);
  1807.         }
  1808.  
  1809.         //set style of cell to left if not first column
  1810.         if (col >= 1) {
  1811.             if ((hints=getCellHints(row, col-1)) == null) {
  1812.                 hints = new CellHints(this);
  1813.                 addCellHint(row, col-1, hints);
  1814.             }
  1815.             hints.setRightLineColor(l);
  1816.         }
  1817.  
  1818.         //set style of cell to cell below
  1819.         if ((hints=getCellHints(row+1, col)) == null) {
  1820.             hints = new CellHints(this);
  1821.             addCellHint(row+1, col, hints);
  1822.         }
  1823.         hints.setTopLineColor(b);
  1824.  
  1825.         //set style of cell to right
  1826.         if ((hints=getCellHints(row, col+1)) == null) {
  1827.             hints = new CellHints(this);
  1828.             addCellHint(row, col+1, hints);
  1829.         }
  1830.         hints.setLeftLineColor(r);
  1831.     }
  1832.  
  1833.  
  1834.  
  1835. //-----------------------------------------------------------------------------
  1836. //                          Cell Control APIs
  1837. //-----------------------------------------------------------------------------
  1838.  
  1839.     /**
  1840.      * Gets the cell that currently possesses the keyboard focus.<p>
  1841.      * WARNING: This is shared data - Do not hold onto this past current call!!
  1842.      * @return The TableCell that has the keyboard focus.
  1843.      */
  1844.     public TableCell getCurrentCell() {
  1845.         return currSelectedCell;
  1846.     }
  1847.  
  1848.     /**
  1849.      * Gets the data for the cell that currently has the keyboard focus.<p>
  1850.      * WARNING: This is shared data - Do not hold onto this past current call!!
  1851.      * @return The Data instance for the cell that has the keyboard focus.
  1852.      * @exception   DataNotAvailable If the DataSource does not currently have
  1853.      *      data for the cell
  1854.      */
  1855.     public Data getCurrentCellData() throws DataNotAvailable {
  1856.         if (currSelectedCell == null) return null;
  1857.  
  1858.         return dataSource.getData(currSelectedCell.getCoordinates());
  1859.     }
  1860.  
  1861.     /**
  1862.      * Gets the coordinate of the cell that has the keyboard focus
  1863.      */
  1864.     public Coordinate getCurrentCellCoordinates() {
  1865.         if (currSelectedCell == null) return null;
  1866.         Coordinate c =  currSelectedCell.getCoordinates();
  1867.  
  1868.         //make one relative
  1869.         return new Coordinate(c.row()+1, c.col()+1);
  1870.     }
  1871.  
  1872.     /**
  1873.      * Ensures that no cell is marked as the current cell for editing
  1874.      */
  1875.     public /*synchronized*/ void clearCurrentCell() {
  1876.         if (currSelectedCell == null) {
  1877.             return;
  1878.         }
  1879.  
  1880.         sendFocusEvents(currSelectedCell, null);
  1881.     }
  1882.  
  1883.     /**
  1884.      * Sets the cell that has the keyboard focus to the one at the specified
  1885.      * row and column
  1886.      */
  1887.     public /*synchronized*/ void setCurrentCell(int row, int col) {
  1888.  
  1889.       //  System.out.println("TableView: setCurrentCell r:" + row + " c: " + col);
  1890.  
  1891.         row--;
  1892.         col--;
  1893.  
  1894.         TableCell newSelection = null;
  1895.         if (currSelectedCell == null || row != currSelectedCell.row() ||
  1896.             col != currSelectedCell.col())
  1897.         {
  1898.             if (!cells.contains(row, col)) {
  1899.                 if (row < 0 || !validRow(row)
  1900.                     || col < 0 || col >= cols())
  1901.                 {
  1902.                     //row and/or column not valid
  1903.                     return;
  1904.                 }
  1905.  
  1906.                 //then we need to use the default cell
  1907.                   newSelection = getUniqueCell(row, col);
  1908.             } else {
  1909.                 newSelection = (TableCell)cells.elementAt(row, col);
  1910.             }
  1911.  
  1912.             sendFocusEvents(currSelectedCell, newSelection);
  1913.  
  1914.             try {
  1915.                 dataSource.setCurrentRow(row);
  1916.             } catch(TypeNotSupported ex) {
  1917.                 handleException(row, col, ex);
  1918.             }
  1919.         }
  1920.     }
  1921.  
  1922.     /**
  1923.      * Sets the background color for a column
  1924.      */
  1925.     public /*synchronized*/ void setColBgColor(int col, Color bg) {
  1926.         CellHints h = getColHints(col-1);
  1927.         h.bg = bg;
  1928.     }
  1929.  
  1930.     /**
  1931.      * Sts the background color for a row
  1932.      */
  1933.      public /*synchronized*/ void setRowBgColor(int row, Color bg) {
  1934.         row--;
  1935.  
  1936.         CellHints h = getRowHints(row);
  1937.         if (h == null) {
  1938.             h = new CellHints(this);
  1939.             addRowHint(row,  h);
  1940.         }
  1941.  
  1942.         h.set(CellHints.BG_BIT);
  1943.         h.bg = bg;
  1944.     }
  1945.  
  1946.     /**
  1947.      * Sets the background color for a cell
  1948.      */
  1949.     public /*synchronized*/ void setCellBgColor(int row, int col, Color bg) {
  1950.         row--; col--;
  1951.  
  1952.         CellHints h = getCellHints(row, col);
  1953.         if (h == null) {
  1954.             h = new CellHints(this);
  1955.             addCellHint(row, col, h);
  1956.         }
  1957.  
  1958.         h.set(CellHints.BG_BIT);
  1959.         h.bg = bg;
  1960.     }
  1961.  
  1962.     /**
  1963.      * Sets the foreground color for a column
  1964.      */
  1965.     public /*synchronized*/ void setColFgColor(int col, Color fg) {
  1966.         CellHints h = getColHints(col-1);
  1967.         h.fg = fg;
  1968.     }
  1969.  
  1970.     /**
  1971.      * Sets the foreground color for a row
  1972.      */
  1973.      public /*synchronized*/ void setRowFgColor(int row, Color fg) {
  1974.         row--;
  1975.  
  1976.         CellHints h = getRowHints(row);
  1977.         if (h == null) {
  1978.             h = new CellHints(this);
  1979.             addRowHint(row,  h);
  1980.         }
  1981.  
  1982.         h.set(CellHints.FG_BIT);
  1983.         h.fg = fg;
  1984.     }
  1985.  
  1986.     /**
  1987.      * Sets the foreground color for a cell
  1988.      */
  1989.      public /*synchronized*/ void setCellFgColor(int row, int col, Color fg) {
  1990.         row--; col--;
  1991.  
  1992.         CellHints h = getCellHints(row, col);
  1993.         if (h == null) {
  1994.             h = new CellHints(this);
  1995.             addCellHint(row, col, h);
  1996.         }
  1997.  
  1998.         h.set(CellHints.FG_BIT);
  1999.         h.fg = fg;
  2000.     }
  2001.  
  2002.    /**
  2003.      * Set the font of all cell text.
  2004.      * @param col the column to set the font
  2005.      * @param f font instance for cell text
  2006.      */
  2007.     public /*synchronized*/ void setColFont(int col, Font f) {
  2008.         col--;
  2009.         CellHints h = getColHints(col);
  2010.         h.font = f;
  2011.         cellHeight = getFontMetrics(f).getHeight() + 4;
  2012.         if (autoRedraw) { redrawAsync(); }
  2013.     }
  2014.  
  2015.    /**
  2016.      * Set the font of for a row.
  2017.      * @param row the row to set the font
  2018.      * @param f font instance for cell text
  2019.      */
  2020.      public /*synchronized*/ void setRowFont(int row, Font f) {
  2021.         row--;
  2022.  
  2023.         CellHints h = getRowHints(row);
  2024.         if (h == null) {
  2025.             h = new CellHints(this);
  2026.             addRowHint(row,  h);
  2027.         }
  2028.  
  2029.         h.set(CellHints.FONT_BIT);
  2030.         h.font = f;
  2031.     }
  2032.  
  2033.      /**
  2034.       * Set the font of for a cell.
  2035.       */
  2036.      public /*synchronized*/ void setCellFont(int row, int col, Font f) {
  2037.         row--; col--;
  2038.  
  2039.         CellHints h = getCellHints(row, col);
  2040.         if (h == null) {
  2041.             h = new CellHints(this);
  2042.             addCellHint(row, col, h);
  2043.         }
  2044.  
  2045.         h.set(CellHints.FONT_BIT);
  2046.         h.font = f;
  2047.     }
  2048.  
  2049.    /**
  2050.      * Returns the current font setting for cell text.
  2051.      */
  2052.     public Font getColFont(int col) {
  2053.         col--;
  2054.         return getColHints(col).font();
  2055.     }
  2056.  
  2057.     public /*synchronized*/ void setColDefaultCell(int col, TableCell c) {
  2058.         col--;
  2059.         CellHints h = getColHints(col);
  2060.         h.setDefaultCell(c);
  2061.  
  2062.         if (autoRedraw) { redrawAsync(); }
  2063.     }
  2064.  
  2065.      public /*synchronized*/ void setRowDefaultCell(int row, TableCell c) {
  2066.         row--;
  2067.  
  2068.         CellHints h = getRowHints(row);
  2069.         if (h == null) {
  2070.             h = new CellHints(this);
  2071.             addRowHint(row,  h);
  2072.         }
  2073.  
  2074.         h.setDefaultCell(c);
  2075.     }
  2076.  
  2077.     public TableCell getColDefaultCell(int col) {
  2078.         col--;
  2079.         return getColHints(col).defaultCell();
  2080.     }
  2081.  
  2082.     /**
  2083.      * Sets whether the cells in a column may be edited
  2084.      */
  2085.     public /*synchronized*/ void setColEditable(int col, boolean edit) {
  2086.         // align must be LEFT, CENTER, or RIGHT
  2087.         CellHints h = getColHints(col-1);
  2088.         h.editable = edit;
  2089.     }
  2090.  
  2091.     /**
  2092.      * Sets whether the cells in a row may be edited
  2093.      */
  2094.      public /*synchronized*/ void setRowEditable(int row, boolean edit) {
  2095.         row--;
  2096.  
  2097.         CellHints h = getRowHints(row);
  2098.         if (h == null) {
  2099.             h = new CellHints(this);
  2100.             addRowHint(row,  h);
  2101.         }
  2102.  
  2103.         h.set(CellHints.EDITABLE_BIT);
  2104.         h.editable = edit;
  2105.     }
  2106.  
  2107.     /**
  2108.      * Sets whether a cell can be edited
  2109.      */
  2110.     public /*synchronized*/ void setCellEditable(int row, int col, boolean edit) {
  2111.         row--; col--;
  2112.  
  2113.         CellHints h = getCellHints(row, col);
  2114.         if (h == null) {
  2115.             h = new CellHints(this);
  2116.             addCellHint(row, col, h);
  2117.         }
  2118.  
  2119.         h.set(CellHints.EDITABLE_BIT);
  2120.         h.editable = edit;
  2121.     }
  2122.  
  2123.     /**
  2124.      * Clears the CellHints for a cell
  2125.      */
  2126.     public /*synchronized*/ void clearCellHint(int row, int col, int bit) {
  2127.         row--; col--;
  2128.  
  2129.         CellHints h = getCellHints(row, col);
  2130.         if (h != null) {
  2131.             h.clear(bit);
  2132.         }
  2133.     }
  2134.  
  2135.     /**
  2136.      * Clears the CellHints for a row
  2137.      */
  2138.     public /*synchronized*/ void clearRowHint(int row, int bit) {
  2139.         row--;
  2140.  
  2141.         CellHints h = getRowHints(row);
  2142.         if (h != null) {
  2143.             h.clear(bit);
  2144.         }
  2145.     }
  2146.  
  2147.     /**
  2148.      * Gets whether CellHints a set for a particular cell.
  2149.      * @param row The cell row
  2150.      * @param col The cell column
  2151.      * @param bit The particular variable of the hint that is of interest as
  2152.      *      defined in CellHints
  2153.      */
  2154.     public boolean isCellHintSet(int row, int col, int bit) {
  2155.         row--; col--;
  2156.  
  2157.         CellHints h = getCellHints(row, col);
  2158.         if (h != null) {
  2159.             return h.get(bit);
  2160.         }
  2161.  
  2162.         return false;
  2163.     }
  2164.  
  2165.     /**
  2166.      * Gets whether CellHints a set for a particular row.
  2167.      * @param row The cell row
  2168.      * @param bit The particular variable of the hint that is of interest as
  2169.      *      defined in CellHints
  2170.      */
  2171.     public boolean isRowHintSet(int row, int bit) {
  2172.         row--;
  2173.  
  2174.         CellHints h = getRowHints(row);
  2175.         if (h != null) {
  2176.             return h.get(bit);
  2177.         }
  2178.  
  2179.         return false;
  2180.     }
  2181.  
  2182.     /**
  2183.      * Gets whether CellHints a set for a particular column.
  2184.      * @param col The cell column
  2185.      * @param bit The particular variable of the hint that is of interest as
  2186.      *      defined in CellHints
  2187.      */
  2188.     public boolean getColEditable(int col) {
  2189.         col--;
  2190.         return getColHints(col).editable();
  2191.     }
  2192.  
  2193.     /**
  2194.      * Sets whether the column heading of interest is editable.
  2195.      */
  2196.     public /*synchronized*/ void setHeadingEditable(int col, boolean edit) {
  2197.         CellHints h = getHeadingHints(0, col);
  2198.         h.editable = edit;
  2199.     }
  2200.  
  2201.     /**
  2202.      * Gets whether the column heading of interest is editable.
  2203.      */
  2204.     public boolean getHeadingEditable(int col) {
  2205.         return getHeadingHints(0, col).editable();
  2206.     }
  2207.  
  2208.     /**
  2209.      * Set the heading foreground and background colors of the heading hints
  2210.      * @fg foreground Color for heading text
  2211.      * @bg background Color for heading text
  2212.      */
  2213.     public /*synchronized*/ void setHeadingColors(int col, Color fg, Color bg) {
  2214.         CellHints h = getHeadingHints(0, col);
  2215.         h.fg = fg;
  2216.         h.bg = bg;
  2217.         if (autoRedraw) { redrawAsync(); }
  2218.     }
  2219.  
  2220.     /**
  2221.      * Returns the color of the column heading foreground.
  2222.      */
  2223.     public Color getHeadingFg(int col) {
  2224.         CellHints h = getHeadingHints(0, col);
  2225.         return h.fg;
  2226.     }
  2227.  
  2228.     /**
  2229.      * Returns the color of the column heading background.
  2230.      */
  2231.     public Color getHeadingBg(int col) {
  2232.         CellHints h = getHeadingHints(0, col);
  2233.         return h.bg;
  2234.     }
  2235.  
  2236.     /**
  2237.      * Get the column size in pixels for the specified column.
  2238.      * @param i number of column (one relative)
  2239.      */
  2240.     public int getColumnSize(int i) {
  2241.         return getColumnWidth(i-1);
  2242.     }
  2243.  
  2244.     /**
  2245.      * Set the justification of the text for the specified column.
  2246.      * @param i number of column (one relative)
  2247.      * @param align one of the values LEFT, CENTER, or RIGHT
  2248.      */
  2249.     public /*synchronized*/ void setColumnAlignment(int col, int align) {
  2250.         // align must be LEFT, CENTER, or RIGHT
  2251.         CellHints h = getColHints(col-1);
  2252.         h.align = align;
  2253.         h = getHeadingHints(0, col);
  2254.         h.align = align;
  2255.     }
  2256.  
  2257.  
  2258.     /**
  2259.      * Returns the current number of columns.
  2260.      */
  2261.     public int cols() {
  2262.         return splitters.length - 1;
  2263.     }
  2264.  
  2265.     /**
  2266.      * Ensures the topRow variable is valid
  2267.      */
  2268.     public void setTopRow() {
  2269.         setTopRow(-1);
  2270.     }
  2271.  
  2272.     /**
  2273.      * Sets the top row to be displayed when table is drawn.
  2274.      */
  2275.     public /*synchronized*/ void setTopRow(int row) {
  2276.         //visible from outside so row is one relative
  2277.         if (row >= 1) {
  2278.             if (vsb.isVisible()) {
  2279.                 vsb.setValue(row-1);
  2280.                 topRow = vsb.getValue();
  2281.             } else {
  2282.                 topRow = row-1;
  2283.             }
  2284.         }
  2285.  
  2286.         try {
  2287.             int dataRows = dataSource.validDataRowRange(0, topRow+1);
  2288.         } catch(DataNotAvailable exc) {
  2289.             //no data so all up to cells
  2290.             if (topRow <= cells.rows()-1) {
  2291.                 //there are enough cells so everything is OK
  2292.                 return;
  2293.             }
  2294.  
  2295.             //Need to reset topRow to valid number so how about 0
  2296.             topRow = 0;
  2297.         }
  2298.     }
  2299.  
  2300.     /**
  2301.      * Gets the top row that is used when the TableView is drawn.<p>
  2302.      * WARNING: The value returned is 0 relative
  2303.      * @return The top row - 0 relative
  2304.      */
  2305.     public int getTopRow() {
  2306.         return topRow;
  2307.     }
  2308.  
  2309.     /**
  2310.      * Gets the actual number of rows being painted.
  2311.      */
  2312.     public int getNumberOfVisibleRows() {
  2313.         setTopRow();
  2314.         int count = (int)((height-3)/cellHeight) + 1;
  2315.  
  2316.         try {
  2317.             int dataRows = dataSource.validDataRowRange(topRow, topRow+count);
  2318.             int lastCellRow = cells.rows()-1;
  2319.             count = Math.min(count, Math.max(dataRows, lastCellRow)-topRow+1);
  2320.         } catch(DataNotAvailable exc) {
  2321.             //no data so all up to cells
  2322.             if (count > cells.rows()) {
  2323.                 count = cells.rows()-topRow;
  2324.             }
  2325.         }
  2326.  
  2327.         return count;
  2328.     }
  2329.  
  2330.     /**
  2331.      * Sets the mouse capture to the currently selected cell.
  2332.      */
  2333.     public void setCapture() {
  2334.         if (rowHeadingCell(currCaptureCell) && currSelectedCell != currCaptureCell) {
  2335.             currHeadingCell = null;
  2336.         }
  2337.  
  2338.         currCaptureCell = currSelectedCell;
  2339.     }
  2340.  
  2341.     /**
  2342.      * Set mouse capture to a particular cell
  2343.      */
  2344.     public void setCapture(TableCell c) {
  2345.         if (rowHeadingCell(currCaptureCell) && c != currCaptureCell) {
  2346.             currHeadingCell = null;
  2347.         }
  2348.  
  2349.         currCaptureCell = c;
  2350.     }
  2351.  
  2352.     /**
  2353.      * Removes the mouse capture if a cell currently possess it.
  2354.      */
  2355.     public void lostCapture() {
  2356.         if (rowHeadingCell(currCaptureCell)) {
  2357.             currHeadingCell = null;
  2358.         }
  2359.  
  2360.         currCaptureCell = null;
  2361.     }
  2362.  
  2363.     /**
  2364.      * Gets whether a cell currently has mouse capture.
  2365.      */
  2366.     public boolean cellHasCapture() {
  2367.         return currCaptureCell != null;
  2368.     }
  2369.  
  2370.     /**
  2371.      * Remove all rows from the TableView.
  2372.      */
  2373.     public /*synchronized*/ void clear() {
  2374.         clearAllSelections();
  2375.         cells.removeAllElements();
  2376.         dataSource.clear();
  2377.         xDragLast = -1;
  2378.         isDragging = false;
  2379.         topRow = 0;
  2380.         leftCol = lockedColumn+1/*next col*/ +1 /*one relative*/;
  2381.         vsb.setValue(0);
  2382.         hsb.setValue(0);
  2383.         currSelectedCell = currCaptureCell = null;
  2384.  
  2385.         if (autoRedraw) { redrawAsync(); }
  2386.     }
  2387.  
  2388.     /**
  2389.      * Adds a cell to the TableView
  2390.      * @param cell The cell to be displayed
  2391.      * @param s The value for the cell
  2392.      * @exception   TypeNotSupported If action is not supported by the DataSource
  2393.      */
  2394.     public /*synchronized*/ void addCell(TableCell cell, String s) throws TypeNotSupported {
  2395.         cell = cell.cloneCell();
  2396.         cell.setTableView(this, dataSource);
  2397.         cells.updateElement(cell.row(), cell.col(), cell);
  2398.         dataSource.setData(cell.getCoordinates(),
  2399.                            new ImageStringData(dataSource, s));
  2400.         if (autoRedraw) { redrawAsync(); }
  2401.     }
  2402.  
  2403.     /**
  2404.      * Adds or changes the text of a row and column position.
  2405.      * @param r index of row
  2406.      * @param c index of column
  2407.      * @param s String text for cell
  2408.      * @exception   TypeNotSupported If action is not supported by the DataSource
  2409.      */
  2410.     public /*synchronized*/ void addTextCell(int r, int c, String s) throws TypeNotSupported {
  2411.         r--; c--;
  2412.         dataSource.setData(r, c, new ImageStringData(dataSource, s));
  2413.  
  2414.         if (autoRedraw) {
  2415.             redrawAsync();
  2416.         }
  2417.     }
  2418.  
  2419.     /**
  2420.      * Adds or changes the image of a row and column position.
  2421.      * @param r index of row
  2422.      * @param c index of column
  2423.      * @param i image instance for cell
  2424.      * @exception   TypeNotSupported If action is not supported by the DataSource
  2425.      */
  2426.     public /*synchronized*/ void addImageCell(int r, int c, Image i) throws TypeNotSupported {
  2427.         r--; c--;
  2428.         dataSource.setData(r, c, new ImageStringData(dataSource, i));
  2429.         if (autoRedraw) {
  2430.             redrawAsync();
  2431.         }
  2432.     }
  2433.  
  2434.     /**
  2435.      * Add/change contents of a cell, both text and image.
  2436.      * @param r index of row
  2437.      * @param c index of column
  2438.      * @parma s string text for cell
  2439.      * @param i image instance for cell
  2440.      * @exception   TypeNotSupported If action is not supported by the DataSource
  2441.      */
  2442.     public /*synchronized*/ void addCell(int r, int c, String s, Image i) throws TypeNotSupported {
  2443.         r--; c--;
  2444.         dataSource.setData(r, c, new ImageStringData(dataSource, s, i));
  2445.         if (autoRedraw) {
  2446.             redrawAsync();
  2447.         }
  2448.     }
  2449.  
  2450.     /**
  2451.      * Returns string text of specified cell.
  2452.      * @param r index of row
  2453.      * @param c index of column
  2454.      * @exception   DataNotAvailable cell data does not exist in the data sourse
  2455.      */
  2456.     public String getCellText(int r, int c) throws DataNotAvailable {
  2457.         r--; c--;
  2458.         return dataSource.getData(r, c).toString();
  2459.     }
  2460.  
  2461.  
  2462.     /**
  2463.      * Gets the data value for a specified cell
  2464.      * @param r index of row
  2465.      * @param c index of column
  2466.      * @exception   DataNotAvailable cell data does not exist in the data sourse
  2467.      */
  2468.     public Data getCellData(int r, int c) throws DataNotAvailable {
  2469.         r--; c--;
  2470.         return dataSource.getData(r, c);
  2471.     }
  2472.  
  2473.    /**
  2474.     * Gets the FontMetrics for the specified cell
  2475.     */
  2476.    public FontMetrics getCellFontMetrics(TableCell c) {
  2477.         Font f = getCellFont(c);
  2478.         return getFontMetrics(f);
  2479.     }
  2480.  
  2481.     /**
  2482.      * Inherited from Component.
  2483.      */
  2484.     public void update(Graphics g) {
  2485.         paint(g);
  2486.     }
  2487.  
  2488.     Rectangle getClientArea() {
  2489.         Dimension d = size();
  2490.         d.height -= bottomPanel.preferredSize().height;
  2491.         d.width -= vsb.preferredSize().width;
  2492.  
  2493.         return new Rectangle(0, 0, d.width, d.height);
  2494.     }
  2495.  
  2496.     boolean printMode;
  2497.     /**
  2498.      * Gets whether the TableView is currently printing.
  2499.      */
  2500.     protected boolean printMode() { return printMode; }
  2501.  
  2502.     /**
  2503.      * Prints the TableView.
  2504.      */
  2505.     public void print(Graphics g) {
  2506.         if (!isVisible() || gg == null) { return; }
  2507.  
  2508.         if (!(g instanceof PrintGraphics)) {
  2509.             paint(g);
  2510.             return;
  2511.         }
  2512.  
  2513.         synchronized(gg) {
  2514.             try {
  2515.                 printMode = true;
  2516.                 Graphics realG = gg;
  2517.                 gg = g.create();
  2518.                 gg.setClip(getClientArea());
  2519.                 forceRedraw(false);
  2520.                 gg = realG;
  2521.                 super.print(g);
  2522.             } finally {
  2523.                 printMode = false;
  2524.             }
  2525.         }
  2526.     }
  2527.  
  2528.     /**
  2529.      * Inherited from Component.
  2530.      */
  2531.     public void paint(Graphics g) {
  2532.         if (g instanceof PrintGraphics) {
  2533.             print(g);
  2534.             return;
  2535.         }
  2536.  
  2537.         if ((width!=size().width) || height!=size().height)  {
  2538.             redrawAsync();
  2539.         }
  2540.         if (im == null) { return; }
  2541.  
  2542.         g.drawImage(im, 0, 0, this);
  2543.  
  2544.     }
  2545.  
  2546.     /**
  2547.      * Inherited from Component.
  2548.      */
  2549.     public void addNotify() {
  2550.         super.addNotify();
  2551.         repaint();
  2552.     }
  2553.  
  2554.  
  2555.     /**
  2556.      * Gets the number of rows
  2557.      */
  2558.     public int rows() {
  2559.         return Math.max(cells.rows(), dataSource.rows());
  2560.     }
  2561.  
  2562.     void showScrollbars() {
  2563.         Dimension d = size(),
  2564.                   actualViewSize = new Dimension(),
  2565.                   reqdViewSize = new Dimension(),
  2566.                   hsbSize = bottomPanel.preferredSize(),
  2567.                   vsbSize = vsb.preferredSize();
  2568.         boolean   changed = false;
  2569.         int       reqdHeight = cells.rows();
  2570.         int       scrollableCols = cols() - (lockedColumn+1);
  2571.  
  2572.         try {
  2573.             int dataRows = dataSource.validDataRowRange(0,getPageSize().height+2+topRow);
  2574.             reqdHeight = Math.max(reqdHeight, dataSource.rows());
  2575.         } catch(DataNotAvailable exc) {}
  2576.  
  2577.         actualViewSize.height = height - headingHeight - 3 - bottomPanel.size().height;
  2578.         actualViewSize.width = d.width - rowHeadingWidth;
  2579.         reqdViewSize.height = reqdHeight * cellHeight;
  2580.         reqdViewSize.width = splitters[splitters.length-1];
  2581.  
  2582.         //if locking column only need enough space to show scrollable columns to
  2583.         //determine if horizontal scrollbar required.
  2584.         if (lockedColumn != -1) {
  2585.             reqdViewSize.width -= splitters[lockedColumn+1];
  2586.             actualViewSize.width -= splitters[lockedColumn+1];
  2587.         }
  2588.  
  2589.         //compensate for hidden columns
  2590.         int cols = cols();
  2591.         int firstScrollableCol=-1, lastScrollableCol=-1;
  2592.         for (int i=0; i<cols; i++) {
  2593.             if (colHidden[i]) {
  2594.                 if (isColumnLocked(i+1)) {
  2595.                     //increase actual view size since locked column not visible
  2596.                     actualViewSize.width += getColumnWidth(i+1);
  2597.                 } else {
  2598.                     scrollableCols--;
  2599.                     //reduce required width by width of hidden column
  2600.                     reqdViewSize.width -= getColumnWidth(i+1);
  2601.                 }
  2602.             } else {
  2603.                 //not hidden so adjust scroll indexes
  2604.                 if (!isColumnLocked(i+1)) {
  2605.                     if (firstScrollableCol == -1) {
  2606.                         firstScrollableCol = i;
  2607.                     }
  2608.                 }
  2609.             }
  2610.         }
  2611.  
  2612.         //check to see if horizontal scrollbar will be shown
  2613.         if (reqdViewSize.width > actualViewSize.width) {
  2614.             //definitely reqd
  2615.             actualViewSize.height -= hsbSize.height;
  2616.         } else if (reqdViewSize.width > actualViewSize.width - vsbSize.width) {
  2617.             //see if acutally need vertical scrollbar
  2618.             if (reqdViewSize.height > actualViewSize.height - hsbSize.height) {
  2619.                 //should need veritcal vsb and thus hsb scrollbar
  2620.                 actualViewSize.height -= hsbSize.height;
  2621.             }
  2622.         }
  2623.  
  2624.         //show vertical scrollbar if appropriate
  2625.         if (reqdViewSize.height > actualViewSize.height) {
  2626.             vsb.setValues(topRow, getPageSize().height, 0, reqdHeight-1);
  2627.             vsb.setPageIncrement(getPageSize().height);
  2628.             vsb.show();
  2629.             changed = true;
  2630.             actualViewSize.width -= vsbSize.width;
  2631.         } else {
  2632.             topRow = 0;
  2633.             vsb.hide();
  2634.         }
  2635.  
  2636.         //show horizontal scrollbar if appropriate
  2637.         if (reqdViewSize.width > actualViewSize.width) {
  2638.             //determine what the last column completely visible is
  2639.             int i = 1;
  2640.             int row = 0, col = 0;
  2641.             if (currSelectedCell != null) {
  2642.                 Coordinate c = currSelectedCell.getCoordinates();
  2643.                 row = c.row;
  2644.                 col = c.col;
  2645.             }
  2646.  
  2647.             int shiftLeft = splitters[leftCol - 1] + rowHeadingWidth;
  2648.             for (;i<splitters.length; i++) {
  2649.                 if (splitters[i] - shiftLeft > actualViewSize.width) break;
  2650.             }
  2651.  
  2652.             if (vsb.isVisible()) {
  2653.                 actualViewSize.width -= vsb.size().width;
  2654.             }
  2655.  
  2656.             //set hsb values
  2657.             int sliderWidth = (int)((float)actualViewSize.width/reqdViewSize.width*scrollableCols);
  2658.             hsb.setValues(hsbPosition,
  2659.                           sliderWidth,
  2660.                           firstScrollableCol+1,
  2661.                           firstScrollableCol+scrollableCols);
  2662.             hsb.setPageIncrement(sliderWidth);
  2663.             hsb.show();
  2664.             changed = true;
  2665.         } else {
  2666.             hsbPosition = leftCol = lockedColumn+1/*next col*/ +1 /*one relative*/;
  2667.             hsb.hide();
  2668.         }
  2669.  
  2670.         if (changed) {
  2671.             setupSpacer();
  2672.             bottomPanel.validate();
  2673.             doLayout();
  2674.         }
  2675.     }
  2676.  
  2677.     void setupSpacer() {
  2678.         if (vsb.isVisible() && hsb.isVisible()) {
  2679.             spacer.setVisible(true);
  2680.             int width = vsb.getPreferredSize().width;
  2681.             spacer.setSize(width, width);
  2682.         } else {
  2683.             spacer.setVisible(false);
  2684.             spacer.setSize(0, 0);
  2685.         }
  2686.     }
  2687.  
  2688.     /**
  2689.      * Inherited from Component.
  2690.      */
  2691.     public void show() {
  2692.  
  2693.         super.show();
  2694.     }
  2695.  
  2696.     /**
  2697.      * Get the height of the heading row.
  2698.      */
  2699.     public final int getHeadingHeight() {
  2700.         return headingHeight;
  2701.     }
  2702.  
  2703.     /**
  2704.      * Gets the height of each cell row.
  2705.      */
  2706.     public final int getCellHeight() {
  2707.         return cellHeight;
  2708.     }
  2709.  
  2710.     /**
  2711.      * Gets the width of the specified column.
  2712.      */
  2713.     public final int getColumnWidth(int col) {
  2714.         col--;
  2715.  
  2716.         if (fillLastColumn && col == cols()-1) {
  2717.             return size().width - splitters[col] + 1;
  2718.         } else {
  2719.             return splitters[col+1] - splitters[col];
  2720.         }
  2721.     }
  2722.  
  2723.  
  2724.     /**
  2725.      * Gets whether the cell is the corner cell.
  2726.      */
  2727.     public final boolean cornerCell(TableCell c) {
  2728.         return c == cornerCell;
  2729.     }
  2730.  
  2731.     /**
  2732.      * Gets whether the cell is a column heading cell.
  2733.      */
  2734.     public final boolean colHeadingCell(TableCell c) {
  2735.         return c.type() == TableCell.COL_HEADING;
  2736.     }
  2737.  
  2738.     /**
  2739.      * Gets whether the cell is a row heading cell.
  2740.      */
  2741.     public final boolean rowHeadingCell(TableCell cell) {
  2742.         return cell != null &&
  2743.                (cell == headingCell || cell == currHeadingCell
  2744.                 || cell.type() == TableCell.ROW_HEADING);
  2745.     }
  2746.  
  2747.     /**
  2748.      * Gets the bounding rectangle of a cell relative to the TableView
  2749.      */
  2750.     public final Rectangle getCellBounds(TableCell cell) {
  2751.         return getCellBounds(cell, null);
  2752.     }
  2753.  
  2754.     /**
  2755.      * Gets the bounding rectangle of a cell relative to the TableView
  2756.      * @param cell The cell to fetch the bounds
  2757.      * @param b The rectangle object to place bounds in
  2758.      */
  2759.     public final Rectangle getCellBounds(TableCell cell, Rectangle b) {
  2760.         Coordinate p = cell.getCoordinates();
  2761.  
  2762.         if (cell == cornerCell) {
  2763.             if (b == null) {
  2764.                 b = new Rectangle(0, 0, rowHeadingWidth+1, headingHeight+2);
  2765.             } else {
  2766.                 b.setBounds(0, 0, rowHeadingWidth+1, headingHeight+2);
  2767.             }
  2768.             return b;
  2769.         } else if (rowHeadingCell(cell)) {
  2770.             return getRowHeadingBounds(cell, b);
  2771.         } else if (cell.type() == TableCell.COL_HEADING) {
  2772.             return getHeadingCellBounds(p, b);
  2773.         }
  2774.  
  2775.         return getCellBounds(p, b);
  2776.     }
  2777.  
  2778.     /**
  2779.      * Gets the height of the row. Presently, all rows have the same height.
  2780.      * @return Row height in pixels.
  2781.      */
  2782.     public final int getRowHeight(int row) {
  2783.         row--;
  2784.  
  2785.         //for now all rows have the same height
  2786.         return cellHeight+1;
  2787.     }
  2788.  
  2789.     public final int getRowStartY(int row) {
  2790.         row--;
  2791.         return (row-topRow)*cellHeight + headingHeight + 2;
  2792.     }
  2793.  
  2794.     /**
  2795.      * Gets the counds of the table cell at the specified coordinates.
  2796.      */
  2797.     private final Rectangle getCellBounds(Coordinate c, Rectangle b) {
  2798.         if (colHidden[c.col]) {
  2799.             throw new IllegalArgumentException("Column # " + c.col + " is hidden");
  2800.         }
  2801.  
  2802.         int colStart[] = getColStartPositions();
  2803.         int row = c.row;
  2804.         int col = c.col;
  2805.         int w = getColumnWidth(col+1);
  2806.         int left = colStart[col];
  2807.  
  2808.         //compensate for boundary
  2809.         if (leftCol-1 == col) { left++; }
  2810.         else { w++; }
  2811.  
  2812.         if (b == null) {
  2813.             b = new Rectangle();
  2814.         }
  2815.  
  2816.         if (w > width  - rowHeadingWidth) {
  2817.             w = width - rowHeadingWidth;
  2818.             if (vsb.isVisible()) { w -= vsb.size().width; }
  2819.         }
  2820.  
  2821.         b.reshape(left,
  2822.                   getRowStartY(row+1),
  2823.                   w,
  2824.                   getRowHeight(row+1));
  2825.         return b;
  2826.     }
  2827.  
  2828.     /**
  2829.      * Gets the bounds of the column heading cell at the specified coordinate
  2830.      * @param coords The coordinates of the heading
  2831.      * @param b The rectangle to place the bounds values
  2832.      */
  2833.     public final Rectangle getHeadingCellBounds(Coordinate coords, Rectangle b) {
  2834.         int colStart[] = getColStartPositions();
  2835.  
  2836.         int row = coords.row;
  2837.         int col = coords.col;
  2838.         int w = getColumnWidth(col+1);
  2839.         int left = colStart[col];
  2840.  
  2841.         if (col == 0) { left++; }
  2842.         else { w++; }
  2843.  
  2844.         if (b == null) {
  2845.             b = new Rectangle();
  2846.         }
  2847.  
  2848.  
  2849.         if (w > width  - rowHeadingWidth) {
  2850.             w = width - rowHeadingWidth;
  2851.             if (vsb.isVisible()) { w -= vsb.size().width; }
  2852.         }
  2853.  
  2854.         b.reshape(left, 0, w, headingHeight+2);
  2855.  
  2856.         return b;
  2857.     }
  2858.  
  2859.     /**
  2860.      * Gets the bounds of the row heading cell at the specified coordinate
  2861.      * @param cell The row heading cell
  2862.      * @param b The rectangle to place the bounds values
  2863.      */
  2864.     public final Rectangle getRowHeadingBounds(TableCell cell, Rectangle b) {
  2865.         if (b == null) {
  2866.             b = new Rectangle();
  2867.         }
  2868.  
  2869.         b.x = 0;
  2870.         b.y = getRowStartY(cell.row()+1);
  2871.         b.width = rowHeadingWidth+1;
  2872.         b.height = getRowHeight(cell.row()+1);
  2873.  
  2874.         return b;
  2875.     }
  2876.  
  2877.     /**
  2878.      * Redraws a particular cell only.<p>
  2879.      * This function should only be called if selection has not changed since last
  2880.      * redraw.  This function is provided to more efficiently redraw individual
  2881.      * cell updates
  2882.      */
  2883.     public void redrawCell(TableCell c) {
  2884.         redrawCell(c, true);
  2885.     }
  2886.  
  2887.     /**
  2888.      * Redraws a particular cell only.<p>
  2889.      * This function should only be called if selection has not changed since last
  2890.      * redraw.  This function is provided to more efficiently redraw individual
  2891.      * cell updates
  2892.      * @param c The cell to redraw
  2893.      * @param makeVisible Specifies whether the cell should be scrolled
  2894.      *      to make visible before being drawn
  2895.      */
  2896.     public final /*synchronized*/ void redrawCell(TableCell c, boolean makeVisible) {
  2897.         redrawCell(c, makeVisible, true);
  2898.     }
  2899.  
  2900.     /**
  2901.      * Redraws a particular cell only.<p>
  2902.      * This function should only be called if selection has not changed since last
  2903.      * redraw.  This function is provided to more efficiently redraw individual
  2904.      * cell updates
  2905.      * @param c The cell to redraw
  2906.      * @param makeVisible Specifies whether the cell should be scrolled
  2907.      *      to make visible before being drawn
  2908.      * @param repaint Repaint whole TableView after redraw of cell.
  2909.      */
  2910.     public final /*synchronized*/ void redrawCell(TableCell c, boolean makeVisible,
  2911.                                               boolean repaint)
  2912.     {
  2913.         if (disableDrawing) { return; }
  2914.  
  2915.         if (colHidden[c.col()]) {
  2916.             //hidden so do not draw
  2917.             return;
  2918.         }
  2919.  
  2920.         if (!isColumnDisplayed(c.col()+1) || !isRowDisplayed(c.row()+1)) {
  2921.             //not visible so no need to paint just make the cell visible and
  2922.             //the view will be redrawn automatically.
  2923.             if (makeVisible) {
  2924.                 makeCellVisible(c.row()+1, c.col()+1);
  2925.             }
  2926.             return;
  2927.         }
  2928.  
  2929.         try {
  2930.             if (gg == null) { return; }
  2931.             if (!fetchMode) { dataSource.fetchMode(true); }
  2932.  
  2933.             if (c != cornerCell && c.type() != TableCell.COL_HEADING
  2934.                 && makeVisible && isCellVisible(c.row()+1, c.col()+1))
  2935.             {
  2936.                 //make sure cell is visible if not heading
  2937.                 makeCellVisible(c.row()+1, c.col()+1);
  2938.             }
  2939.  
  2940.             hints.setHints(c);
  2941.  
  2942.             //clear rectangle
  2943.             gg.setColor(getBackground());
  2944.             Rectangle r = hints.bounds();
  2945.  
  2946.             //create a clipped graphics context.
  2947.             Graphics cellG = gg.create();
  2948.             Shape s = gg.getClip();
  2949.             if (s != null) {
  2950.                 cellG.setClip(s);
  2951.             }
  2952.  
  2953.             cellG.clipRect(r.x, r.y, r.width, r.height);
  2954.             cellG.fillRect(r.x, r.y, r.width-1, r.height-1);
  2955.             cellG.setColor(getForeground());
  2956.  
  2957.             c.drawCell(cellG, hints);
  2958.             if (c == currSelectedCell && c.isCellTypeEditable()) {
  2959.                 frameCurrentCells();
  2960.             }
  2961.  
  2962.             if (repaint) {
  2963.                 //refresh the screen
  2964.                 paint(getGraphics());
  2965.             }
  2966.         } finally {
  2967.             if (!fetchMode) { dataSource.fetchMode(false); }
  2968.         }
  2969.     }
  2970.  
  2971.     /**
  2972.      * Redraws a particular cell only.<p>
  2973.      * This function should only be called if selection has not changed since last
  2974.      * redraw.  This function is provided to more efficiently redraw individual
  2975.      * cell updates.  This function is internal so it is 0 relative.
  2976.      * @param row The row of the cell to redraw
  2977.      * @param col The column of the cell to redraw
  2978.      * @param makeVisible Specifies whether the cell should be scrolled
  2979.      *      to make visible before being drawn
  2980.      */
  2981.     protected final void redrawCell(int row, int col, boolean makeVisible) {
  2982.         redrawCell(row, col, makeVisible, true);
  2983.     }
  2984.  
  2985.     /**
  2986.      * Redraws a particular cell only.<p>
  2987.      * This function should only be called if selection has not changed since last
  2988.      * redraw.  This function is provided to more efficiently redraw individual
  2989.      * cell updates.  This function is internal so it is 0 relative.
  2990.      * @param row The row of the cell to redraw
  2991.      * @param col The column of the cell to redraw
  2992.      * @param makeVisible Specifies whether the cell should be scrolled
  2993.      *      to make visible before being drawn
  2994.      * @param repaint Repaint whole TableView after redraw of cell.
  2995.      */
  2996.     protected final void redrawCell(int row, int col, boolean makeVisible,
  2997.                                    boolean repaint)
  2998.     {
  2999.         if (disableDrawing) { return; }
  3000.  
  3001.         if (!validRow(row)) {
  3002.             //not asking to redraw a column heading
  3003.             return;
  3004.         } else if (col > -1 && !validCol(col)) {
  3005.             //not asking to redraw a row heading
  3006.             return;
  3007.         } else if (col == -1 && validRow(row)) {
  3008.             redrawRowHeadingCell(row);
  3009.             return;
  3010.         } else if (col == -1 && row == -1) {
  3011.             //corner cell and we are not worried about it
  3012.             return;
  3013.         }
  3014.  
  3015.         TableCell c = getUniqueCell(row, col);
  3016.         redrawCell(c, makeVisible);
  3017.         //vj: Redraw the row heading to show the state of the row
  3018.         redrawRowHeadingCell(c.row());
  3019.         drawTableBoundary();
  3020.     }
  3021.  
  3022.     /**
  3023.      * Redraws all the cells in a row.
  3024.      */
  3025.     public /*synchronized*/ void redrawRow(int row) {
  3026.         if (disableDrawing) { return; }
  3027.  
  3028.         row--;
  3029.         if(!validRow(row)) {
  3030.             return;
  3031.         }
  3032.  
  3033.         int cols = cols();
  3034.         for (int col=0; col<cols; col++) {
  3035.             redrawCell(row, col, false);
  3036.         }
  3037.  
  3038.         redrawRowHeadingCell(row);
  3039.     }
  3040.  
  3041.     public boolean isRowDisplayed(int row) {
  3042.         row--;
  3043.  
  3044.         //check if whole table is visible
  3045.         if (!vsb.isVisible()) {
  3046.             return true;
  3047.         }
  3048.         return row>=topRow && row<=topRow + getPageSize().height - 1;
  3049.  
  3050.         //return row>topRow && row<=topRow + getPageSize().height - 1;
  3051.     }
  3052.  
  3053.     /**
  3054.      * Gets whether a column is currently being displayed.
  3055.      */
  3056.     public boolean isColumnDisplayed(int col) {
  3057.         col--;
  3058.  
  3059.         if ((col>lockedColumn && col<leftCol-1) || colHidden[col]) {
  3060.             return false;
  3061.         }
  3062.  
  3063.         int colStart[] = getColStartPositions();
  3064.         int width = getSize().width;
  3065.  
  3066.         if (useRowHeadings) { width -= rowHeadingWidth; }
  3067.  
  3068.         return colStart[col] < width;
  3069.     }
  3070.  
  3071.     //returns zero relative column number for last column that is visible,
  3072.     //    return -1 for no visible columns except row headings.
  3073.     private int lastVisibleCol() {
  3074.         int width = size().width;
  3075.         int cols = cols();
  3076.  
  3077.         if (useRowHeadings) {
  3078.             width -= rowHeadingWidth;
  3079.             if (width < 0) { return -1; }
  3080.         }
  3081.  
  3082.         for (int i=0; i<cols; i++) {
  3083.             if (isColumnDisplayed(i+1)) {
  3084.                 width -= getColumnWidth(i+1);
  3085.                 if (width <= 0) {
  3086.                     return i;
  3087.                 }
  3088.             }
  3089.         }
  3090.  
  3091.         return cols()-1;
  3092.     }
  3093.  
  3094.     /**
  3095.      * Redraws the specified cell and all of the bordering cells
  3096.      */
  3097.     public /*synchronized*/ void redrawAroundCell(TableCell c) {
  3098.         if (disableDrawing) { return; }
  3099.  
  3100.         //draw on all adjoining cells too
  3101.         int row = c.row()-1;
  3102.         int col = c.col();
  3103.  
  3104.         try {
  3105.             fetchMode = true;
  3106.             dataSource.fetchMode(true);
  3107.  
  3108.             //get the columns for this and adjoining cells
  3109.             int cols[] = {-1/*row heading*/, col, cols()/*one too many*/};
  3110.  
  3111.             //get the previous column
  3112.             for (int i=col-1; i>=0; i--) {
  3113.                 if (isColumnDisplayed(i+1)) {
  3114.                     cols[0] = i;
  3115.                     break;
  3116.                 }
  3117.             }
  3118.  
  3119.             //get the next column
  3120.             int num = cols();
  3121.             for(int i=col+1; i<num; i++) {
  3122.                 if (isColumnDisplayed(i+1)) {
  3123.                     cols[2] = i;
  3124.                     break;
  3125.                 }
  3126.             }
  3127.  
  3128.  
  3129.             for (int i=0; i<=2; i++) {
  3130.                 for (int j=0; j<=2; j++) {
  3131.                     if (cols[j] > cols()-1) { continue; }
  3132.  
  3133.                     //redraw col heading
  3134.                     if (row+i < topRow) {
  3135.                         if (cols[j] < leftCol-1) {
  3136.                             //redraw corner cell
  3137.                             redrawCornerCell(gg.create());
  3138.                         }
  3139.  
  3140.                         redrawColHeadingCell(cols[j]);
  3141.                     } else {
  3142.                         //redraw regular cell
  3143.                         if (isCellVisible(row+i+1, cols[j]+1)) {
  3144.                               redrawCell(row + i, cols[j], false, false);
  3145.                         }
  3146.                     }
  3147.                 }
  3148.             }
  3149.         } finally {
  3150.             fetchMode = false;
  3151.             dataSource.fetchMode(false);
  3152.         }
  3153.  
  3154.         paint(getGraphics());
  3155.     }
  3156.  
  3157.     /**
  3158.      * Gets the visible bounds of the drawing space required for the cells in
  3159.      * the TableView.
  3160.      */
  3161.     public Rectangle getTableBounds(Rectangle r) {
  3162.         Dimension d = size();
  3163.         r.reshape(0, 0, d.width, d.height);
  3164.  
  3165.         //draw boundary around table panel
  3166.         if (vsb.isVisible()) {
  3167.             r.width -= vsb.size().width;
  3168.         }
  3169.         r.height -= bottomPanel.size().height;
  3170.         r.width = splitters[splitters.length-1] - splitters[leftCol-1] + 1;
  3171.         if (useRowHeadings) {
  3172.             r.width += rowHeadingWidth;
  3173.         }
  3174.  
  3175.         //compensate for lockable columns
  3176.         if (lockedColumn!=-1) {
  3177.             r.width += splitters[lockedColumn+1];
  3178.         }
  3179.  
  3180.         //compensate for hidden columns
  3181.         int colstart[] = getColStartPositions();
  3182.         int cols = cols();
  3183.  
  3184.         for (int i=0; i<cols; i++) {
  3185.             if (colHidden[i] && colstart[i]!=-1) {
  3186.                 r.width -= getColumnWidth(i+1);
  3187.             }
  3188.         }
  3189.  
  3190.         int visRows = (r.height-2)/cellHeight;
  3191.         if (visRows + topRow > dataSource.rows()) {
  3192.             r.height = headingHeight+2 + cellHeight*(dataSource.rows() - topRow)+2;
  3193.         }
  3194.  
  3195.         return r;
  3196.     }
  3197.  
  3198.     /**
  3199.      * Draws the outline around the cells
  3200.      */
  3201.     protected void drawTableBoundary() {
  3202.         Dimension d = size();
  3203.         Rectangle r = new Rectangle(0, 0, d.width, d.height);
  3204.  
  3205.         //draw boundary around table panel
  3206.         if (vsb.isVisible()) {
  3207.             r.width -= vsb.size().width;
  3208.         }
  3209.         r.height -= bottomPanel.size().height;
  3210.  
  3211.         gg.setColor(Color.black);
  3212.         gg.drawRect(r.x, r.y, r.width-1, r.height-1);
  3213.  
  3214.         //draw boundary around table
  3215.         r.width = splitters[splitters.length-1] - splitters[leftCol-1] + 1;
  3216.         if (useRowHeadings) {
  3217.             r.width += rowHeadingWidth;
  3218.         }
  3219.  
  3220.         //compensate for locked columns
  3221.         if (lockedColumn != -1) {
  3222.             r.width += splitters[lockedColumn+1];
  3223.         }
  3224.  
  3225.         //compensate for hidden columns
  3226.         int colstart[] = getColStartPositions();
  3227.         int cols = cols();
  3228.  
  3229.         for (int i=0; i<cols; i++) {
  3230.             if (colHidden[i] && colstart[i]!=-1) {
  3231.                 r.width -= getColumnWidth(i+1);
  3232.             }
  3233.         }
  3234.  
  3235.         int visRows = (r.height-2)/cellHeight;
  3236.         if (visRows + topRow > dataSource.rows()) {
  3237.             r.height = headingHeight+2 + cellHeight*(dataSource.rows() - topRow)+2;
  3238.         }
  3239.  
  3240.         gg.drawRect(r.x, r.y, r.width, r.height-1);
  3241.     }
  3242.  
  3243.     protected Rectangle getVisibleCellBoundary() {
  3244.         Dimension d = size();
  3245.         Rectangle r = new Rectangle(0, 0, d.width, d.height);
  3246.  
  3247.         //get height of table panel
  3248.         r.height -= bottomPanel.size().height;
  3249.  
  3250.         //get boundary around table
  3251.         r.width = splitters[splitters.length-1] - splitters[leftCol-1] + 1;
  3252.         if (useRowHeadings) {
  3253.             r.width += rowHeadingWidth;
  3254.         }
  3255.  
  3256.         int visRows = (r.height-2)/cellHeight;
  3257.         if (visRows + topRow > dataSource.rows()) {
  3258.             r.height = headingHeight+2 + cellHeight*(dataSource.rows() - topRow)+2;
  3259.         }
  3260.  
  3261.         return r;
  3262.     }
  3263.  
  3264.     /**
  3265.      * Inserts a new row above the specified row number
  3266.      * @exception   TypeNotSupported If action is not supported by the DataSource
  3267.      */
  3268.     public /*synchronized*/ void insertRow(int beforeRow) throws TypeNotSupported {
  3269.  
  3270.         beforeRow--;
  3271.         dataSource.insertRow(beforeRow);
  3272.         /*vj - let the new cell itself be the current cell
  3273.         if (currSelectedCell != null &&
  3274.             currSelectedCell.row() >= beforeRow)
  3275.         {
  3276.             currSelectedCell.setRow(currSelectedCell.row()+1);
  3277.         }*/
  3278.  
  3279.         if (autoRedraw) { redrawAsync(); }
  3280.     }
  3281.  
  3282.     /**
  3283.      * Gets the state of the data in the specified row
  3284.      * @return One of NEW_ROW, CLEAN_ROW, DELETED_ROW, MODIFIED_ROW as defined in
  3285.      *      DataSource
  3286.      */
  3287.     public int rowState(int row) {
  3288.         row--;
  3289.         return dataSource.rowState(row);
  3290.     }
  3291.  
  3292.     /**
  3293.      * Mark the specified row as not deleted
  3294.      * @exception   TypeNotSupported If action is not supported by the DataSource
  3295.      */
  3296.     public void undeleteRow(int row) throws TypeNotSupported {
  3297.         row--;
  3298.  
  3299.         dataSource.undeleteRow(row);
  3300.  
  3301.         //BS: remove the * showed next to the row heading
  3302.   /*      try{
  3303.  
  3304.             String text = rowHeadingSource.getData(row,0).toString();
  3305.  
  3306.             if(text.endsWith("*"))
  3307.                 rowHeadingSource.setText(row,0,
  3308.                                          text.substring(0,text.length()-1));
  3309.         }catch(DataNotAvailable d){
  3310.             //System.out.println("no data available");
  3311.         }
  3312. */
  3313.     }
  3314.  
  3315.     /**
  3316.      * Mark the specified row as deleted
  3317.      * @exception   TypeNotSupported If action is not supported by the DataSource
  3318.      */
  3319.     public /*synchronized*/ void deleteRow(int row) throws TypeNotSupported {
  3320.         row--;
  3321.  
  3322.       //  System.out.println("deleting row");
  3323.  
  3324.         dataSource.deleteRow(row);
  3325.  
  3326.         if (currSelectedCell != null) {
  3327.             if(currSelectedCell.row() == row) {
  3328.                 currSelectedCell = currCaptureCell = null;
  3329.             } else if (currSelectedCell.row() > row) {
  3330.                 currSelectedCell.setRow(currSelectedCell.row()-1);
  3331.             }
  3332.         }
  3333.  
  3334.  
  3335.         //BS: we want to show that this row is scheduled for deletion
  3336.         //add a * to the row heading
  3337.   /*      try{
  3338.             rowHeadingSource.setText(row,0,
  3339.                         rowHeadingSource.getData(row,0).toString() + "*");
  3340.         }catch(DataNotAvailable d){
  3341.            //System.out.println("no data available");
  3342.         }
  3343. */
  3344.         if (autoRedraw) { redrawAsync(); }
  3345.     }
  3346.  
  3347.     /**
  3348.      * Appends a new row to the end of the TableView
  3349.      * @exception   TypeNotSupported If action is not supported by the DataSource
  3350.      */
  3351.     public int appendRow() throws TypeNotSupported {
  3352.         int     newRow;
  3353.  
  3354.         newRow = dataSource.appendRow();
  3355.  
  3356.         if (autoRedraw) { redrawAsync(); }
  3357.         return newRow;
  3358.     }
  3359.  
  3360.     /**
  3361.      * Creates a new cell and adds it to the Matrix used to store TableCells.
  3362.      * @param cell The default cell to clone to make the new cell.
  3363.      */
  3364.     public void addCellFromDefault(TableCell cell) {
  3365.         TableCell c = cell.cloneCell();
  3366.         cells.addElement(c.row(), c.col(), c);
  3367.         if (currSelectedCell == cell) { currSelectedCell = c; }
  3368.         if (currCaptureCell == cell) { currCaptureCell = c; }
  3369.     }
  3370.  
  3371.     /**
  3372.      * Gets the default cell and sets the coordinates to the specified values
  3373.      */
  3374.     protected TableCell getDefaultCell(int row, int col) {
  3375.         CellHints hc = getCellHints(row, col);
  3376.         CellHints hr = getRowHints(row);
  3377.         CellHints h = getColHints(col);
  3378.  
  3379.         TableCell cell = h.cascadeDefaultCell(hr, hc);
  3380.         if (cell == null) {
  3381.             cell = defaultCell;
  3382.         }
  3383.  
  3384.         Coordinate c = cell.getCoordinates();
  3385.         cell.reset();
  3386.         c.row = row;
  3387.         c.col = col;
  3388.  
  3389.         return cell;
  3390.     }
  3391.  
  3392.     /**
  3393.      * Gets the cell at the specified coordinats.  If the cell does not exist in
  3394.      * the cells Matrix, then the default cell is returned.
  3395.      */
  3396.     protected TableCell getCell(Coordinate c) {
  3397.         return getCell(c.row(), c.col());
  3398.     }
  3399.  
  3400.     /**
  3401.      * Gets the cell at the specified coordinats.  If the cell does not exist in
  3402.      * the cells Matrix, then the default cell is returned.
  3403.      */
  3404.     protected TableCell getCell(int row, int col) {
  3405.         if (currSelectedCell != null
  3406.             && currSelectedCell.row() == row && currSelectedCell.col() == col)
  3407.         {
  3408.             return currSelectedCell;
  3409.         } else if (cells.contains(row, col)) {
  3410.             return (TableCell)cells.elementAt(row, col);
  3411.         } else {
  3412.             return getDefaultCell(row, col);
  3413.         }
  3414.     }
  3415.  
  3416.     //BS: fixed save so -row headings are correctly displayed
  3417.     //                  -table is repainted, keeping the top row at the top
  3418.  
  3419.     /**
  3420.      * Requests the DataSource to save the current state of the TableView
  3421.      * @exception   TypeNotSupported If action is not supported by the DataSource
  3422.      */
  3423.     public void save() throws TypeNotSupported {
  3424.  
  3425.         int top = getTopRow();//BS: 0 relative !!!
  3426.  
  3427.         //System.out.println(top);
  3428.         dataSource.commitData();
  3429.         dataSource.save();
  3430.  
  3431.         //BS:we have to update the rowheading as some rows can have been deleted
  3432.         //rowHeadingSource.redoAutoNumbering();
  3433.  
  3434.         //BS: look if that row number still exists ...
  3435.  
  3436.         //modify rowstate in dbadatastore to return NONEXISTS_ROW if not valid row...
  3437.  
  3438.         if(dataSource.rowState(top + 1) != DataSource.NONEXISTS_ROW)
  3439.             //yes, draw grid with that row on top
  3440.             setTopRow(top + 1);
  3441.         else
  3442.             //no draw with first row at top
  3443.             setTopRow(1);
  3444.             //vj: Clear current cell selection
  3445.             clearCurrentCell();
  3446.             redrawAsync();
  3447.  
  3448.     }
  3449.  
  3450.  
  3451.     /**
  3452.      * Requests the DataSource to refresh its data.  Same as refresh but for
  3453.      * backward compatibility.
  3454.      */
  3455.     public void restart() {
  3456.         refresh();
  3457.     }
  3458.  
  3459.     /**
  3460.      * Requests the DataSource to refresh its data.
  3461.      */
  3462.     public void refresh() {
  3463.         dataSource.refresh();
  3464.         hideAuxControl();
  3465.         currSelectedCell = null;
  3466.         currCaptureCell = null;
  3467.         topRow = 0;
  3468.         redrawAsync();
  3469.     }
  3470.  
  3471.     /**
  3472.      * Redraws the TableView's offscreen image.  Call when through making changes to TableView.
  3473.      * @param repaint If true, TableView will be repainte after it is redrawn
  3474.      *      offscreen.
  3475.      */
  3476.     private /*synchronized*/ void redraw(boolean repaint) {
  3477.         redraw();
  3478.         if (repaint) {
  3479.             paint(getGraphics());
  3480.         }
  3481.     }
  3482.  
  3483.     /**
  3484.      * Redraws the TableView.  Call when through making changes to TableView. Does not
  3485.      *      force a redraw of the offscreen image.
  3486.      */
  3487.     private /*synchronized*/ void redraw() {
  3488.         Dimension d = size();
  3489.  
  3490.         if ((width != d.width || height != d.height)
  3491.             && (d.width > 0 && d.height > 0))
  3492.         {
  3493.             im = createImage(width = d.width,
  3494.                              height = d.height);
  3495.             if (im == null) return;
  3496.             gg = im.getGraphics();
  3497.         }
  3498.         forceRedraw(false);
  3499.     }
  3500.  
  3501.     /**
  3502.      * Forces the offscreen image to be redraw.  It does not check for a size
  3503.      * change since the last redraw.
  3504.      */
  3505.     private /*synchronized*/ void forceRedraw(boolean repaint) {
  3506.         if (gg == null) return;
  3507.  
  3508.         gg.setColor(getBackground());
  3509.         gg.fillRect(0,0,width,height);
  3510.  
  3511.         try {
  3512.             dataSource.fetchMode(true);
  3513.             showScrollbars();
  3514.             int count = getNumberOfVisibleRows();
  3515.             drawHeadings(count);
  3516.             drawRows(count, topRow);
  3517.             moveAuxControl();
  3518.             drawTableBoundary();
  3519.         } finally {
  3520.             dataSource.fetchMode(false);
  3521.         }
  3522.  
  3523.         if (repaint) {
  3524.             paint(getGraphics());
  3525.         }
  3526.     }
  3527.  
  3528.     void drawRows(int count, int cellRow) {
  3529.         int                 r = 0;
  3530.         MatrixEnumeration   e = cells.elements();
  3531.         TableCell           c = null;
  3532.         int                 x, w;
  3533.         int                 cols = cols();
  3534.         int                 hx=0, hy=0, hw=0, hh=0;
  3535.         int                 startPos[] = getColStartPositions();
  3536.         int                 currRow=-1, currCol=-1;
  3537.  
  3538.         if (cellRow > 0) {
  3539.             if (cellRow >= cells.rows()) {
  3540.                 e = null;
  3541.             } else {
  3542.                 c  = (TableCell)e.advanceTo(cellRow);
  3543.             }
  3544.         }
  3545.  
  3546.         //create a new graphics so can change attributes without having to reset.
  3547.         Graphics cellG = gg.create();
  3548.         Shape clip = cellG.getClip();
  3549.         if (clip==null) { clip = new Rectangle(0, 0, width, height); }
  3550.  
  3551.         //iterate the rows and paint each one
  3552.         int lastVisCol = lastVisibleCol();
  3553.         while(count-- > 0) {
  3554.             //iterate the cols of the current row
  3555.             for (int col=0; col<cols && col<=lastVisCol; col++) {
  3556.                 if ((col>lockedColumn && col<leftCol-1) || colHidden[col]) { continue; }
  3557.                 w = getColumnWidth(col+1);
  3558.                 //check if cells matrix has a cell for current cell
  3559.                 while (e != null
  3560.                        && (c==null || (e.currCol()<col && e.currRow()<=cellRow))
  3561.                        && e.hasMoreElements())
  3562.                 {
  3563.                     c = (TableCell)e.nextElement();
  3564.                     currRow = e.currRow();
  3565.                     currCol = e.currCol();
  3566.                     if (currRow <= cellRow && currCol < col) {
  3567.                         //keep going till get to correct column
  3568.                         c = null;
  3569.                     }
  3570.                 }
  3571.  
  3572.                 if (currRow==cellRow && currCol==col) {
  3573.                     hints.setHints(c);
  3574.                     try {
  3575.                         c.drawCell(cellG, hints);
  3576.                     } finally {
  3577.                         cellG.setClip(clip);
  3578.                     }
  3579.                     c = null;
  3580.                 } else
  3581.                 if (currSelectedCell != null &&
  3582.                     //it is default cell, but could be currSelectedCell
  3583.                         currSelectedCell.row() == cellRow &&
  3584.                         currSelectedCell.col() == col)
  3585.                 {
  3586.                     hints.setHints(currSelectedCell);
  3587.                     hints.clip(cellG);
  3588.                     try {
  3589.                         currSelectedCell.drawCell(cellG, hints);
  3590.                     } finally {
  3591.                         cellG.setClip(clip);
  3592.                     }
  3593.                 } else {
  3594.                     //looks like this cell not set yet so use default
  3595.                     TableCell defCell = getDefaultCell(cellRow, col);
  3596.                     hints.setHints(defCell);
  3597.                     hints.clip(cellG);
  3598.                     try {
  3599.                         defCell.drawCell(cellG, hints);
  3600.                     } finally {
  3601.                         cellG.setClip(clip);
  3602.                     }
  3603.                 }
  3604.  
  3605.             }
  3606.             cellRow++;
  3607.             r++;
  3608.         }
  3609.  
  3610.         if (currSelectedCell != null && currSelectedCell.isCellTypeEditable()) {
  3611.             frameCurrentCells();
  3612.         }
  3613.     }
  3614.  
  3615.     boolean drawFrame = true;
  3616.  
  3617.     /**
  3618.      * Sets whether current cell should have a frame drawn around it
  3619.      */
  3620.     public boolean drawFrame() { return drawFrame; }
  3621.  
  3622.     /**
  3623.      * Gets whether current cell should have a frame drawn around it
  3624.      */
  3625.     public boolean drawFrame(boolean draw) {
  3626.         drawFrame = draw;
  3627.  
  3628.         if (autoRedraw) {
  3629.             redrawAsync();
  3630.         }
  3631.  
  3632.         return draw;
  3633.     }
  3634.  
  3635.     /**
  3636.      * Draws the frame around the current cell.  Multiple framed cells are not supported
  3637.      * at this time. But as the name implies, it is coming.
  3638.      */
  3639.     protected void frameCurrentCells() {
  3640.         if (drawFrame && currSelectedCell != null) {
  3641.             Rectangle r = getCellBounds(currSelectedCell);
  3642.             if (r.x < rowHeadingWidth || r.y < headingHeight+2) { return; }
  3643.             gg.setColor(Color.black);
  3644.             gg.drawRect(r.x-1,r.y-1,r.width+1,r.height+1);  //draw outside
  3645.             gg.drawRect(r.x+1,r.y+1,r.width-3,r.height-3);  //draw inside
  3646.         }
  3647.     }
  3648.  
  3649.     /**
  3650.      * Gets the X pixel for the left side of a colum (0 relative).
  3651.      * @returns -1 if column is hidden or scrolled off to left.
  3652.      */
  3653.     public int getColumnStartX(int col, boolean includeRowHeadings) {
  3654.         //see if not visible due to scrolling or hidden
  3655.             if (colHidden[col] || (col>lockedColumn && col<leftCol-1)) {
  3656.                 return -1;
  3657.             }
  3658.  
  3659.         int startsAt = splitters[col];
  3660.  
  3661.         if (includeRowHeadings) {
  3662.             startsAt += rowHeadingWidth;
  3663.         }
  3664.  
  3665.         //subtract if a column before 'col' is hidden or scrolled
  3666.         for (int i=0; i<col; i++) {
  3667.             if (colHidden[i] || (i>lockedColumn && i<leftCol-1)) {
  3668.                 startsAt -= getColumnWidth(i+1);
  3669.             }
  3670.         }
  3671.  
  3672.         return startsAt;
  3673.     }
  3674.  
  3675.     /**
  3676.      * Gets the left pixel position of each column. If a column is not visible
  3677.      * b/c it is too far to the left then it is said to start at position -1.
  3678.      * Notice that this means that determining the width of a column is not as
  3679.      * simple as taking the diff between two starting positions.
  3680.      */
  3681.     protected final int[] getColStartPositions() {
  3682.         int starts[] = new int[splitters.length-1];
  3683.         int adjust = -splitters[leftCol-1];
  3684.         int len = starts.length;
  3685.  
  3686.         if (lockedColumn != -1) {
  3687.             adjust += splitters[lockedColumn+1];
  3688.         }
  3689.  
  3690.         int totalHidden = 0;
  3691.         for (int col=0; col<len; col++) {
  3692.             //if not visible b/c scrolled count as scrolled even if hidden
  3693.             if (col<leftCol-1 && col>lockedColumn) {
  3694.                 starts[col] = -1;
  3695.                 continue;
  3696.             } else if (colHidden[col]) {
  3697.                 starts[col] = -1;
  3698.                 totalHidden += (splitters[col+1] - splitters[col]);
  3699.             } else if (col <= lockedColumn) {
  3700.                 starts[col] = splitters[col] - totalHidden;
  3701.             } else {
  3702.                 starts[col] = splitters[col] + adjust - totalHidden;
  3703.             }
  3704.  
  3705.             if (useRowHeadings) {
  3706.                 starts[col] += rowHeadingWidth;
  3707.             }
  3708.         }
  3709.  
  3710.        return starts;
  3711.     }
  3712.  
  3713.  
  3714.     /**
  3715.      * If the event handler is set, the exception is passed to the event handler.<p>
  3716.      * This function is 0 relative!!
  3717.      */
  3718.     public void handleException(int row, int col, Exception ex) {
  3719.         if (eventHandler != null) {
  3720.             eventHandler.handleException(new Coordinate(row, col), ex);
  3721.         }
  3722.     }
  3723.  
  3724.     /**
  3725.      * Requests the DataSource to undo some action to the specified row
  3726.      * @exception   TypeNotSupported If action is not supported by the DataSource
  3727.      */
  3728.     public void undoRow(int row) throws TypeNotSupported {
  3729.         row--;
  3730.         dataSource.undoRow(row);
  3731.     }
  3732.  
  3733.     /**
  3734.      * Requests the DataSource to commit any changes made to the current cell
  3735.      * since the last commit.
  3736.      */
  3737.     public void commitCurrentCell() throws TypeNotSupported {
  3738.         dataSource.commitData();
  3739.         if (currSelectedCell != null) {
  3740.             redrawCell(currSelectedCell);
  3741.         }
  3742.     }
  3743.  
  3744.     /**
  3745.      * Requests the DataSource to undo any changes made to the current cell
  3746.      * since the last commit.
  3747.      */
  3748.     public void undoCurrentCell() {
  3749.         dataSource.rollbackCurrentData();
  3750.         if (currSelectedCell != null) {
  3751.             redrawCell(currSelectedCell);
  3752.         }
  3753.     }
  3754.  
  3755.     void handleHeadingClick(MouseEvent e, int x, int y) {
  3756.         int colstart[] = getColStartPositions();
  3757.  
  3758.         if (x<=rowHeadingWidth && useRowHeadings) {
  3759.             //it was a click in row header region
  3760.             if ((x < rowHeadingWidth + clickMargin) &&
  3761.                 (x > rowHeadingWidth - clickMargin))
  3762.             {
  3763.                 dragColumn = 0;
  3764.                 isDragging = true;
  3765.                 mouseDragged(e, x, y); //draw drag line immediately
  3766.             } else {
  3767.                 //upper left corner clicked
  3768.                 if (rowHeadingCell(currCaptureCell)) {
  3769.                     currHeadingCell = null;
  3770.                 }
  3771.  
  3772.                 currCaptureCell = cornerCell;
  3773.                 CellEvent.generateMouseEvent(this, cornerCell, e, CellEvent.MOUSE_PRESSED);
  3774.                 return;
  3775.             }
  3776.             return;
  3777.         } else {
  3778.             //NOTE: dragColumn is 1 relative (==0 means row heading size change)
  3779.             //check for changing size of row headings
  3780.             if (useRowHeadings) {
  3781.                 if (x < rowHeadingWidth+clickMargin
  3782.                     && x > rowHeadingWidth-clickMargin)
  3783.                 {
  3784.                     dragColumn = 0;
  3785.                     isDragging = true;
  3786.                     mouseDragged(e, x, y);
  3787.                     return;
  3788.                 }
  3789.             }
  3790.  
  3791.             // is it close enough to be a column size drag?
  3792.             for (int i=0; i<colstart.length; i++) {
  3793.                 //if column not visible
  3794.                 if (colstart[i] == -1) { continue; }
  3795.  
  3796.                 int colEnd = colstart[i] + getColumnWidth(i+1);
  3797.                 if ((x < colEnd + clickMargin) &&
  3798.                     (x > colEnd - clickMargin))   {
  3799.                     dragColumn = i+1;
  3800.                     isDragging = true;
  3801.                     mouseDragged(e, x, y); //draw drag line immediately
  3802.                     return;
  3803.                 }
  3804.             }
  3805.         }
  3806.  
  3807.         //get the heading for the coordinates
  3808.         TableCell cell = (TableCell)colHeadings.elementAt(0, columnClicked(x));
  3809.  
  3810.         //check to see if x is past last column
  3811.         if (cell.col() == cols()-1) {
  3812.             Rectangle bounds = getCellBounds(cell);
  3813.             if (!bounds.contains(x, y)) {
  3814.                 //not really in cell so that's it, we are done.
  3815.                 return;
  3816.             }
  3817.         }
  3818.  
  3819.         if (cell == null) {
  3820.             return;
  3821.         }
  3822.  
  3823.         if (rowHeadingCell(currCaptureCell)) {
  3824.             currHeadingCell = null;
  3825.         }
  3826.  
  3827.         currCaptureCell = cell;
  3828.         CellEvent.generateMouseEvent(this, cell, e, CellEvent.MOUSE_PRESSED);
  3829.     }
  3830.  
  3831.  
  3832.     int resizeRowHeightFrom = -1;
  3833.     boolean isDraggingRowHeight = false;
  3834.  
  3835.     void handleRowHeadingClick(MouseEvent e, int x, int y) {
  3836.  
  3837.         //System.out.println("Into handleRowHeadingClick");
  3838.  
  3839.         if (resizeClick(x, y)) {
  3840.             //row resize time
  3841.             resizeRowHeightFrom = y;
  3842.             isDraggingRowHeight = true;
  3843.             mouseDragged(e, x, y); //draw drag line immediately
  3844.  
  3845.             return;
  3846.         }
  3847.  
  3848.         //BS:deselect the currently selected cell, otherwise multiple row
  3849.         //selection doesn't work
  3850.  
  3851.         sendFocusEvents(currSelectedCell,null);
  3852.  
  3853.  
  3854.         //create a new current heading cell since this could be a shared resource
  3855.         //during event handling
  3856.         //get the heading for the coordinates
  3857.         currHeadingCell = headingCell.cloneCell();
  3858.         Coordinate c = currHeadingCell.getCoordinates();
  3859.         c.row = cellRow(y);
  3860.         c.col = 0;
  3861.  
  3862.         if (!validRow(c.row)) { return; }
  3863.  
  3864.         //BS:set the currentRow to the one clicked
  3865.         try{
  3866.             dataSource.setCurrentRow(c.row);
  3867.         }catch(TypeNotSupported ex){};
  3868.  
  3869.         currCaptureCell = currHeadingCell;
  3870.         CellEvent.generateMouseEvent(this, currCaptureCell, e, CellEvent.MOUSE_PRESSED);
  3871.  
  3872.     }
  3873.  
  3874.     void handleSuccessiveClick(MouseEvent e) {
  3875.         //must only be called if no focus change
  3876.         // track time elapsed since last mouseDown
  3877.         long clickSpeed = e.getWhen() - clickTime;
  3878.         TableCell cell = (currCaptureCell != null) ?currCaptureCell  :currSelectedCell;
  3879.         boolean handled = false;
  3880.  
  3881.         if (cell == null) {
  3882.             handled = false;
  3883.         } else if (clickSpeed < CLICKTHRESHOLD) {
  3884.             CellEvent.generateMouseEvent(this, cell, e, CellEvent.MOUSE_DOUBLE);
  3885.         } else {
  3886.             //single click so send mouse event to control
  3887.             CellEvent.generateMouseEvent(this, cell, e, CellEvent.MOUSE_PRESSED);
  3888.         }
  3889.  
  3890.         clickTime  = e.getWhen();
  3891.         return;
  3892.     }
  3893.  
  3894.     int cellRow(int y) {
  3895.         return ((int)(y-headingHeight-2)/cellHeight)+topRow;
  3896.     }
  3897.  
  3898.     int columnClicked(int x) {
  3899.         int colstart[] = getColStartPositions();
  3900.  
  3901.         if (x<rowHeadingWidth) {
  3902.             return -1;
  3903.         }
  3904.  
  3905.         for (int i=0; i<colstart.length; i++) {
  3906.             if (colstart[i] == -1) { continue; }
  3907.             if (x<colstart[i]+getColumnWidth(i+1)) {
  3908.                 return i;
  3909.             }
  3910.         }
  3911.  
  3912.         return cols()-1;
  3913.     }
  3914.  
  3915.  
  3916.     //BS: added setFocusToRow
  3917.  
  3918.     void setFocusToRow(int row)
  3919.     {
  3920.  
  3921.       //  System.out.println("Into setFocusToRow " + row);
  3922.  
  3923.         row--;
  3924.         if (currSelectedCell == null || currSelectedCell.row() != row)
  3925.         {
  3926.             //vj: replaced gotoRow with scrollUpDownAbsolute
  3927.             //    because gotoRow would now call dataSource.setCurrentRow(row).
  3928.             //    Also scrollUpDownAbsolute expects a zero-relative row number
  3929.  
  3930.             //row++;
  3931.             //gotoRow(row);
  3932.             if(row != topRow){
  3933.                 scrollUpDownAbsolute(row);
  3934.             }
  3935.  
  3936.         }
  3937.         else
  3938.         {
  3939.             row++;
  3940.             redrawRow(row);
  3941.  
  3942.             //BS: changed sendFocusEvents call
  3943.  
  3944.             //sendFocusEvents(null, currSelectedCell);
  3945.             sendFocusEvents(currSelectedCell,null);
  3946.         }
  3947.     }
  3948.  
  3949.  
  3950.  
  3951.     //this method refreshes the grid without refreshing the datasource
  3952.     //it is useful when the Grid receives notification that the datasource has changed
  3953.     //(or restarted)
  3954.     public void refreshView(){
  3955.         hideAuxControl();
  3956.         currSelectedCell = null;
  3957.         currCaptureCell = null;
  3958.         topRow = 0;
  3959.         redrawAsync();
  3960.     }
  3961.  
  3962.     void sendFocusEvents(TableCell lost, TableCell get) {
  3963.  
  3964.         //System.out.println("In sendFocusEvents");
  3965.  
  3966.         CellEvent e = new CellEvent(this, lost, null, CellEvent.LOST_FOCUS);
  3967.         if (lost != null) {
  3968.             if (!lost.canLoseFocus()) {
  3969.                 //not a legal state so do not change
  3970.                 return;
  3971.             }
  3972.  
  3973.             //set selected cell to get so frame not drawn around cell
  3974.             currSelectedCell = get;
  3975.             lost.focusEvent(e);
  3976.             lostCapture();
  3977.         }
  3978.  
  3979.         if (get == null) {
  3980.             currSelectedCell = null;
  3981.             return;
  3982.         }
  3983.  
  3984.         currSelectedCell = get;
  3985.         e.setCell(get);
  3986.         e.setID(e.GOT_FOCUS);
  3987.         get.focusEvent(e);
  3988.  
  3989.         //change currently selected row now
  3990.         makeCellVisible(get.row()+1, get.col()+1);
  3991.         //BS:the setCurrentRow method of the datasource was not used...
  3992.         try{
  3993.             if(lost == null)
  3994.                 dataSource.setCurrentRow(get.row());
  3995.             else
  3996.                 if(lost.row() != get.row())
  3997.                     dataSource.setCurrentRow(get.row());//table row 0 is datasource row 0
  3998.  
  3999.  
  4000.  
  4001.         }catch(TypeNotSupported ex){};
  4002.  
  4003.         clickTime = 0;
  4004.     }
  4005.  
  4006.     /**
  4007.      * Inherited from Component
  4008.      */
  4009.     public void mouseExited(int x, int y) {
  4010.         setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
  4011.     }
  4012.  
  4013.     /**
  4014.      * Inherited from Component
  4015.      */
  4016.     public /*synchronized*/ void mousePressed(MouseEvent e, int x, int y) {
  4017.         requestFocus();
  4018.  
  4019.         // Check for a click on the heading area:
  4020.         if (y<headingHeight+1) {
  4021.             handleHeadingClick(e, x, y);
  4022.             return;
  4023.         }
  4024.  
  4025.         Rectangle r = new Rectangle();
  4026.         r = getTableBounds(r);
  4027.         if (!r.inside(x, y)) {
  4028.             return;
  4029.         }
  4030.  
  4031.         if (x<rowHeadingWidth && useRowHeadings) {
  4032.             //click in row heading area
  4033.             handleRowHeadingClick(e, x, y);
  4034.             return;
  4035.         }
  4036.  
  4037.         //it's a click in the row area
  4038.         //check for hit on the scrollbar
  4039.         if (x > width) return;
  4040.  
  4041.         // set new row selection
  4042.         int row = cellRow(y);
  4043.         int col = columnClicked(x);
  4044.  
  4045.         TableCell newSelection = null;
  4046.         if (currSelectedCell == null || row != currSelectedCell.row() ||
  4047.             col != currSelectedCell.col())
  4048.         {
  4049.             if (!cells.contains(row, col)) {
  4050.                 //check for mouse below last row
  4051.                 if (!validRow(row)) {
  4052.                     return;
  4053.                 }
  4054.                 //then we need to use the default cell
  4055.                 newSelection = getDefaultCell(row, col).cloneCell();
  4056.                 newSelection.setDefaultFlag();
  4057.             } else {
  4058.                 newSelection = (TableCell)cells.elementAt(row, col);
  4059.             }
  4060.  
  4061.             sendFocusEvents(currSelectedCell, newSelection);
  4062.             if (cellHasCapture()) {
  4063.                 CellEvent.generateMouseEvent(this, newSelection, e, CellEvent.MOUSE_PRESSED);
  4064.             }
  4065.         } else {
  4066.             //check for double click since didn't change cells
  4067.             handleSuccessiveClick(e);
  4068.         }
  4069.     }
  4070.  
  4071.     /**
  4072.      * Determines whether the specified row exists in the TableView. <p>
  4073.      * This function is 0 based!
  4074.      */
  4075.     public boolean validRow(int row) {
  4076.         if (row < 0) return false;
  4077.  
  4078.         if (cells.rows()-1 > row) {
  4079.             return true;
  4080.         }
  4081.  
  4082.         try {
  4083.             dataSource.validDataRowRange(row, row);
  4084.         } catch(DataNotAvailable exc) {
  4085.             //Yep, it was a click below cells
  4086.             return false;
  4087.         }
  4088.  
  4089.         return true;
  4090.     }
  4091.  
  4092.     /**
  4093.      * Determines whether the specified column exists in the TableView. <p>
  4094.      * This function is 0 based!
  4095.      */
  4096.     public boolean validCol(int col) {
  4097.         return col >= 0 && col < cols();
  4098.     }
  4099.  
  4100.     /**
  4101.      * Inherited from Component
  4102.      */
  4103.     public /*synchronized*/ void mouseDragged(MouseEvent e, int x, int y) {
  4104.         if (isDragging)  {
  4105.             handleColDrag(x);
  4106.             return;
  4107.         } else if (isDraggingRowHeight) {
  4108.             handleRowDrag(y);
  4109.             return;
  4110.         }
  4111.  
  4112.         if (cellHasCapture()) {
  4113.             CellEvent.generateMouseEvent(this, currCaptureCell, e, CellEvent.MOUSE_DRAGGED);
  4114.         }
  4115.     }
  4116.  
  4117.     boolean captureByHeading() {
  4118.         if (currCaptureCell == null) { return false; }
  4119.  
  4120.         Coordinate c = currCaptureCell.getCoordinates();
  4121.  
  4122.         return colHeadings.contains(c.row, c.col, currCaptureCell)
  4123.                || cornerCell == currCaptureCell;
  4124.     }
  4125.  
  4126.     boolean captureByRowHeading() {
  4127.         if (currCaptureCell == null) { return false; }
  4128.  
  4129.         return rowHeadingCell(currCaptureCell) || cornerCell == currCaptureCell;
  4130.     }
  4131.  
  4132.     Event translate(Event e) {
  4133.         //get coords of current cell
  4134.         TableCell cell = (currCaptureCell != null) ?currCaptureCell  :currSelectedCell;
  4135.  
  4136.         int row = cell.getCoordinates().row;
  4137.         int col = cell.getCoordinates().col;
  4138.         int currY = (row - topRow) * cellHeight + headingHeight + 2;
  4139.         int currX = getColumnStartX(col, false);
  4140.  
  4141.         //translate event's x and y to cell relative
  4142.         if (!captureByRowHeading()) {
  4143.             e.x -= (currX + rowHeadingWidth);
  4144.         }
  4145.         if (!captureByHeading()) {
  4146.             e.y -= currY;
  4147.         }
  4148.  
  4149.         return e;
  4150.     }
  4151.  
  4152.     //reminder - dragColumn is 1 relative (0 means row heading size change)
  4153.     void handleColDrag(int x) {
  4154.         //fix any drag that went off the left side of cell
  4155.         int startsAt;
  4156.  
  4157.         if (dragColumn == 0) {
  4158.             //dragging to change size of header area
  4159.             x = Math.max(x, 0);
  4160.             rowHeadingWidth = x;
  4161.         } else if (x<(startsAt=getColumnStartX(dragColumn-1, true))) {
  4162.             x = startsAt;
  4163.         }
  4164.  
  4165.         //erase prvious drag line and draw in new position
  4166.         gg.setColor(getBackground());
  4167.         gg.setXORMode(Color.gray);
  4168.         gg.drawLine(xDragLast,0, xDragLast, size().height);
  4169.         gg.drawLine(x, 0, x, size().height);
  4170.         gg.setColor(Color.black);
  4171.         gg.setPaintMode();
  4172.  
  4173.         //save x position of drag line
  4174.         xDragLast = x;
  4175.         repaint();
  4176.     }
  4177.  
  4178.     int yDragLast = -1;
  4179.     void handleRowDrag(int y) {
  4180.         //erase prvious drag line and draw in new position
  4181.         gg.setColor(getBackground());
  4182.         gg.setXORMode(Color.black);
  4183.         gg.drawLine(0, yDragLast, size().width, yDragLast);
  4184.         gg.drawLine(0, y, size().width, y);
  4185.         gg.setColor(Color.black);
  4186.         gg.setPaintMode();
  4187.  
  4188.         //save x position of drag line
  4189.         yDragLast = y;
  4190.         repaint();
  4191.     }
  4192.  
  4193.  
  4194.     /**
  4195.      * Sets the size of a column as specified in pixels.
  4196.      * @param col The column to be sized.
  4197.      * @param width The number of pixels to size the column to.
  4198.      */
  4199.     public /*synchronized*/ void setColumnSize(int col, int width) {
  4200.         col--;
  4201.         int diff = width - splitters[col+1] + splitters[col];
  4202.         int len = splitters.length;
  4203.  
  4204.         for (int i=col+1; i<len; i++) {
  4205.             splitters[i] += diff;
  4206.         }
  4207.     }
  4208.  
  4209.     /**
  4210.      * Resizes the specified column so that the right side of the column
  4211.      * is set to the requested pixel position. This method is one relative.
  4212.      * @param col The column number to resize.
  4213.      * @param rightSide The pixel position of the right side of the column.
  4214.      *      This position does not account for the possible presence of the
  4215.      *      row headings.
  4216.      */
  4217.     protected final /*synchronized*/ void adjustColumnSide(int col, int rightSide) {
  4218.         int diff;
  4219.         int len = splitters.length;
  4220.  
  4221.         diff = rightSide - (getColumnStartX(col-1,false) + getColumnWidth(col));
  4222.         if (isColumnLocked(col)) {
  4223.             //if locked column then this is the side
  4224.             splitters[col] = rightSide;
  4225.         } else {
  4226.             //scrollable column
  4227.             splitters[col] += diff;
  4228.         }
  4229.  
  4230.         for(int i=col+1;i<len;i++) {
  4231.             splitters[i] += diff;
  4232.         }
  4233.  
  4234.         redrawAsync();
  4235.     }
  4236.  
  4237.     /**
  4238.      * Inherited from Component
  4239.      */
  4240.     public /*synchronized*/ void mouseReleased(MouseEvent e, int x, int y) {
  4241.  
  4242.  
  4243.         if (isDragging) {
  4244.  
  4245.             //erase drag line
  4246.             gg.setColor(getBackground());
  4247.             gg.setXORMode(Color.black);
  4248.             gg.drawLine(xDragLast, 0, xDragLast, size().height);
  4249.             gg.setColor(Color.black);
  4250.             gg.setPaintMode();
  4251.  
  4252.             //set column width to dragged position
  4253.             if (dragColumn == 0) {
  4254.                 //changed header size
  4255.                 redrawAsync();
  4256.             } else {
  4257.                 adjustColumnSide(dragColumn, xDragLast - rowHeadingWidth);
  4258.             }
  4259.  
  4260.             //turn off dragging
  4261.             xDragLast = -1;
  4262.             isDragging = false;
  4263.  
  4264.             return;
  4265.         } else if (isDraggingRowHeight) {
  4266.  
  4267.             //erase drag line
  4268.             gg.setColor(getBackground());
  4269.             gg.setXORMode(Color.black);
  4270.             gg.drawLine(0, yDragLast, size().width, yDragLast);
  4271.             gg.setColor(Color.black);
  4272.             gg.setPaintMode();
  4273.  
  4274.             //set column width to dragged position
  4275.               setCellHeight(cellHeight + y - resizeRowHeightFrom);
  4276.  
  4277.             //turn off dragging
  4278.             yDragLast = -1;
  4279.             isDraggingRowHeight = false;
  4280.  
  4281.  
  4282.             return;
  4283.  
  4284.         } else {
  4285.             if (cellHasCapture()) {
  4286.                 CellEvent.generateMouseEvent(this, currCaptureCell, e, CellEvent.MOUSE_RELEASED);
  4287.             }
  4288.         }
  4289.     }
  4290.  
  4291.     /**
  4292.      * Inherited from Component
  4293.      */
  4294.     public /*synchronized*/ void mouseMoved(MouseEvent ev, int x, int y) {
  4295.         boolean isCloseEnough = false;
  4296.         int colstart[] = getColStartPositions();
  4297.  
  4298.         if (y<headingHeight && locate(x, y) instanceof Adjustable && vsb.isVisible()) {
  4299.             //noop - over vertical scrollbar but still might want to change cursor so
  4300.             //don't return yet.
  4301.         } else
  4302.         // Use resize cursor ?
  4303.         if (useRowHeadings
  4304.             && x<rowHeadingWidth+clickMargin && y < headingHeight)
  4305.         {
  4306.             if ((x < rowHeadingWidth + clickMargin)
  4307.                 && (x > rowHeadingWidth - clickMargin))
  4308.             {
  4309.                 isCloseEnough = true;
  4310.             }
  4311.         } else if (y<headingHeight) {
  4312.                // Moving mouse around in header area
  4313.             // is it close enough to be a column size drag?
  4314.             for (int i=1; i<colstart.length; i++) {
  4315.                 if (colstart[i]==-1) { continue; }
  4316.                 if ((x < colstart[i] + clickMargin) &&
  4317.                     (x > colstart[i] - clickMargin))
  4318.                 {
  4319.                     isCloseEnough = true;
  4320.                 }
  4321.                 //check the last column
  4322.                 int lastPos = colstart[colstart.length-1] + getColumnWidth(cols());
  4323.                 if ((x < lastPos + clickMargin) &&
  4324.                     (x > lastPos - clickMargin))   {
  4325.                     isCloseEnough = true;
  4326.                 }
  4327.             }
  4328.         } else if (useRowHeadings
  4329.                    && x<rowHeadingWidth+clickMargin)
  4330.         {
  4331.             handleRowHeadingMove(x, y);
  4332.             return;
  4333.         }
  4334.  
  4335.         int cursor = (isCloseEnough? Cursor.W_RESIZE_CURSOR : Cursor.DEFAULT_CURSOR);
  4336.         setCursor(Cursor.getPredefinedCursor(cursor));
  4337.     }
  4338.  
  4339.     boolean resizeClick(int x, int y) {
  4340.         Rectangle b = getVisibleCellBoundary();
  4341.         if (y > b.height) {
  4342.             return false;
  4343.         }
  4344.  
  4345.         //adjust y so can determine if mouse within 3 pixels of boundary
  4346.         y = y - (headingHeight + 2) + 3 - cellHeight;
  4347.  
  4348.         if (y >= 0 && y % cellHeight < 6) {
  4349.             //resize cursor
  4350.             return true;;
  4351.         }
  4352.  
  4353.         return false;
  4354.     }
  4355.  
  4356.     boolean handleRowHeadingMove(int x, int y) {
  4357.         //mouse is moving around in row headings
  4358.         //set the cursor as appropriate
  4359.         //for now assume constant cell height
  4360.  
  4361.         Rectangle b = getVisibleCellBoundary();
  4362.         int cursor = Cursor.DEFAULT_CURSOR;
  4363.  
  4364.         if (y <= b.height) {
  4365.             //adjust y so can determine if mouse within 3 pixels of boundary
  4366.             y = y - (headingHeight + 2) + 3 - cellHeight;
  4367.  
  4368.             if (y >= 0 && y % cellHeight < 6) {
  4369.                 //resize cursor
  4370.                 cursor = Frame.N_RESIZE_CURSOR;
  4371.             } else {
  4372.                 //normal cursor
  4373.                 cursor = Frame.DEFAULT_CURSOR;
  4374.             }
  4375.         }
  4376.  
  4377.         setCursor(Cursor.getPredefinedCursor(cursor));
  4378.  
  4379.         return true;
  4380.     }
  4381.  
  4382.     /**
  4383.      * Inherited from Component
  4384.      */
  4385.     public /*synchronized*/ void keyReleased(KeyEvent e) {
  4386.         if (currSelectedCell != null) {
  4387.             CellEvent.generateKeyEvent(this, currSelectedCell, e, CellEvent.KEY_RELEASED);
  4388.         }
  4389.     }
  4390.  
  4391.     /**
  4392.      * Implements FocusListener interface.
  4393.      */
  4394.     public /*synchronized*/ void focusLost(FocusEvent e) {
  4395. //        if (tabbed) {
  4396. //            //if visible and tabbed then the auxControl must have received focus
  4397. //            if (auxControl!=null && !auxControl.isVisible()) {
  4398. //                requestFocus();
  4399. //            }
  4400. //            tabbed = false;
  4401. //            if (!auxControl.isVisible()) {
  4402. //                requestFocus();
  4403. //            }
  4404. //        } else {
  4405.             //need to deactivate cursor in current cell
  4406.              if (currSelectedCell != null) {
  4407.                 currSelectedCell.deactivateCursor();
  4408.             }
  4409.  
  4410.             lostCapture();
  4411.             hideAuxControl(true, false);
  4412. //        }
  4413.     }
  4414.  
  4415.     /**
  4416.      * Implements FocusListener interface.
  4417.      */
  4418.     public /*synchronized*/ void focusGained(FocusEvent e) {
  4419.         //need to activate the cursor in the current cell
  4420.          if (currSelectedCell != null) {
  4421.              currSelectedCell.activateCursor();
  4422.          }
  4423.     }
  4424.  
  4425.     TableCell getUniqueCell(int row, int col) {
  4426.         if (!cells.contains(row, col)) {
  4427.             //then we need to use the default cell
  4428.             TableCell cell = getDefaultCell(row, col).cloneCell();
  4429.             cell.setDefaultFlag();
  4430.             return cell;
  4431.         }
  4432.  
  4433.         return (TableCell)cells.elementAt(row, col);
  4434.     }
  4435.  
  4436.  
  4437.     /**
  4438.      * Inherited from Component
  4439.      */
  4440.     public /*synchronized*/ void keyPressed(KeyEvent e) {
  4441.  
  4442.         int row, col;
  4443.         boolean  changed = false;
  4444.  
  4445.         if (currSelectedCell == null) {
  4446.             row = topRow;
  4447.             col = 0;
  4448.         } else {
  4449.             row = currSelectedCell.row();
  4450.             col = currSelectedCell.col();
  4451.         }
  4452.  
  4453.         int dataRows = -1;
  4454.         try {
  4455.             dataRows = dataSource.validDataRowRange(0, row+2);
  4456.         } catch(DataNotAvailable exc) {}
  4457.         switch (e.getKeyCode()) {
  4458.             case KeyEvent.VK_ENTER:
  4459.                 if (currSelectedCell == null) { return; }
  4460.                 if (!currSelectedCell.loseFocusOnArrow()) {
  4461.                     CellEvent.generateKeyEvent(this, currSelectedCell,
  4462.                                      e, CellEvent.KEY_PRESSED);
  4463.                     return;
  4464.                 }
  4465.  
  4466.                 //if shift down go up one level, o.w. fall through to down arrow code
  4467.                 if (e.isShiftDown()) {
  4468.                     if (row > 0) {
  4469.                            TableCell newSelection = getUniqueCell(row-1, col);
  4470.                         sendFocusEvents(currSelectedCell, newSelection);
  4471.                     }
  4472.                     break;
  4473.                 }
  4474.             case KeyEvent.VK_DOWN:
  4475.                 if (currSelectedCell == null) { return; }
  4476.                 if (!currSelectedCell.loseFocusOnArrow()) {
  4477.                     CellEvent.generateKeyEvent(this, currSelectedCell,
  4478.                                      e, CellEvent.KEY_PRESSED);
  4479.                     return;
  4480.                 }
  4481.  
  4482.                 if (row < cells.rows()-1 || row < dataRows) {
  4483.                        TableCell newSelection = getUniqueCell(row+1, col);
  4484.                     sendFocusEvents(currSelectedCell, newSelection);
  4485.                 }
  4486.                 break;
  4487.             case KeyEvent.VK_TAB:
  4488.                 e.consume();
  4489.                 //if tab and shift pressed go left
  4490.                 if (e.isShiftDown()) {
  4491.                     if (col > 0) {
  4492.                         //get the previous not hidden cell in same row
  4493.                         int prev = -1;
  4494.                         for (int i=col-1; i>=0; i--) {
  4495.                             if (!colHidden[i]) {
  4496.                                 prev = i;
  4497.                                 break;
  4498.                             }
  4499.                         }
  4500.  
  4501.                         if (prev == -1) { return; }
  4502.                            TableCell newSelection = getUniqueCell(row, prev);
  4503.                         sendFocusEvents(currSelectedCell, newSelection);
  4504.                     }
  4505.                     break;
  4506.                 }
  4507.  
  4508.                 //if only tab pressed then go right
  4509.                 int numcols = cols();
  4510.                 if (col < numcols-1) {
  4511.                     int next = -1;
  4512.                     for (int i=col+1; i<numcols; i++) {
  4513.                         if (!colHidden[i]) {
  4514.                             next = i;
  4515.                             break;
  4516.                         }
  4517.                     }
  4518.  
  4519.                     if (next == -1) { return; }
  4520.                        TableCell newSelection = getUniqueCell(row, next);
  4521.                     sendFocusEvents(currSelectedCell, newSelection);
  4522.                 }
  4523.                 requestFocus();
  4524.                 break;
  4525.             case KeyEvent.VK_RIGHT:
  4526.                 if (currSelectedCell == null) { return; }
  4527.                 if (!currSelectedCell.loseFocusOnArrow()) {
  4528.                     CellEvent.generateKeyEvent(this, currSelectedCell,
  4529.                                      e, CellEvent.KEY_PRESSED);
  4530.                     return;
  4531.                 }
  4532.  
  4533.                 int cols = cols();
  4534.                 if (col < cols-1) {
  4535.                     int next = -1;
  4536.                     for (int i=col+1; i<cols; i++) {
  4537.                         if (!colHidden[i]) {
  4538.                             next = i;
  4539.                             break;
  4540.                         }
  4541.                     }
  4542.  
  4543.                     if (next == -1) { return; }
  4544.                        TableCell newSelection = getUniqueCell(row, next);
  4545.                     sendFocusEvents(currSelectedCell, newSelection);
  4546.                 }
  4547.                 break;
  4548.             case KeyEvent.VK_LEFT:
  4549.                 if (currSelectedCell == null) { return; }
  4550.                 if (!currSelectedCell.loseFocusOnArrow()) {
  4551.                     CellEvent.generateKeyEvent(this, currSelectedCell,
  4552.                                      e, CellEvent.KEY_PRESSED);
  4553.                     return;
  4554.                 }
  4555.  
  4556.                 if (col > 0) {
  4557.                     //get the previous not hidden cell in same row
  4558.                     int prev = -1;
  4559.                     for (int i=col-1; i>=0; i--) {
  4560.                         if (!colHidden[i]) {
  4561.                             prev = i;
  4562.                             break;
  4563.                         }
  4564.                     }
  4565.  
  4566.                     if (prev == -1) { return; }
  4567.                        TableCell newSelection = getUniqueCell(row, prev);
  4568.                     sendFocusEvents(currSelectedCell, newSelection);
  4569.                 }
  4570.                 break;
  4571.             case KeyEvent.VK_UP:
  4572.                 if (currSelectedCell == null) { return; }
  4573.                 if (!currSelectedCell.loseFocusOnArrow()) {
  4574.                     CellEvent.generateKeyEvent(this, currSelectedCell,
  4575.                                      e, CellEvent.KEY_PRESSED);
  4576.                     return;
  4577.                 }
  4578.  
  4579.                 if (row > 0) {
  4580.                        TableCell newSelection = getUniqueCell(row-1, col);
  4581.                     sendFocusEvents(currSelectedCell, newSelection);
  4582.                 }
  4583.                 break;
  4584.             case KeyEvent.VK_PAGE_UP:
  4585.                 scrollPageUp();
  4586.                 changed = true;
  4587.                 break;
  4588.             case KeyEvent.VK_PAGE_DOWN:
  4589.                 scrollPageDown();
  4590.                 changed = true;
  4591.                 break;
  4592.             case KeyEvent.VK_END:
  4593.                 if (currSelectedCell == null || currSelectedCell.loseFocusOnArrow()) {
  4594.                     if (e.isControlDown()) {
  4595.                         setCurrentCell(rows(), cols());
  4596.                     } else {
  4597.                         //this call is one relative
  4598.                         setCurrentCell(currSelectedCell.row() + 1,
  4599.                                             cols());
  4600.                     }
  4601.                     return;
  4602.                 }
  4603.             case KeyEvent.VK_HOME:
  4604.                 if (currSelectedCell == null || currSelectedCell.loseFocusOnArrow()) {
  4605.                     if (e.isControlDown()) {
  4606.                         //this call is one relative
  4607.                         setCurrentCell(1, 1);
  4608.                     } else {
  4609.                         //this call is one relative
  4610.                         setCurrentCell(currSelectedCell.row() + 1, 1);
  4611.                     }
  4612.  
  4613.                     if (leftCol != hsb.getMinimum()) {
  4614.                         if (hsb.isVisible()) {
  4615.                             hsbPosition = leftCol = hsb.getMinimum();
  4616.                         } else {
  4617.                             hsbPosition = leftCol = 1;
  4618.                         }
  4619.  
  4620.                         redrawAsync();
  4621.                     }
  4622.                 }
  4623.             default:
  4624.                 if (currSelectedCell != null) {
  4625.                     CellEvent.generateKeyEvent(this, currSelectedCell,
  4626.                                      e, CellEvent.KEY_PRESSED);
  4627.                     return;
  4628.                 }
  4629.         }
  4630.  
  4631.         if (changed) redrawAsync();
  4632.     }
  4633.  
  4634.    /* public void asyncNotify(Vector args) {
  4635.         redraw(true);
  4636.     }*/
  4637.     protected /* synchronized */ void myNotifyAll()
  4638.         throws java.lang.IllegalMonitorStateException
  4639.     {
  4640.         // notifyAll();
  4641.         redraw(true);
  4642.     }
  4643.  
  4644.     /**
  4645.      * Request for an asynchronous redraw of the TableView.  Calling this function can
  4646.      * greatly increase the efficiency of scrolling and rapid cell movement.
  4647.      */
  4648.     public void redrawAsync() {
  4649.         if (disableDrawing) { return; }
  4650.  
  4651.         //AsyncNotifier.notify(this);
  4652.         try {
  4653.             //setRedrawAgain(true);
  4654.             try
  4655.             {
  4656.                 myNotifyAll();
  4657.             }
  4658.             catch (java.lang.IllegalMonitorStateException e)
  4659.             {
  4660.                 System.out.println(e.getMessage());
  4661.             }
  4662.         } catch(Exception ex) {
  4663.             ex.printStackTrace();
  4664.         }
  4665.     }
  4666.  
  4667.     /**
  4668.      * Inherited from Component
  4669.      */
  4670.     public void adjustmentValueChanged(AdjustmentEvent e) {
  4671.         Adjustable scroller = (Adjustable)e.getSource();
  4672.  
  4673.         if (scroller == vsb) {
  4674.             if (topRow != vsb.getValue()) {
  4675.                 switch(e.getAdjustmentType()) {
  4676.                     case AdjustmentEvent.UNIT_INCREMENT:
  4677.                         scrollLineDown();  break;
  4678.                     case AdjustmentEvent.BLOCK_INCREMENT :
  4679.                         scrollPageDown(); break;
  4680.                     case AdjustmentEvent.BLOCK_DECREMENT:
  4681.                         scrollPageUp(); break;
  4682.                     case AdjustmentEvent.UNIT_DECREMENT:
  4683.                         scrollLineUp(); break;
  4684.                     case AdjustmentEvent.TRACK:
  4685.                         scrollUpDownAbsolute(vsb.getValue());
  4686.                         break;
  4687.                 }
  4688.             }
  4689.         } else {
  4690.             if (hsb.getValue() == hsbPosition) { return; }
  4691.  
  4692.             hsbPosition = leftCol =  hsb.getValue();
  4693.  
  4694.             //compensate for hidden columns
  4695.             for (int i=hsb.getMinimum()+1; i<leftCol; i++) {
  4696.                 if (i > colHidden.length) { break; }
  4697.                 if (colHidden[i]) { leftCol++; }
  4698.             }
  4699.  
  4700.             redrawAsync();
  4701.         }
  4702.     }
  4703.  
  4704.     /**
  4705.      * Scrolls to the specified row.
  4706.      */
  4707.     public void gotoRow(int row) {
  4708.  
  4709.         row--;
  4710.         //System.out.println("row: " + row + " topRow: " + topRow);
  4711.         //BS: we want to have the row 'row' at the top of our TableView
  4712.             //vj: Change the current row of the data source to match with that
  4713.             //    of table view
  4714.             try{
  4715.                 dataSource.setCurrentRow(row);
  4716.             }catch(TypeNotSupported ex){};
  4717.             if(row != topRow){
  4718.             //if (row < topRow || row > topRow + getPageSize().height - 1) {
  4719.                 scrollUpDownAbsolute(row);
  4720.             }
  4721.  
  4722.  
  4723.     }
  4724.  
  4725.     /**
  4726.      * Scrolls up to the specified row.
  4727.      */
  4728.     public /*synchronized*/ void scrollUpTo(int newTop) {
  4729.         newTop = Math.max(0, newTop);
  4730.  
  4731.         if (newTop != topRow) {
  4732.             vsb.setValue(newTop);
  4733.             //topRow = vsb.getValue();
  4734.             //BS: we want the line were scrolled to, to be the top one
  4735.             topRow = newTop;
  4736.             redrawAsync();
  4737.         }
  4738.     }
  4739.  
  4740.     /**
  4741.      * Scrolls in the direction required to make the specified row visible.
  4742.      */
  4743.     public void scrollUpDownAbsolute(int row) {
  4744.         if (row < topRow) {
  4745.             scrollUpTo(row);
  4746.         } else {
  4747.             scrollDownTo(row);
  4748.         }
  4749.     }
  4750.  
  4751.     /**
  4752.      * Scrolls the TableView one line up
  4753.      */
  4754.     public void scrollLineUp() {
  4755.         scrollUpTo(topRow - 1);
  4756.     }
  4757.  
  4758.     /**
  4759.      * Scrolls one page up
  4760.      */
  4761.     public void scrollPageUp() {
  4762.         scrollUpTo(topRow - getPageSize().height + 1);
  4763.     }
  4764.  
  4765.     /**
  4766.      * Scrolls down so the specified row will be visible.
  4767.      */
  4768.     public /*synchronized*/ void scrollDownTo(int nextTop) {
  4769.            //int lastRow = cells.rows()-1;
  4770.            //BS: cells.rows() was always == 0 ...
  4771.         int lastRow = dataSource.rows();
  4772.  
  4773.         try {
  4774.             lastRow = Math.max(lastRow,
  4775.                        dataSource.validDataRowRange(0, nextTop));
  4776.         } catch(DataNotAvailable ex) {}
  4777.  
  4778.         nextTop = Math.min(nextTop, lastRow);
  4779.  
  4780.         if (nextTop >= topRow) {
  4781.             vsb.setValue(nextTop);
  4782.             //topRow = vsb.getValue();
  4783.             //BS: we want the line were scrolled to, to be the top one
  4784.             topRow = nextTop;
  4785.             redrawAsync();
  4786.         }
  4787.     }
  4788.  
  4789.     /**
  4790.      * Scrolls down one line.
  4791.      */
  4792.     public void scrollLineDown() {
  4793.         scrollDownTo(topRow + 1);
  4794.     }
  4795.  
  4796.     /**
  4797.      * Scrolls down one page.
  4798.      */
  4799.     public void scrollPageDown() {
  4800.         scrollDownTo(topRow + getPageSize().height - 1);
  4801.     }
  4802.  
  4803.  
  4804.     /**
  4805.      * Gets whether a particular cell is currently being drawn.
  4806.      */
  4807.     public boolean isCellVisible(Coordinate pos) {
  4808.         if (pos == null) {
  4809.             return false;
  4810.         }
  4811.  
  4812.         return isCellVisible(pos.row+1, pos.col+1);
  4813.     }
  4814.  
  4815.     /**
  4816.      * Gets whether a particular cell is currently being drawn.
  4817.      */
  4818.     public boolean isCellVisible(int row, int col) {
  4819.         row--;
  4820.         col--;
  4821.  
  4822.         boolean changed = false;
  4823.         int rc = cells.rows();
  4824.  
  4825.         try {
  4826.             rc = Math.max(rc, dataSource.validDataRowRange(0, row+1)+1);
  4827.         } catch(DataNotAvailable ex) {}
  4828.  
  4829.         row = Math.min(rc-1, row);
  4830.         row = Math.max(0, row);
  4831.         col = Math.min(col, splitters.length);
  4832.         col = Math.max(0, col);
  4833.  
  4834.         if (row < topRow
  4835.            || row > topRow + getPageSize().height
  4836.            || !isColumnDisplayed(col+1))
  4837.         {
  4838.             return false;
  4839.         }
  4840.  
  4841.         return true;
  4842.     }
  4843.  
  4844.     /**
  4845.      * Makes the specified cell visible by scrolling as required.
  4846.      */
  4847.     public /*synchronized*/ void makeCellVisible(int row, int col) {
  4848.         row--;
  4849.         col--;
  4850.         boolean changed = false;
  4851.         int rc = cells.rows();
  4852.  
  4853.         try {
  4854.             rc = Math.max(rc, dataSource.validDataRowRange(0, row+1)+1);
  4855.         } catch(DataNotAvailable ex) {}
  4856.  
  4857.         row = Math.min(rc-1, row);
  4858.         row = Math.max(0, row);
  4859.         col = Math.min(col, cols()-1/*zero relative*/);
  4860.         col = Math.max(0, col);
  4861.  
  4862.         // scroll UPWARD
  4863.         if (row < topRow) {
  4864.             topRow = row;
  4865.             vsb.setValue(topRow);
  4866.             topRow = vsb.getValue();
  4867.             changed = true;
  4868.         }
  4869.  
  4870.         // scroll DOWNWARD
  4871.         if (row > topRow + getPageSize().height - 1) {
  4872.             topRow = row - getPageSize().height + 1;
  4873.             vsb.setValue(topRow);
  4874.             topRow = vsb.getValue();
  4875.             changed = true;
  4876.         }
  4877.  
  4878.         // scroll LEFT
  4879.         col++;
  4880.         boolean scrollLeft = false;
  4881.         if (col<leftCol && col>lockedColumn+1 && !colHidden[col-1]) {
  4882.             hsbPosition = leftCol = col;
  4883.  
  4884.             //compensate for hidden columns
  4885.             for (int i=hsb.getMinimum()+1; i<col-1; i++) {
  4886.                 if (colHidden[i]) { hsbPosition--; }
  4887.             }
  4888.  
  4889.             hsb.setValue(hsbPosition);
  4890.             scrollLeft = true;
  4891.             changed = true;
  4892.         }
  4893.  
  4894.         // scroll RIGHT
  4895.         int totalWidth = size().width-vsb.preferredSize().width;
  4896.         if (getColumnStartX(col-1, true)+getColumnWidth(col) > totalWidth) {
  4897.             hsbPosition = leftCol = col;
  4898.  
  4899.             //compensate hsbPosition for hidden columns - it only counts non-hidden
  4900.             //columns
  4901.             for (int i=hsb.getMinimum()+1; i<col-1; i++) {
  4902.                 if (colHidden[i]) { hsbPosition--; }
  4903.             }
  4904.  
  4905.             hsb.setValue(hsbPosition);
  4906.             changed = true;
  4907.         }
  4908.  
  4909.         if (changed) {
  4910.             if (scrollLeft) {
  4911.                 redrawAsync();
  4912.             } else {
  4913.                 redrawAsync();
  4914.             }
  4915.         }
  4916.     }
  4917.  
  4918.     boolean postEvent(int id, int num) {
  4919.             Event e = new Event(this, id, new Integer(num));
  4920.             return postEvent(e);
  4921.     }
  4922.  
  4923.     /**
  4924.      * Get the number of visible columns not counting locked and hidden columns
  4925.      * or row headings.
  4926.      */
  4927.     Dimension getPageSize() {
  4928.         //i is 1 based in this method b/c leftCol is 1 based
  4929.         Dimension d = size();
  4930.         int i = leftCol;
  4931.  
  4932.         //take out the width for vsb and row headings and locked columns
  4933.         if (vsb.isVisible()) { d.width -= vsb.size().width; }
  4934.         if (lockedColumn!=-1) {
  4935.             d.width -= getColumnStartX(leftCol-1, true);
  4936.         }
  4937.  
  4938.         //determine how many non-hidden columns are visible
  4939.         int totalHidden=0, hiddenCols=0;
  4940.         for (;i<splitters.length;i++) {
  4941.             if (colHidden[i-1]) {
  4942.                 totalHidden += getColumnWidth(i);
  4943.                 hiddenCols++;
  4944.                 continue;
  4945.             }
  4946.  
  4947.             if (splitters[i]-splitters[leftCol-1]-totalHidden > d.width) {
  4948.                 break;
  4949.             }
  4950.         }
  4951.  
  4952.         //set the width
  4953.         d.width = i - leftCol - hiddenCols;
  4954.  
  4955.         //compensate for the toolbar and set the height
  4956.         d.height -= bottomPanel.size().height;
  4957.         d.height = (d.height - headingHeight)/cellHeight;
  4958.  
  4959.         return d;
  4960.     }
  4961.  
  4962.     void drawHeadings(int numRowsToDraw) {
  4963.         //iterate headings and draw them
  4964.         int                 r = 0;
  4965.         MatrixEnumeration   e = colHeadings.elements();
  4966.         TableCell           c = null;
  4967.         int                 x, w;
  4968.         int                 cols = cols();
  4969.  
  4970.         //create a new graphics so can change attributes without having to reset.
  4971.         Graphics headingG = gg.create();
  4972.         Shape clip = gg.getClip();
  4973.         if (clip==null) { clip = new Rectangle(0, 0, width, height); }
  4974.  
  4975.         int lastVisCol = lastVisibleCol();
  4976.         //iterate the cols of the current row
  4977. for (int col=0; col<cols && col<=lastVisCol; col++) {
  4978.             if ((col>lockedColumn && col<leftCol-1) || colHidden[col]) { continue; }
  4979. //        for (int col=leftCol-1; col<cols; col++) {
  4980.             if (col>lockedColumn && col<leftCol-1 || colHidden[col]) { continue; }
  4981.             w = getColumnWidth(col+1);
  4982.             c = (TableCell)colHeadings.elementAt(0, col);
  4983.             hints.setHints(c);
  4984.             hints.clip(headingG);
  4985.             try {
  4986.                 c.drawCell(headingG, hints);
  4987.             } finally {
  4988.                 headingG.setClip(clip);
  4989.             }
  4990.         }
  4991.  
  4992.         drawRowHeadings(headingG, numRowsToDraw);
  4993.     }
  4994.  
  4995.     synchronized void redrawColHeadingCell(int col) {
  4996.         if (col < leftCol-1) {
  4997.             //col heading not visible so get out now
  4998.             return;
  4999.         }
  5000.  
  5001.         if (colHeadings.contains(0, col)) {
  5002.             TableCell cell = (TableCell)colHeadings.elementAt(0, col);
  5003.             hints.setHints(cell);
  5004.             cell.drawCell(gg, hints);
  5005.         }
  5006.  
  5007.     }
  5008.  
  5009.     synchronized void redrawRowHeadingCell(int row) {
  5010.         if (!useRowHeadings || !validRow(row)) {
  5011.             //not drawing row heading so get out quickly
  5012.             return;
  5013.         }
  5014.  
  5015.         //if current cell is heading cell we need to draw it in proper state
  5016.         if (rowHeadingCell(currCaptureCell) && currCaptureCell.row() == row) {
  5017.             hints.setHints(currHeadingCell);
  5018.             currHeadingCell.drawCell(gg, hints);
  5019.         } else {
  5020.             TableCell       cell = headingCell.cloneCell();
  5021.  
  5022.             cell.setRow(row);
  5023.             hints.setHints(cell);
  5024.             cell.drawCell(gg, hints);
  5025.         }
  5026.     }
  5027.  
  5028.     void drawRowHeadings(Graphics headingG, int count) {
  5029.         if (!useRowHeadings) {
  5030.             //not drawing row heading so get out quickly
  5031.             return;
  5032.         }
  5033.  
  5034.         TableCell        cell = headingCell.cloneCell();
  5035.         Coordinate       c = cell.getCoordinates();
  5036.         Shape            clip = headingG.getClip();
  5037.  
  5038.         for (int i=0; i<count; i++) {
  5039.             cell.setRow(i + topRow);
  5040.             hints.setHints(cell);
  5041.             cell.drawCell(gg, hints);
  5042.  
  5043.         }
  5044.  
  5045.         //if current cell is heading cell we need to draw it in proper state
  5046.         if (rowHeadingCell(currCaptureCell)) {
  5047.             hints.setHints(currHeadingCell);
  5048.             hints.clip(headingG);
  5049.             try {
  5050.                 currHeadingCell.drawCell(headingG, hints);
  5051.             } finally {
  5052.                 headingG.setClip(clip);
  5053.             }
  5054.         }
  5055.  
  5056.         redrawCornerCell(headingG);
  5057.     }
  5058.  
  5059.     synchronized void redrawCornerCell(Graphics headingG) {
  5060.         Shape clip = headingG.getClip();
  5061.         if (clip==null) { clip = new Rectangle(0, 0, width, height); }
  5062.  
  5063.         //draw corner cell
  5064.         hints.setHints(cornerCell);
  5065.         hints.clip(headingG);
  5066.         try {
  5067.             cornerCell.drawCell(headingG, hints);
  5068.         } finally {
  5069.             headingG.setClip(clip);
  5070.         }
  5071.     }
  5072.  
  5073.     Frame frame() {
  5074.         Container c = this;
  5075.         while(!(c instanceof Frame)) {
  5076.             c = c.getParent();
  5077.         }
  5078.  
  5079.         return (Frame)c;
  5080.     }
  5081.  
  5082.     //-------------------------------------------------------------------------
  5083.     //  Event methods
  5084.     //-------------------------------------------------------------------------
  5085.  
  5086.     /**
  5087.      * Route a cell event to appropriate event handler function, data source,
  5088.      * and then the registered listeners.
  5089.      */
  5090.     public void routeTableEvent(TableEvent e) {
  5091.         if (eventHandler != null) {
  5092.             eventHandler.handleTableEvent(e);
  5093.         }
  5094.  
  5095.         dataSource.handleTableEvent(e);
  5096.  
  5097.         processEvent(e);
  5098.     }
  5099.  
  5100.     /**
  5101.      * Route a cell event to appropriate event handler function, data source,
  5102.      * and then the registered listeners.
  5103.      */
  5104.     public void routeEvent(CellEvent e) {
  5105.         if (eventHandler != null) {
  5106.             TableCell cell = e.getCell();
  5107.  
  5108.             if (rowHeadingCell(cell)) {
  5109.                 eventHandler.handleRowHeadingEvent(e, cell);
  5110.             } else if (colHeadingCell(cell)) {
  5111.                 eventHandler.handleColHeadingEvent(e, cell);
  5112.             } else if (cornerCell(cell)) {
  5113.                 eventHandler.handleCornerCellEvent(e, cell);
  5114.             } else {
  5115.                 //must be a cell
  5116.                 eventHandler.handleCellEvent(e, cell);
  5117.             }
  5118.         }
  5119.  
  5120.         //send the event to the datasource
  5121.         dataSource.handleCellEvent(e);
  5122.  
  5123.         processEvent(e);
  5124.     }
  5125.  
  5126.     /**
  5127.      * Processes events on this TreeView. If the event is an ActionEvent,
  5128.      * it invokes the processActionEvent method, else it invokes its
  5129.      * superclass's processEvent.
  5130.      * @param e the event
  5131.      */
  5132.     protected void processEvent(AWTEvent e) {
  5133.  
  5134.         //vj: Commit current cell contents if the grid loses focus.
  5135.         if ((e.getID() == java.awt.event.FocusEvent.FOCUS_LOST) && (currSelectedCell != null)) {
  5136.             try{
  5137.                 commitCurrentCell();
  5138.                 } catch(Exception ex) {
  5139.                     //Can throw RuntimeExceptions so catch everything
  5140.                     //handleException(currSelectedCell.row(), currSelectedCell.col(), ex);
  5141.                     return;
  5142.                 }
  5143.         }
  5144.  
  5145.         if (e instanceof CellEvent) {
  5146.             processCellEvent((CellEvent)e);
  5147.             return;
  5148.         } else if (e instanceof TableEvent) {
  5149.             processTableEvent((TableEvent)e);
  5150.             return;
  5151.         }
  5152.  
  5153.         super.processEvent(e);
  5154.     }
  5155.  
  5156.  
  5157.     /**
  5158.      * The cell listeners that are registered to recieve event notifications.
  5159.      */
  5160.     Vector cellListeners = new Vector();
  5161.     /**
  5162.      * The table listeners that are registered to recieve event notifications.
  5163.      */
  5164.     Vector tableListeners = new Vector();
  5165.  
  5166.     /**
  5167.      * Adds the specified cell listener to recieve cell events from this view.
  5168.      * @param l the cell event listener
  5169.      */
  5170.     public void addCellListener(CellListener l) {
  5171.         if (!cellListeners.contains(l)) {
  5172.             cellListeners.addElement(l);
  5173.         }
  5174.     }
  5175.  
  5176.     /**
  5177.      * Removes the specified cell listener so that it no longer
  5178.      * receives cell events from this view.
  5179.      * @param l the cell event listener
  5180.      */
  5181.     public void removeCellListener(CellListener l) {
  5182.         cellListeners.removeElement(l);
  5183.     }
  5184.  
  5185.     /**
  5186.      * Processes cell events occurring on this view by
  5187.      * dispatching them to any registered CellEventListener objects.
  5188.      * NOTE: This method will not be called unless cell events
  5189.      * are enabled for this component; this happens when an CellListener
  5190.      * object is registered via addCellListener().
  5191.      * @param e the cell event.
  5192.      */
  5193.     protected void processCellEvent(CellEvent e) {
  5194.         Enumeration enum = cellListeners.elements();
  5195.         while(enum.hasMoreElements()) {
  5196.             CellListener l = (CellListener)enum.nextElement();
  5197.             try {
  5198.                 l.cellEventPerformed(e);
  5199.             } catch(Exception ex) {
  5200.                 System.err.println("Error occured during event processing");
  5201.                 ex.printStackTrace();
  5202.             }
  5203.         }
  5204.     }
  5205.  
  5206.     /**
  5207.      * Adds the specified table listener to recieve table events from this view.
  5208.      * @param l the table event listener
  5209.      */
  5210.     public void addTableListener(TableListener l) {
  5211.         if (!tableListeners.contains(l)) {
  5212.             tableListeners.addElement(l);
  5213.         }
  5214.     }
  5215.  
  5216.     /**
  5217.      * Removes the specified table listener so that it no longer
  5218.      * receives table events from this view.
  5219.      * @param l the table event listener
  5220.      */
  5221.     public void removeTableListener(TableListener l) {
  5222.         tableListeners.removeElement(l);
  5223.     }
  5224.  
  5225.     /**
  5226.      * Processes table events occurring on this view by
  5227.      * dispatching them to any registered TableEventListener objects.
  5228.      * NOTE: This method will not be called unless cell events
  5229.      * are enabled for this component; this happens when an TableListener
  5230.      * object is registered via addTableListener().
  5231.      * @param e the cell event.
  5232.      */
  5233.     protected void processTableEvent(TableEvent e) {
  5234.         Enumeration enum = tableListeners.elements();
  5235.         while(enum.hasMoreElements()) {
  5236.             TableListener l = (TableListener)enum.nextElement();
  5237.             try {
  5238.                 l.tableEventPerformed(e);
  5239.             } catch(Exception ex) {
  5240.                 System.err.println("Error occured during event processing");
  5241.                 ex.printStackTrace();
  5242.             }
  5243.         }
  5244.     }
  5245.  
  5246.     /**
  5247.      * Component on toolbar triggered an event. This will result in the firing of
  5248.      * a TableEvent.
  5249.      */
  5250.     public void toolbarActionPerformed(ActionEvent event) {
  5251.         TableEvent e = new TableEvent(this, event, TableEvent.TOOLBAR_EVENT);
  5252.         if (event.getSource() == gotoButton) {
  5253.             e.setParameter(gotoTextField.getText());
  5254.         }
  5255.  
  5256.         routeTableEvent(e);
  5257.     }
  5258.  
  5259.     /**
  5260.      * Processes mouse events occurring on this component by
  5261.      * dispatching them to any registered MouseListener objects.
  5262.      * Classes overriding this method should call super.processMouseEvent()
  5263.      * to ensure default event processing continues normally.
  5264.      */
  5265.     protected void processMouseEvent(MouseEvent e) {
  5266.         int id = e.getID();
  5267.         switch(id) {
  5268.           case MouseEvent.MOUSE_PRESSED:
  5269.             mousePressed(e, e.getX(), e.getY());
  5270.             break;
  5271.           case MouseEvent.MOUSE_RELEASED:
  5272.             mouseReleased(e, e.getX(), e.getY());
  5273.             break;
  5274.           case MouseEvent.MOUSE_CLICKED:
  5275.             //no op
  5276.             break;
  5277.           case MouseEvent.MOUSE_EXITED:
  5278.             mouseExited(e.getX(), e.getY());
  5279.             break;
  5280.           case MouseEvent.MOUSE_ENTERED:
  5281.             //no op
  5282.             break;
  5283.         }
  5284.  
  5285.         //let the parent class process the event as normal
  5286.         super.processMouseEvent(e);
  5287.     }
  5288.  
  5289.     /**
  5290.      * Processes mouse motion events occurring on this component by
  5291.      * dispatching them to any registered MouseMotionListener objects.
  5292.      * Classes overriding this method should call super.processMouseMotionEvent()
  5293.      * to ensure default event processing continues normally.
  5294.      */
  5295.     protected void processMouseMotionEvent(MouseEvent e) {
  5296.         if (e.getID() == MouseEvent.MOUSE_DRAGGED) {
  5297.             mouseDragged(e, e.getX(), e.getY());
  5298.         } else if (e.getID() == MouseEvent.MOUSE_MOVED) {
  5299.             mouseMoved(e, e.getX(), e.getY());
  5300.         }
  5301.  
  5302.         super.processMouseMotionEvent(e);
  5303.     }
  5304.  
  5305.     /**
  5306.      * Processes key events occurring on this component by
  5307.      * dispatching them to any registered KeyListener objects.
  5308.      * NOTE: This method will not be called unless key events
  5309.      * are enabled for this component; this happens when one of the
  5310.      * following occurs:
  5311.      * a) A KeyListener object is registered via addKeyListener()
  5312.      * b) Key events are enabled via enableEvents()
  5313.      * Classes overriding this method should call super.processKeyEvent()
  5314.      * to ensure default event processing continues normally.
  5315.      * @param e the key event
  5316.      */
  5317.     protected void processKeyEvent(KeyEvent e) {
  5318.         if (e.getID() == KeyEvent.KEY_PRESSED) {
  5319.             keyPressed(e);
  5320.         } else if (e.getID() == KeyEvent.KEY_RELEASED) {
  5321.             keyReleased(e);
  5322.         }
  5323.  
  5324.         super.processKeyEvent(e);
  5325.     }
  5326.  
  5327. //-----------------------------------------------------------------------------
  5328. //          Search & Filter methods (well just search for now)
  5329. //-----------------------------------------------------------------------------
  5330.  
  5331.     public int findSubstring(String query, int col, boolean forward, boolean useCase) {
  5332.         col--;
  5333.         if (col < 0  || col >= cols()) {
  5334.             throw new IllegalArgumentException("col=" + (col+1) + " is not in view");
  5335.         }
  5336.  
  5337.         int     start,
  5338.                 stop = rows() - 1;
  5339.  
  5340.         if (!useCase) {
  5341.             query = query.toUpperCase();
  5342.         }
  5343.  
  5344.         int step = forward  ?1  :-1;
  5345.         if (currSelectedCell != null) {
  5346.             start = currSelectedCell.row() + step;
  5347.         } else if (forward) {
  5348.             start = 0;
  5349.         } else {
  5350.             start = rows() - 1;
  5351.             stop = 0;
  5352.         }
  5353.  
  5354.         try {
  5355.             int index = -1;
  5356.             for (int row=start; row<=stop; row+=step) {
  5357.                 String curr = getCellText(row+1, col+1);
  5358.                 if (useCase) {
  5359.                     index = curr.indexOf(query);
  5360.                 } else {
  5361.                     index = curr.toUpperCase().indexOf(query);
  5362.                 }
  5363.  
  5364.                 if (index != -1) {
  5365.                     return row + 1;
  5366.                 }
  5367.             }
  5368.         } catch (DataNotAvailable ex) {
  5369.             ex.printStackTrace();
  5370.         }
  5371.  
  5372.         return -1;
  5373.     }
  5374.  
  5375. //-----------------------------------------------------------------------------
  5376. //          AuxControl methods
  5377. //-----------------------------------------------------------------------------
  5378.  
  5379.     Component   auxControl = null;
  5380.     Coordinate  auxOwnerPos = null;
  5381.     boolean     auxShowing = false;
  5382.     Matrix      storage = new Matrix();
  5383.  
  5384.     public /*synchronized*/ Component registerAuxControl(Component aux, TableCell owner) {
  5385.         if (aux == null || owner == null) {
  5386.             return null;
  5387.         }
  5388.  
  5389.         if (auxControl != null) {
  5390.             unregisterAuxControl(getAuxOwner());
  5391.         }
  5392.  
  5393.         add(aux);
  5394.         aux.hide();
  5395.  
  5396.         auxControl = aux;
  5397.         auxOwnerPos = owner.getCoordinates();
  5398.         getAuxControlRegion();
  5399.  
  5400.         return aux;
  5401.     }
  5402.  
  5403.     public Component registerAuxControl(TableCell owner) {
  5404.         return registerAuxControl(getCellControl(owner), owner);
  5405.     }
  5406.  
  5407.     public Component getAuxControl(TableCell owner) {
  5408.         if (!isAuxOwner(owner)) {
  5409.             throw new IllegalArgumentException("Only control owner may unregister the aux control");
  5410.         }
  5411.  
  5412.         return auxControl;
  5413.     }
  5414.  
  5415.     public /*synchronized*/ TableCell getAuxOwner() {
  5416.         if (auxControl == null) {
  5417.             return null;
  5418.         }
  5419.  
  5420.         return getCell(auxOwnerPos);
  5421.     }
  5422.  
  5423.     public /*synchronized*/ void unregisterAuxControl(TableCell owner) {
  5424.         if (!owner.getCoordinates().equals(auxOwnerPos)) {
  5425.             throw new IllegalArgumentException("Only control owner may unregister the aux control");
  5426.         }
  5427.  
  5428.         remove(auxControl);
  5429.  
  5430.         auxShowing = false;
  5431.         auxControl = null;
  5432.         owner.lostAuxControl();
  5433.         auxOwnerPos = null;
  5434.     }
  5435.  
  5436.     public boolean isAuxOwner(TableCell cell) {
  5437.         return cell.getCoordinates().equals(auxOwnerPos);
  5438.     }
  5439.  
  5440.     public void doLayout() {
  5441.         super.doLayout();
  5442.  
  5443.         //awt hack! Makes control fill entire area otherwise.
  5444.         moveAuxControl();
  5445.     }
  5446.  
  5447.     public /*synchronized*/ void moveAuxControl() {
  5448.         boolean visible = isCellVisible(auxOwnerPos);
  5449.  
  5450.         if (auxControl != null && visible && auxShowing) {
  5451.             Rectangle b = getAuxControlRegion();
  5452.             auxControl.show();
  5453.             auxControl.reshape(b.x, b.y, b.width, b.height);
  5454.             auxControl.doLayout();
  5455.         } else if (!visible) {
  5456.             hideAuxControl(true, true);
  5457.         }
  5458.     }
  5459.  
  5460.     public /*synchronized*/ void showAuxControl() {
  5461.         if (auxControl == null) {
  5462.             return;
  5463.         }
  5464.  
  5465.         auxShowing = true;
  5466.         if (!isCellVisible(auxOwnerPos)) {
  5467.             return;
  5468.         }
  5469.  
  5470.         moveAuxControl();
  5471.         auxControl.show();
  5472. //        tabbed = true;
  5473.         auxControl.requestFocus();
  5474.     }
  5475.  
  5476.     public void hideAuxControl() {
  5477.         hideAuxControl(false, true);
  5478.     }
  5479.  
  5480.     public /*synchronized*/ void hideAuxControl(boolean tempHide, boolean keepFocus) {
  5481.         if (auxControl != null) {
  5482.             auxControl.hide();
  5483.             if (keepFocus) {
  5484.                 requestFocus();
  5485.             }
  5486.             if (!tempHide) {
  5487.                 auxShowing = false;
  5488.             }
  5489.         }
  5490.     }
  5491.  
  5492.     public boolean isAuxVisible() {
  5493.         if (auxControl == null) {
  5494.             return false;
  5495.         }
  5496.  
  5497.         return auxControl.isVisible();
  5498.     }
  5499.  
  5500.     public /*synchronized*/ Rectangle getAuxControlRegion() {
  5501.         if (auxControl == null) {
  5502.             throw new NullPointerException("AuxControl not set");
  5503.         }
  5504.  
  5505.         //get size
  5506.         Dimension size = size();
  5507.  
  5508.         //get cell bounds
  5509.         Rectangle bounds = getCellBounds(getAuxOwner());
  5510.         Dimension tbSize = toolbar.size();
  5511.         //get the controls preferred size
  5512.         Dimension prefSize = auxControl.preferredSize();
  5513.  
  5514.         prefSize.width = Math.max(prefSize.width, bounds.width);
  5515.         //try to put below first, if can't then put above if possible
  5516.         //o.w. put it in the best place
  5517.         if (bounds.y + bounds.height + prefSize.height < size.height - tbSize.height) {
  5518.             //can put below.  try to align with left first
  5519.             if (bounds.x + prefSize.width < size.width) {
  5520.                 //flush left below
  5521.                 return setAuxArea(bounds.x, bounds.y+bounds.height,
  5522.                                   prefSize.width, prefSize.height);
  5523.             } else if (bounds.x + bounds.width - prefSize.width > 0) {
  5524.                 //flush right below
  5525.                 return setAuxArea(bounds.x + bounds.width - prefSize.width,
  5526.                                   bounds.y + bounds.height,
  5527.                                   prefSize.width, prefSize.height);
  5528.             } else {
  5529.                 return bestFitBelow(size, bounds, prefSize);
  5530.             }
  5531.         } else if (bounds.y - prefSize.height > 0) {
  5532.             //can put above
  5533.             if (bounds.x + prefSize.width < size.width) {
  5534.                 //flush left above
  5535.                 return setAuxArea(bounds.x, bounds.y-prefSize.height+2,
  5536.                                   prefSize.width, prefSize.height);
  5537.             } else if (bounds.x + bounds.width - prefSize.width > 0) {
  5538.                 //flush right below
  5539.                 return setAuxArea(bounds.x + bounds.width - prefSize.width,
  5540.                                   bounds.y-prefSize.height+2,
  5541.                                   prefSize.width, prefSize.height);
  5542.             } else {
  5543.                 return bestFitAbove(size, bounds, prefSize);
  5544.             }
  5545.         } else {
  5546.             return bestFit(size, bounds, prefSize, tbSize);
  5547.         }
  5548.     }
  5549.  
  5550.     Rectangle setAuxArea(int x, int y, int w, int h) {
  5551.         return new Rectangle(x, y, w, h);
  5552.     }
  5553.  
  5554.     Rectangle bestFitBelow(Dimension size, Rectangle bounds, Dimension prefSize) {
  5555.         //can't put flush left or right so put as far right as possible
  5556.         if (prefSize.width > size.width) {
  5557.             //too wide so reduce to TableView width
  5558.             prefSize.width = size.width;
  5559.         }
  5560.  
  5561.         //put as far right as possible
  5562.         return setAuxArea(size.width - prefSize.width, bounds.y + bounds.height,
  5563.                           prefSize.width, prefSize.height);
  5564.     }
  5565.  
  5566.  
  5567.  
  5568.     Rectangle bestFitAbove(Dimension size, Rectangle bounds, Dimension prefSize) {
  5569.         //can't put flush left or right so put as far right as possible
  5570.         if (prefSize.width > size.width) {
  5571.             //too wide so reduce to TableView width
  5572.             prefSize.width = size.width;
  5573.         }
  5574.  
  5575.         //put as far right as possible
  5576.         return setAuxArea(size.width - prefSize.width, bounds.y - prefSize.height,
  5577.                           prefSize.width, prefSize.height);
  5578.     }
  5579.  
  5580.  
  5581.  
  5582.     Rectangle bestFit(Dimension size, Rectangle bounds, Dimension prefSize, Dimension tbSize) {
  5583.         //can't put above or below full size so put where most room
  5584.         if (prefSize.width > size.width) {
  5585.             //too wide so reduce to TableView width
  5586.             prefSize.width = size.width;
  5587.         }
  5588.  
  5589.         int above = bounds.y;
  5590.         int below = size.height - bounds.y - bounds.height - tbSize.height;
  5591.         int maxRoom = Math.max(above, below);
  5592.  
  5593.         if (prefSize.height > maxRoom) {
  5594.             //too tall so reduce to either height above or below cell
  5595.             prefSize.height = maxRoom;
  5596.         }
  5597.  
  5598.         if (maxRoom == above) {
  5599.             //put above
  5600.                if (bounds.x + prefSize.width < size.width) {
  5601.                 //flush left above
  5602.                 return setAuxArea(bounds.x, bounds.y-prefSize.height+2,
  5603.                                   prefSize.width, prefSize.height);
  5604.             } else if (bounds.x + bounds.width - prefSize.width > 0) {
  5605.                 //flush right below
  5606.                 return setAuxArea(bounds.x + bounds.width - prefSize.width,
  5607.                                   bounds.y-prefSize.height+2,
  5608.                                   prefSize.width, prefSize.height);
  5609.             } else {
  5610.                 return setAuxArea(size.width - prefSize.width,
  5611.                                      0,
  5612.                                      prefSize.width, above);
  5613.             }
  5614.         } else {
  5615.             //put below
  5616.             if (bounds.x + prefSize.width < size.width) {
  5617.                 //flush left below
  5618.                 return setAuxArea(bounds.x, bounds.y+bounds.height,
  5619.                                   prefSize.width, prefSize.height);
  5620.             } else  if (bounds.x + bounds.width - prefSize.width > 0) {
  5621.                 //flush right below
  5622.                 return setAuxArea(bounds.x + bounds.width - prefSize.width,
  5623.                                   bounds.y + bounds.height,
  5624.                                   prefSize.width, prefSize.height);
  5625.             } else {
  5626.                 //put all the way to right
  5627.                 return setAuxArea(size.width - prefSize.width,
  5628.                                   bounds.y + bounds.height,
  5629.                                   prefSize.width, below);
  5630.             }
  5631.         }
  5632.     }
  5633.  
  5634.     public void setStore(TableCell cell, Object s) {
  5635.         storage.updateElement(cell.row(), cell.col(), s);
  5636.     }
  5637.  
  5638.     public Object getStore(TableCell cell) throws NullPointerException {
  5639.         if (storage.contains(cell.row(), cell.col())) {
  5640.             return storage.elementAt(cell.row(), cell.col());
  5641.         }
  5642.  
  5643.         throw new NullPointerException("No object store for cell row="
  5644.                     + cell.row() + " col=" + cell.col());
  5645.     }
  5646.  
  5647.     public boolean isStored(TableCell cell) {
  5648.         return storage.contains(cell.row(), cell.col());
  5649.     }
  5650.  
  5651.  
  5652. //-----------------------------------------------------------------------------
  5653. //          CellHints methods
  5654. //-----------------------------------------------------------------------------
  5655.  
  5656.   /**
  5657.      * Adds a CellHint dedicated to a row.
  5658.      * <p>This fucntion is 0 relative
  5659.      */
  5660.     public void addRowHint(int row, CellHints c) {
  5661.         row++;
  5662.  
  5663.         cellAttributes.addElement(row, 0, c);
  5664.     }
  5665.  
  5666.     /**
  5667.      * Adds a CellHint dedicated to a cell.
  5668.      * <p>This fucntion is 0 relative
  5669.      */
  5670.     public void addCellHint(int row, int col, CellHints c) {
  5671.         row++;
  5672.         col++;
  5673.  
  5674.         cellAttributes.addElement(row, col, c);
  5675.     }
  5676.  
  5677.     /**
  5678.      * Gets a CellHint dedicated to a cell.
  5679.      * <p>This fucntion is 0 relative
  5680.      */
  5681.     public CellHints getCellHints(int row, int col) {
  5682.         row++;
  5683.         col++;
  5684.  
  5685.         if (cellAttributes.contains(row, col)) {
  5686.             return (CellHints)cellAttributes.elementAt(row, col);
  5687.         } else {
  5688.             return null;
  5689.         }
  5690.     }
  5691.  
  5692.     /**
  5693.      * Gets a CellHint dedicated to a row.
  5694.      * <p>This fucntion is 0 relative
  5695.      */
  5696.     public CellHints getRowHints(int row) {
  5697.         row++;
  5698.  
  5699.         if (cellAttributes.contains(row, 0)) {
  5700.             return (CellHints)cellAttributes.elementAt(row, 0);
  5701.         } else {
  5702.             return null;
  5703.         }
  5704.     }
  5705.  
  5706.     /**
  5707.      * Gets a CellHint dedicated to a column.
  5708.      * <p>This fucntion is 0 relative
  5709.      */
  5710.     public CellHints getColHints(int col) {
  5711.         //column attributes must be set
  5712.         col++;
  5713.  
  5714.         return (CellHints)cellAttributes.elementAt(0, col);
  5715.     }
  5716.  
  5717.     /**
  5718.      * Gets the cell hints for a row heading.
  5719.      */
  5720.     public final CellHints getRowHeadingHints(int row) {
  5721.         return rowHeadingHints;
  5722.     }
  5723.  
  5724.     /**
  5725.      * Gets the CellHints for a column heading<p>
  5726.      * row is zero relative<br>
  5727.      * col is one relative - with cornercell coord being 0
  5728.      */
  5729.     public final CellHints getHeadingHints(int row, int col) {
  5730.         return (CellHints)headingAttributes.elementAt(row, col);
  5731.     }
  5732.  
  5733.     public void putLineStyles(TableCell c, CellHints hints) {
  5734.         if (colHeadingCell(c)) {
  5735.             hints.cascadeLineStyles(null, null, getHeadingHints(c.row(), c.col()+1));
  5736.             return;
  5737.         } else if (c == cornerCell) {
  5738.             hints.cascadeLineStyles(null, null, getHeadingHints(0, 0));
  5739.             return;
  5740.         } else if (rowHeadingCell(c)) {
  5741.             hints.cascadeLineStyles(null, null, getRowHeadingHints(c.row()));
  5742.             return;
  5743.         }
  5744.  
  5745.         CellHints hc = getCellHints(c.row(), c.col());
  5746.         CellHints hr = getRowHints(c.row());
  5747.         CellHints h = getColHints(c.col());
  5748.  
  5749.         hints.cascadeLineStyles(hr, hc, h);
  5750.     }
  5751.  
  5752.     /**
  5753.      * Gets the cell alignment for the specified cell
  5754.      */
  5755.     public int getCellAlignment(TableCell c) {
  5756.         if (colHeadingCell(c)) {
  5757.             return getColHints(c.col()).align;
  5758.         } else if (c == cornerCell || rowHeadingCell(c)) {
  5759.             return getRowHeadingHints(c.row()).align;
  5760.         }
  5761.  
  5762.         CellHints hc = getCellHints(c.row(), c.col());
  5763.         CellHints hr = getRowHints(c.row());
  5764.         CellHints h = getColHints(c.col());
  5765.  
  5766.         return h.cascadeAlignment(hr, hc);
  5767.     }
  5768.  
  5769.     /**
  5770.      * Gets the cell foreground for the specified cell
  5771.      */
  5772.     public Color getCellFG(TableCell c) {
  5773.         if (printMode) { return Color.black; }
  5774.  
  5775.         if (colHeadingCell(c)) {
  5776.             return getHeadingHints(c.row(), c.col()+1).fg;
  5777.         } else if (c == cornerCell) {
  5778.             return getHeadingHints(0, 0).fg;
  5779.         } else if (rowHeadingCell(c)) {
  5780.             return getRowHeadingHints(c.row()).fg;
  5781.         }
  5782.  
  5783.         CellHints hc = getCellHints(c.row(), c.col());
  5784.         CellHints hr = getRowHints(c.row());
  5785.         CellHints h = getColHints(c.col());
  5786.  
  5787.         return h.cascadeForeground(hr, hc);
  5788.     }
  5789.  
  5790.     /**
  5791.      * Gets the cell background for the specified cell
  5792.      */
  5793.     public Color getCellBG(TableCell c) {
  5794.         if (printMode) { return Color.white; }
  5795.  
  5796.         if (colHeadingCell(c)) {
  5797.             return getHeadingHints(c.row(), c.col()+1).bg;
  5798.         } else if (c == cornerCell) {
  5799.             return getHeadingHints(0, 0).bg;
  5800.         } else if (rowHeadingCell(c)) {
  5801.             return getRowHeadingHints(c.row()).bg;
  5802.         }
  5803.  
  5804.         CellHints hc = getCellHints(c.row(), c.col());
  5805.         CellHints hr = getRowHints(c.row());
  5806.         CellHints h = getColHints(c.col());
  5807.  
  5808.         return h.cascadeBackground(hr, hc);
  5809.     }
  5810.  
  5811.     /**
  5812.      * Gets whether a specified cell is editable according to the CellHints
  5813.      */
  5814.     public boolean getCellEditable(TableCell c) {
  5815.         if (colHeadingCell(c)) {
  5816.             return getHeadingHints(c.row(), c.col()+1).editable;
  5817.         } else if (c == cornerCell) {
  5818.             return getHeadingHints(0, 0).editable;
  5819.         } else if (rowHeadingCell(c)) {
  5820.             return getRowHeadingHints(c.row()).editable;
  5821.         }
  5822.  
  5823.         CellHints hc = getCellHints(c.row(), c.col());
  5824.         CellHints hr = getRowHints(c.row());
  5825.         CellHints h = getColHints(c.col());
  5826.  
  5827.         return h.cascadeEditable(hr, hc);
  5828.     }
  5829.  
  5830.     /**
  5831.      * Determines whether the specified cell is highlighted
  5832.      */
  5833.     public boolean getCellHighlighted(TableCell c) {
  5834.         //adjust for all highlight functions being 1 relative
  5835.         int row = c.row() + 1;
  5836.         int col = c.col() + 1;
  5837.  
  5838.         if (colHeadingCell(c)) {
  5839.             isColumnSelected(col);
  5840.         } else if (c == cornerCell) {
  5841.             return isViewSelected();
  5842.         } else if (rowHeadingCell(c)) {
  5843.             return isRowSelected(row) || isCellSelected(row, col);
  5844.         }
  5845.  
  5846.         //must be an honest to goodness cell
  5847.         return isCellSelected(row, col);
  5848.     }
  5849.  
  5850.     /**
  5851.      * Gets the font for the specified cell
  5852.      */
  5853.     public Font getCellFont(TableCell c) {
  5854.         if (colHeadingCell(c)) {
  5855.             return getHeadingHints(c.row(), c.col()+1).font;
  5856.         } else if (c == cornerCell) {
  5857.             return getHeadingHints(0, 0).font;
  5858.         } else if (rowHeadingCell(c)) {
  5859.             return getRowHeadingHints(c.row()).font;
  5860.         }
  5861.  
  5862.         CellHints hc = getCellHints(c.row(), c.col());
  5863.         CellHints hr = getRowHints(c.row());
  5864.         CellHints h = getColHints(c.col());
  5865.  
  5866.         return h.cascadeFont(hr, hc);
  5867.     }
  5868.  
  5869.     /**
  5870.      * Gets the storage object associated with a cell.
  5871.      */
  5872.     public Object getCellStorage(TableCell c) {
  5873.         if (colHeadingCell(c)) {
  5874.             return getHeadingHints(c.row(), c.col()+1).cellStorage;
  5875.         } else if (c == cornerCell) {
  5876.             return getHeadingHints(0, 0).cellStorage;
  5877.         } else if (rowHeadingCell(c)) {
  5878.             return getRowHeadingHints(c.row()).cellStorage;
  5879.         }
  5880.  
  5881.         CellHints hc = getCellHints(c.row(), c.col());
  5882.         CellHints hr = getRowHints(c.row());
  5883.         CellHints h = getColHints(c.col());
  5884.  
  5885.         return h.cascadeStorage(hr, hc);
  5886.     }
  5887.  
  5888.     /**
  5889.      * Gets the auxillary control for cell.
  5890.      */
  5891.     public Component getCellControl(TableCell c) {
  5892.         if (colHeadingCell(c)) {
  5893.             return getHeadingHints(c.row(), c.col()+1).control;
  5894.         } else if (c == cornerCell) {
  5895.             return getHeadingHints(0, 0).control;
  5896.         } else if (rowHeadingCell(c)) {
  5897.             return getRowHeadingHints(c.row()).control;
  5898.         }
  5899.  
  5900.         CellHints hc = getCellHints(c.row(), c.col());
  5901.         CellHints hr = getRowHints(c.row());
  5902.         CellHints h = getColHints(c.col());
  5903.  
  5904.         return h.cascadeControl(hr, hc);
  5905.     }
  5906.  
  5907.  
  5908. //-----------------------------------------------------------------------------
  5909. //          Selection control variables and member functions
  5910. //-----------------------------------------------------------------------------
  5911.  
  5912. //ALL OF THESE FUNCTIONS ARE ONE RELATIVE!!!!!!!
  5913.  
  5914.     /**
  5915.      * The bit set that defines which cells/rows/cols are selected. <BR>
  5916.      * bit 0 = corner cell <BR>
  5917.      * bit 1 - # of cols = columns <BR>
  5918.      * bit (# of cols) * row + 1 = rows <BR>
  5919.      * all other bits represent individual cells
  5920.      */
  5921.     BitSet      selected = new BitSet();
  5922.     Coordinate  selectionBase = null;
  5923.     Coordinate  selectionLimit = null;;
  5924.     boolean     selectionMade = false;
  5925.  
  5926.     /**
  5927.      * Gets whether the specified row is selected
  5928.      */
  5929.     public boolean isRowSelected(int row) {
  5930.         return selected.get(tx4Sxn(row));
  5931.     }
  5932.  
  5933.     /**
  5934.      * Gets whether the specified cell is selected
  5935.      */
  5936.     public boolean isCellSelected(int row, int col) {
  5937.         return selected.get(tx4Sxn(row, col));
  5938.     }
  5939.  
  5940.     /**
  5941.      * Gets whether the specified column is selected
  5942.      */
  5943.     public boolean isColumnSelected(int col) {
  5944.         return selected.get(col);
  5945.     }
  5946.  
  5947.     /**
  5948.      * Gets whether the whole TableView is selected
  5949.      */
  5950.     public boolean isViewSelected() { return selected.get(0); }
  5951.  
  5952.     public void toggleCell(int row, int col) {
  5953.         if (!isRowSelected(row)) {
  5954.             toggleBit(tx4Sxn(row, col));
  5955.         }
  5956.     }
  5957.  
  5958.     /**
  5959.      * Gets a list of the coordinates for all of the selected cells
  5960.      */
  5961.     public Coordinate[] getSelectedCells() {
  5962.         Vector cells = new Vector();
  5963.         int cols = cols();
  5964.         int rows = sxnRows(cols);
  5965.  
  5966.         for (int row=1;row<rows;row++) {
  5967.             for (int col=1; col<cols; col++) {
  5968.                 if (selected.get(tx4Sxn(row, col))) {
  5969.                     cells.addElement(new Coordinate(row, col));
  5970.                 }
  5971.             }
  5972.         }
  5973.  
  5974.         Coordinate sxn[] = new Coordinate[cells.size()];
  5975.         cells.copyInto(sxn);
  5976.  
  5977.         return sxn;
  5978.     }
  5979.  
  5980.     /**
  5981.      * Gets the row number of the first selected row
  5982.      * @return The first selected row, -1 if none are selected
  5983.      */
  5984.     public int getFirstSelectedRow() {
  5985.         int cols = cols();
  5986.         int total = selected.size();
  5987.         int row = 1;
  5988.  
  5989.         for (int index=cols+1; index<total; index+=(cols+1), row++) {
  5990.             if (selected.get(index)) {
  5991.                 return row;
  5992.             }
  5993.         }
  5994.  
  5995.         return -1;
  5996.     }
  5997.  
  5998.     /**
  5999.      * Gets an array of all of the selected rows
  6000.      */
  6001.     public int[] getSelectedRows() {
  6002.         int cols = cols();
  6003.         int total = selected.size();
  6004.         int srows[] = new int[dataSource.rows()];
  6005.         int row = 1;
  6006.         int next = 0;
  6007.  
  6008.         for (int index=cols+1; index<total; index+=(cols+1), row++) {
  6009.             if (selected.get(index)) {
  6010.                 srows[next++] = row;
  6011.             }
  6012.         }
  6013.  
  6014.         int sxn[] = new int[next];
  6015.         System.arraycopy(srows, 0, sxn, 0, next);
  6016.  
  6017.         return sxn;
  6018.     }
  6019.  
  6020.     /**
  6021.      * Gets an array of all of the selected columns
  6022.      */
  6023.     public int[] getSelectedCols() {
  6024.         int cols = cols();
  6025.         int scols[] = new int[cols];
  6026.         int next = 0;
  6027.  
  6028.         for (int col=1; col<=cols; col++) {
  6029.             if (selected.get(col)) {
  6030.                 scols[next-1] = col;
  6031.                 next++;
  6032.             }
  6033.         }
  6034.  
  6035.         int sxn[] = new int[next];
  6036.         System.arraycopy(scols, 0, sxn, 0, next);
  6037.  
  6038.         return sxn;
  6039.     }
  6040.  
  6041.     /**
  6042.      * Determines whether the specified row is hightlighted
  6043.      */
  6044.     public boolean isRowSet(int row) {
  6045.         return selected.get(tx4Sxn(row));
  6046.     }
  6047.  
  6048.     /**
  6049.      * Selects the specified row
  6050.      */
  6051.     public /*synchronized*/ void setRow(int row, boolean setTo) {
  6052.  
  6053.         int bit = tx4Sxn(row);
  6054.         int cols = cols();
  6055.  
  6056.         for (int i=0;i<=cols;i++) {
  6057.             if (setTo) {
  6058.                 selected.set(bit+i);
  6059.             } else {
  6060.                 selected.clear(bit+i);
  6061.             }
  6062.         }
  6063.  
  6064.         selectionMade = true;
  6065.  
  6066.         if (autoRedraw) { redrawRow(row); }
  6067.     }
  6068.  
  6069.     /**
  6070.      * Toggles the selection on the specified row.
  6071.      */
  6072.     public /*synchronized*/ void toggleRow(int row) {
  6073.  
  6074.         int bit = tx4Sxn(row);
  6075.         boolean set = selected.get(bit);
  6076.         int cols = cols();
  6077.  
  6078.         for (int i=0;i<=cols;i++) {
  6079.             if (set) {
  6080.                 selected.clear(bit+i);
  6081.             } else {
  6082.                 selected.set(bit+i);
  6083.             }
  6084.         }
  6085.  
  6086.         selectionMade = true;
  6087.         if (autoRedraw) { redrawRow(row); }
  6088.     }
  6089.  
  6090.     /**
  6091.      * Toggles the selection for the specified column
  6092.      */
  6093.     public /*synchronized*/ void toggleCol(int col) {
  6094.         boolean set = selected.get(col);
  6095.         int cols = cols();
  6096.         int total = selected.size();
  6097.  
  6098.         for (int i=col; i<=total; i+=(cols+1)) {
  6099.             if (set) {
  6100.                 selected.clear(i);
  6101.             } else {
  6102.                 selected.set(i);
  6103.             }
  6104.         }
  6105.  
  6106.         selectionMade = true;
  6107.         if (autoRedraw) { redrawAsync(); }
  6108.     }
  6109.  
  6110.     /**
  6111.      * Either clears all cell selections or selects all cells.
  6112.      */
  6113.     public /*synchronized*/ void toggleAll() {
  6114.         if (selected.get(0)) {
  6115.             //clear all bits
  6116.             clearAllSelections();
  6117.         } else {
  6118.             //set all of them
  6119.             int total = selected.size();
  6120.             for (int i=0; i<total; i++) {
  6121.                 selected.set(i);
  6122.             }
  6123.             selectionMade = true;
  6124.         }
  6125.  
  6126.         if (autoRedraw) { redrawAsync(); }
  6127.     }
  6128.  
  6129.     /**
  6130.      * Unselects all cells.
  6131.      */
  6132.     public /*synchronized*/ void clearAllSelections() {
  6133.         if (selectionMade) {
  6134.             selectionBase = null;
  6135.             selectionLimit = null;
  6136.             selectionMade = false;
  6137.             selected.xor(selected);
  6138.             if (autoRedraw) { redrawAsync();; }
  6139.         }
  6140.     }
  6141.  
  6142.     /**
  6143.      * Sets the cell by which range selections are performed
  6144.      */
  6145.     public void setSelectionBase(int row, int col) {
  6146.         selectionBase = new Coordinate(row, col);
  6147.     }
  6148.  
  6149.     /**
  6150.      * Determines whether a selection base cell has been set.
  6151.      */
  6152.     public boolean isSelectionBaseSet() {
  6153.         return selectionBase != null;
  6154.     }
  6155.  
  6156.     /**
  6157.      * Determines if a range of cells are currently selected.
  6158.      */
  6159.     public boolean isRangeSelected() {
  6160.         return selectionLimit != null;
  6161.     }
  6162.  
  6163.     //need to provide for erasing values in cells then make public
  6164.     void eraseRangeSelection() {
  6165.         //need to turn autoRedraw off while doing this
  6166.         setRange(false);
  6167.     }
  6168.  
  6169.     /*synchronized*/ void setRange(boolean setTo) {
  6170.         //if value == true then set bits o.w. clear bits
  6171.         if (selectionBase == null) { return; }
  6172.  
  6173.         if (selectionLimit == null) {
  6174.             selectionLimit = selectionBase;
  6175.         }
  6176.  
  6177.         int topRow = Math.min(selectionBase.row, selectionLimit.row);
  6178.         int topCol = Math.min(selectionBase.col, selectionLimit.col);
  6179.         int bottomRow =  Math.max(selectionBase.row, selectionLimit.row);
  6180.         int bottomCol =  Math.max(selectionBase.col, selectionLimit.col);
  6181.  
  6182.         //need to turn autoRedraw off while doing this
  6183.         boolean auto = autoRedraw;
  6184.         autoRedraw = false;
  6185.  
  6186.         //check for two rows defining range
  6187.         if (selectionBase.col == 0 && selectionLimit.col ==0) {
  6188.             //two row selections made - this is easy case
  6189.             for (int row=topRow; row<=bottomRow; row++) {
  6190.                 setRow(row, setTo);
  6191.             }
  6192.         }
  6193.  
  6194.         autoRedraw = auto;
  6195.         if (autoRedraw) { redrawAsync();; }
  6196.     }
  6197.  
  6198.     /**
  6199.      * Clears all selections
  6200.      */
  6201.     public void clearRangeSelection() {
  6202.         eraseRangeSelection();
  6203.         selectionBase = null;
  6204.         selectionLimit = null;
  6205.     }
  6206.  
  6207.     /**
  6208.      * Selects the range that spans from the currently selected base cell to
  6209.      * the specified row and column.
  6210.      */
  6211.     public /*synchronized*/ void selectRange(int limitRow, int limitCol) {
  6212.         //if no base, then we do not select any rows
  6213.         if (selectionBase == null) {
  6214.             selectionBase = new Coordinate(limitRow, limitCol);
  6215.         }
  6216.  
  6217.         boolean auto = autoRedraw;
  6218.         autoRedraw = false;
  6219.  
  6220.         //erase old range and draw new one
  6221.         eraseRangeSelection();
  6222.  
  6223.         selectionLimit = new Coordinate(limitRow, limitCol);
  6224.         setRange(true);
  6225.  
  6226.         autoRedraw = auto;
  6227.         if (autoRedraw) { redrawAsync();; }
  6228.     }
  6229.  
  6230.     /**
  6231.      * Selects a range of cells and sets the base for future selections
  6232.      */
  6233.     public void selectRange(int baseRow, int baseCol, int limitRow, int limitCol) {
  6234.         //if previous selection erase
  6235.         clearRangeSelection();
  6236.  
  6237.         //create a new range base
  6238.         selectionBase = new Coordinate(baseRow, baseCol);
  6239.         selectRange(limitRow, limitCol);
  6240.  
  6241.     }
  6242.  
  6243.     final void toggleBit(int bit) {
  6244.         selectionMade = true;
  6245.         if (selected.get(bit)) {
  6246.             selected.clear(bit);
  6247.         } else {
  6248.             selected.set(bit);
  6249.         }
  6250.     }
  6251.  
  6252.     //1 relative
  6253.     final int tx4Sxn(int row, int col) {
  6254.         return tx4Sxn(row) + col;
  6255.     }
  6256.  
  6257.     //1 relative
  6258.     final int tx4Sxn(int row) {
  6259.         int cols = cols();
  6260.  
  6261.         return (cols+1) * (row);
  6262.     }
  6263.  
  6264.     final int sxnRows(int cols) {
  6265.         return (int)Math.ceil(selected.size() / (cols + 1f));
  6266.     }
  6267.  
  6268.  
  6269.     private boolean m_HasAppendButton = false;
  6270.     public boolean getHasAppendButton() {
  6271.         return m_HasAppendButton;
  6272.     }
  6273.  
  6274.     private boolean m_HasInsertButton = false;
  6275.     public boolean getHasInsertButton() {
  6276.         return m_HasInsertButton;
  6277.     }
  6278.  
  6279.     private boolean m_HasGotoButton = false;
  6280.     public boolean getHasGotoButton() {
  6281.         return m_HasGotoButton;
  6282.     }
  6283.  
  6284.     private boolean m_HasUndoButton = false;
  6285.     public boolean getHasUndoButton() {
  6286.         return m_HasUndoButton;
  6287.     }
  6288.  
  6289.     private boolean m_HasRestartButton = false;
  6290.     public boolean getHasRestartButton() {
  6291.         return m_HasRestartButton;
  6292.     }
  6293.  
  6294.     private boolean m_HasDeleteButton = false;
  6295.     public boolean getHasDeleteButton() {
  6296.         return m_HasDeleteButton;
  6297.     }
  6298.  
  6299.     private boolean m_HasUndeleteButton = false;
  6300.     public boolean getHasUndeleteButton() {
  6301.         return m_HasUndeleteButton;
  6302.     }
  6303.  
  6304.     private boolean m_HasSaveButton = false;
  6305.     public boolean getHasSaveButton() {
  6306.         return m_HasSaveButton;
  6307.     }
  6308.  
  6309.  
  6310.  
  6311. }
  6312.  
  6313.  
  6314.  
  6315.