import java.awt.*;
import java.awt.event.*;
import javax.swing.JTable;
import javax.swing.table.AbstractTableModel;
import javax.swing.DefaultCellEditor;
import javax.swing.table.TableCellRenderer;
import javax.swing.JLabel;
import javax.swing.JDialog;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JColorChooser;
import javax.swing.BorderFactory;
import javax.swing.border.Border;
import javax.swing.JScrollPane;
import javax.swing.JFrame;
import javax.swing.SwingUtilities;

/**
 * This is like TableEditDemo, except that it substitutes a
 * Favorite Color column for the Last Name column and specifies
 * a custom cell renderer and editor for the color data.
 */


public class TableDialogEditDemo extends JFrame 
{
 private boolean DEBUG = false;
 public TableDialogEditDemo( )
     {
     super("TableDialogEditDemo");
     MyTableModel myModel = new MyTableModel( );
     JTable table = new JTable(myModel);
     table.setPreferredScrollableViewportSize(new Dimension(500, 70));

     //Create the scroll pane and add the table to it. 
     JScrollPane scrollPane = new JScrollPane(table);

     //Set up renderer and editor for the Favorite Color column.
     setUpColorRenderer(table);
     setUpColorEditor(table);

     //Set up real input validation for integer data.
     setUpIntegerEditor(table);

     //Add the scroll pane to this window.
     getContentPane( ).add(scrollPane, BorderLayout.CENTER);

     addWindowListener(new WindowAdapter( ) 
	{
      public void windowClosing(WindowEvent e) 
	   { System.exit(0); }
      });
     }

     class ColorRenderer extends JLabel
                        implements TableCellRenderer 
	  {
        Border unselectedBorder = null;
        Border selectedBorder = null;
        boolean isBordered = true;

        public ColorRenderer(boolean isBordered) 
		{
            super( );
            this.isBordered = isBordered;
            setOpaque(true);     
		//MUST do this for background to show up.
            }

        public Component getTableCellRendererComponent(
               JTable table, Object color, 
               boolean isSelected, boolean hasFocus,
               int row, int column) 
		   {
		   setBackground((Color)color);
		   if (isBordered)
  	           {
		     if (isSelected) 
			 {
			 if (selectedBorder == null) 
			   {
                     selectedBorder = BorderFactory.createMatteBorder(2,5,2,5,
                                               table.getSelectionBackground( ));
                     }
                   setBorder(selectedBorder);
                	 }
		     else
			{
                  if (unselectedBorder == null)
			  {
                    unselectedBorder = BorderFactory.createMatteBorder(2,5,2,5,
                                                  table.getBackground( ));
                    }
                  setBorder(unselectedBorder);
                  }
                 }
               return this;
               }
     }

     private void setUpColorRenderer(JTable table) 
	  {
        table.setDefaultRenderer(Color.class,
                                 new ColorRenderer(true));
        }

    //Set up the editor for the Color cells.
     private void setUpColorEditor(JTable table) 
	  {
        //First, set up the button that brings up the dialog.
        final JButton button = new JButton("") 	
		{
            public void setText(String s) 
		{ /*Button never shows text -- only color.*/ }
        };
        button.setBackground(Color.blue);
        button.setBorderPainted(false);
        button.setMargin(new Insets(0,0,0,0));

        //Now create an editor to encapsulate the button, and
        //set it up as the editor for all Color cells.
        final ColorEditor colorEditor = new ColorEditor(button);
        table.setDefaultEditor(Color.class, colorEditor);

        //Set up the dialog that the button brings up.
        final JColorChooser colorChooser = new JColorChooser();
        ActionListener okListener = new ActionListener( )
		{
            public void actionPerformed(ActionEvent e) 
		    {
                colorEditor.currentColor = colorChooser.getColor();
                } 
            };
        final JDialog dialog = JColorChooser.createDialog(button,
                                        "Pick a Color",
                                        true,
                                        colorChooser,
                                        okListener,
                                        null); 

        //Here's the code that brings up the dialog.
        button.addActionListener(new ActionListener( )
		{
            public void actionPerformed(ActionEvent e) 
		    {
                button.setBackground(colorEditor.currentColor);
                colorChooser.setColor(colorEditor.currentColor);
                //Without the following line, the dialog comes up
                //in the middle of the screen.
                //dialog.setLocationRelativeTo(button);
                dialog.show();
                }
            });
        }

