/*******************************************************************************
 * This file is part of GECAMed.
 * 
 * GECAMed is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License (L-GPL) as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 * 
 * GECAMed is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License for more details.
 * 
 * You should have received a copy of the GNU Lesser General Public License (L-GPL)
 * along with GECAMed.  If not, see <http://www.gnu.org/licenses/>.
 * 
 * GECAMed is Copyrighted by the Centre de Recherche Public Henri Tudor (http://www.tudor.lu)
 * (c) CRP Henri Tudor, Luxembourg, 2008
 *******************************************************************************/
package lu.tudor.santec.gecamed.core.gui.utils;

import java.awt.Container;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.FocusEvent;
import java.awt.event.FocusListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;

import javax.swing.JFrame;
import javax.swing.JTable;
import javax.swing.JTextField;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.TableColumnModelEvent;
import javax.swing.event.TableColumnModelListener;
import javax.swing.table.JTableHeader;
import javax.swing.table.TableColumnModel;

public class EditableHeaderSupport extends MouseAdapter 
       implements TableColumnModelListener, FocusListener, ActionListener
{
       private JTableHeader        tableHeader;
       private JTextField          editingComponent;
       private TableColumnModel    columnModel;
       private int                 editingColumn = -1;
       
       public EditableHeaderSupport(JTable tbl) {
           // Table Header need to detect double clicks
           tableHeader = tbl.getTableHeader();
           tableHeader.addMouseListener(this);
           
           // Need to know if column events occur
           columnModel = tbl.getColumnModel(); 
           columnModel.addColumnModelListener(this);
           
           // Need to know when the JTextField finishes editing
           editingComponent = new JTextField();  
           editingComponent.addActionListener(this); 

           // Need to know when the JTextField loses focus
           editingComponent.addFocusListener(this);
       } 

       public void focusGained(FocusEvent e) { }
       
       /* If focus goes somewhere, we are done */
       public void focusLost(FocusEvent e) {
           endEditing();
       }
       
       /* When the the JTextField content is changed it fires this event */
       public void actionPerformed(ActionEvent ae) {
           endEditing();
       } 

       /* Any column event need to end editing, things get ugly if header of
          column being edited is moved or resized */
       
       public void columnAdded(TableColumnModelEvent e) {
           endEditing();
       }

       public void columnMarginChanged(ChangeEvent e) {
           endEditing();
       }

       public void columnMoved(TableColumnModelEvent e) {
           endEditing();
       }

       public void columnRemoved(TableColumnModelEvent e) {
           endEditing();
       }
       
       /* One column event, that we don't need to edit editing over*/    
       public void columnSelectionChanged(ListSelectionEvent e) { }
       
       public void mouseClicked(MouseEvent me) {
           // If this is a double click... 
           if (me.getClickCount() == 2) {
               int col = tableHeader.columnAtPoint(me.getPoint());
               // ... see if it's in the header, if so...
               if (col != -1) {
                   editingColumn = col; 
                   // ... add JTextField to the header ...
                   tableHeader.add(editingComponent);
                   // ... grab the text value from the header ...
                   editingComponent.setText(
                       (String) columnModel.getColumn(col).getHeaderValue()
                   );
                   // ... resize the JTextField to overlay the Header column
                   editingComponent.setBounds(tableHeader.getHeaderRect(col));
                   editingComponent.requestFocus();
               }
           }
       } 
       
       public void endEditing() {
            // If where are done editing, make sure we really editing...
            if (editingColumn != -1) {
               // ... Set the Header value to the value of the JTextField ...
               columnModel.getColumn(editingColumn).setHeaderValue(editingComponent.getText());
               // ... remove the JTextField and refesh header column area ...
               tableHeader.remove(editingComponent);
               tableHeader.repaint(tableHeader.getHeaderRect(editingColumn)); 
               editingColumn = -1;
            } 
       }

       /* Main method to implement demostration invokabe as an application */

       public static void main(String[] arg) {
           Object[][] data = {
            { "A", "1", "C" },
            { " ", "2", "D" },
            { "B", "3", " " },
            { "B", "4", "D" },
            { "A", "5", "C" },
            { " ", "6", "C" },
            { "A", "7", " " },
            { " ", "8", " " },
            { "B", "9", "D" },
            { "B", "10", "E" }
           };
           Object[] cols = { "ONE", "TWO", "THREE" };
           JTable tbl = new JTable(data, cols);             
           
           new EditableHeaderSupport(tbl);
           
           JFrame frm = new JFrame("EditableHeaderSupport"); 
           frm.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
           Container me = frm.getContentPane();
           me.setLayout(new java.awt.BorderLayout());
           me.add(new javax.swing.JScrollPane(tbl));
           frm.pack();
           frm.setVisible(true); 
       }
}