    /*
     * The editor button that brings up the dialog.
     * We extend DefaultCellEditor for convenience,
     * even though it mean we have to create a dummy
     * check box.  Another approach would be to copy
     * the implementation of TableCellEditor methods
     * from the source code for DefaultCellEditor.
     */

    class ColorEditor extends DefaultCellEditor 
	  {
        Color currentColor = null;
        public ColorEditor(JButton b) 
		{
            super(new JCheckBox()); //Unfortunately, the constructor
                                    //expects a check box, combo box,
                                    //or text field.
            editorComponent = b;
            setClickCountToStart(2); //This is usually 1 or 2.

            //Must do this so that editing stops when appropriate.
            b.addActionListener(new ActionListener( ) 
		    {
                public void actionPerformed(ActionEvent e) 	
			{ fireEditingStopped( ); }
                });
            }

        protected void fireEditingStopped( ) 
	  { super.fireEditingStopped( ); }

        public Object getCellEditorValue( )
	  { return currentColor; }

        public Component getTableCellEditorComponent(JTable table, 
                                                     Object value,
                                                     boolean isSelected,
                                                     int row,
                                                     int column) 
				{
                        ((JButton)editorComponent).setText(value.toString( ));
                        currentColor = (Color)value;
                        return editorComponent;
                        }
         }

    private void setUpIntegerEditor(JTable table) 
	  {
        //Set up the editor for the integer cells.
        final WholeNumberField integerField = new WholeNumberField(0, 5);
        integerField.setHorizontalAlignment(WholeNumberField.RIGHT);

        DefaultCellEditor integerEditor = 
            new DefaultCellEditor(integerField) 
		   {
               //Override DefaultCellEditor's getCellEditorValue method
               //to return an Integer, not a String:
               public Object getCellEditorValue( )
			 {
                   return new Integer(integerField.getValue());
                   }
               };
        table.setDefaultEditor(Integer.class, integerEditor);
        }


    class MyTableModel extends AbstractTableModel 
	  {
        final String[] columnNames = {"First Name", 
                                      "Favorite Color",
                                      "Sport",
                                      "# of Years",
                                      "Vegetarian"};
        final Object[][] data = 
		{
            {"Mary", new Color(153, 0, 153),
             "Snowboarding", new Integer(5), new Boolean(false)},
            {"Alison", new Color(51, 51, 153),
             "Rowing", new Integer(3), new Boolean(true)},
            {"Kathy", new Color(51, 102, 51),
             "Chasing toddlers", new Integer(2), new Boolean(false)},
            {"Mark", Color.blue,
             "Speed reading", new Integer(20), new Boolean(true)},
            {"Philip", Color.pink,
             "Pool", new Integer(7), new Boolean(false)}
        };

        public int getColumnCount( ) 
	   { return columnNames.length; }
        
        public int getRowCount( )
	   { return data.length; }

        public String getColumnName(int col) 
	   { return columnNames[col]; }

        public Object getValueAt(int row, int col) 
	   { return data[row][col]; }

        /* JTable uses this method to determine the default renderer/
         * editor for each cell.  If we didn't implement this method,
         * then the last column would contain text ("true"/"false"),
         * rather than a check box.
         */
        public Class getColumnClass(int c) 
	   { return getValueAt(0, c).getClass(); }

        /* Don't need to implement this method unless your table's
         * editable.
         */

        public boolean isCellEditable(int row, int col) 
		{
            //Note that the data/cell address is constant,
            //no matter where the cell appears onscreen.
            if (col < 1) 
		  { return false; }
		else 
		  { return true;  }
            }

        public void setValueAt(Object value, int row, int col) 
		{
            if (DEBUG) 
		    {
                System.out.println("Setting value at " + row + "," + col
                                   + " to " + value
                                   + " (an instance of " 
                                   + value.getClass() + ")");
                }

            data[row][col] = value;
            fireTableCellUpdated(row, col);
            if (DEBUG) 
		    {
                System.out.println("New value of data:");
                printDebugData();
                }
            }

        private void printDebugData( )
		{
            int numRows = getRowCount();
            int numCols = getColumnCount();
            for (int i=0; i < numRows; i++) 
		    {
                System.out.print("    row " + i + ":");
                for (int j=0; j < numCols; j++) 
			{
		      System.out.print("  " + data[i][j]);
                  }
                System.out.println( );
            }
            System.out.println("--------------------------");
        }
    }

    public static void main(String[] args) 
	  {
        TableDialogEditDemo frame = new TableDialogEditDemo();
        frame.pack( );
        frame.setVisible(true);
        }
}

