/*
 * Copyright 
 *   2005 axYus - www.axyus.com
 *   2005 C.Marchand - christophe.marchand@axyus.com
 * 
 * This file is part of XEMELIOS.
 * 
 * XEMELIOS is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 * 
 * XEMELIOS 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 General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with XEMELIOS; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */
package fr.gouv.finances.cp.xemelios.ui.export;

import java.awt.Component;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.util.Vector;

import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.JCheckBox;
import javax.swing.JComponent;
import javax.swing.JDialog;
import javax.swing.JLabel;
import javax.swing.JRootPane;
import javax.swing.JTable;
import javax.swing.KeyStroke;
import javax.swing.event.TreeExpansionEvent;
import javax.swing.event.TreeExpansionListener;
import javax.swing.table.DefaultTableCellRenderer;
import javax.swing.table.TableCellRenderer;
import javax.swing.table.TableModel;

import org.apache.log4j.Logger;
import org.jdesktop.swingx.JXTreeTable;
import org.jdesktop.swingx.treetable.DefaultTreeTableModel;

import fr.gouv.finances.cp.utils.xml.marshal.XmlOutputter;
import fr.gouv.finances.cp.xemelios.common.config.ChampModel;
import fr.gouv.finances.cp.xemelios.common.config.DocumentModel;
import fr.gouv.finances.cp.xemelios.common.config.ElementModel;
import fr.gouv.finances.cp.xemelios.common.config.EtatModel;
import fr.gouv.finances.cp.xemelios.data.DataLayerManager;
import fr.gouv.finances.cp.xemelios.export.ConfigModel;
import fr.gouv.finances.cp.xemelios.export.ConfigParser;
import fr.gouv.finances.cp.xemelios.export.ExportChampModel;
import fr.gouv.finances.cp.xemelios.export.ExportElementModel;
import fr.gouv.finances.cp.xemelios.export.ExportModel;
import fr.gouv.finances.cp.xemelios.ui.MainWindow;

/**
 *
 * @author  nicolas.lecorre
 */
public class EditConfig extends JDialog {
	private static final long serialVersionUID = 5669669876743219771L;
	private static Logger logger = Logger.getLogger(EditConfig.class);
	
	private DocumentModel dm;
	private ConfigModel cm;
	private String docID, etatID;
	// la structure contenant la configuration
	private ExportModel data = new ExportModel(ExportModel.QN);
	// la structure contenant la configuration à modifier
	private ExportModel dataToBeModified = null;
    
    /** Creates new form EditConfig */
    public EditConfig(JDialog parent, DocumentModel d, ConfigModel c) {
    	super (parent);
    	this.dm = d;
    	docID = dm.getId();
    	this.cm = c;
    	etatID = cm.getEtatID();
    	try {
    		ConfigParser cp = new ConfigParser();
    		cp.parse(new ByteArrayInputStream (c.getConfigLines()));
    		dataToBeModified = (ExportModel)cp.getMarshallable();
    	} catch (Exception e) {
    		logger.error("Erreur lors de la lecture de la configuration à modifier", e);
    	}
        initComponents();
        tCode.setText(c.getCode());
        tLibelle.setText(c.getLibelle());
        setLocationRelativeTo(getParent());
        treeTable.setTreeTableModel(createModel (dm, cm.getEtatID()));
        updateModel();
        treeTable.addTreeExpansionListener(new TreeExpansionListener() {
        	public void treeCollapsed(TreeExpansionEvent event) {
            }
            public void treeExpanded(TreeExpansionEvent event) {
                treeTable.packAll();
            }
        });
        treeTable.getColumnModel().getColumn(1).setMaxWidth(25);
        treeTable.expandAll();
    }

    public EditConfig(JDialog parent, DocumentModel d, String etatID) {
    	super (parent);
    	this.dm = d;
    	docID = dm.getId();
    	this.etatID = etatID;
        initComponents();
        setLocationRelativeTo(getParent());
        treeTable.setTreeTableModel(createModel (dm, etatID));
        treeTable.addTreeExpansionListener(new TreeExpansionListener() {
        	public void treeCollapsed(TreeExpansionEvent event) {
            }
            public void treeExpanded(TreeExpansionEvent event) {
                treeTable.packAll();
            }
        });
        treeTable.getColumnModel().getColumn(1).setMaxWidth(25);
        treeTable.expandAll();
    }
    
    /**
     * Merge le model créé à partir du fichier métier Xemelios et de la configuration que l'on tente de modifier
     */
    private void updateModel () {
    	if (dataToBeModified!=null) {
	    	for (ExportElementModel eemDest:data.getEnfants()) {
	    		String eID = eemDest.getId();
	    		for (ExportElementModel eemRef:dataToBeModified.getEnfants()) {
	    			if (eemRef.getId().equals(eID)) {
	    				updateEEM (eemRef, eemDest);
	    			}
	    		}
	    	}
    	}
    }
    
    private void updateEEM (ExportElementModel reference, ExportElementModel destination) {
    	for (ExportChampModel ecmDest:destination.getChamps()) {
    		String cID = ecmDest.getId();
    		for (ExportChampModel ecmRef:reference.getChamps()) {
    			if (ecmRef.getId().equals(cID)) {
    				ecmDest.setSelectionne(ecmRef.isSelectionne());
    			}
    		}
    	}
    	for (ExportElementModel eemDest:destination.getEnfants()) {
    		String eID = eemDest.getId();
    		for (ExportElementModel eemRef:reference.getEnfants()) {
    			if (eemRef.getId().equals(eID)) {
    				updateEEM (eemRef, eemDest);
    			}
    		}
    	}
    }

    private ConfigTreeTableModel createModel (DocumentModel dm, String etatID) {
    	ConfigTreeTableModel ret = new ConfigTreeTableModel(data);
    	EtatModel em = dm.getEtatById(etatID);
    	ElementModel emROOT = null;
    	for (String k:em.getElements().keySet()) {
    		ElementModel tmp = em.getElements().get(k);
    		if (tmp.getSimpleParent()==null) {
    			emROOT = tmp;
    			break;
    		}
    	}
    	// maintenant, on dispose de l'élément ROOT pour notre arbre
    	if (emROOT != null) {
    		try  {
	    		ExportModel exm = new ExportModel (ExportModel.QN);
	    		exm.setId((cm!=null?cm.getId():""));
	    		exm.setCode((cm!=null?cm.getCode():""));
	    		exm.setLibelle((cm!=null?cm.getLibelle():""));
	    		// les champs de l'élément ROOT
	    		ExportElementModel eem = buildEEM (emROOT, null);
	    		if (emROOT.getEnfant()!=null) {
		    		eem.setEnfants(readChildren(emROOT, em, eem));
		    		// les fils
	    		}
		    	exm.addEnfant(eem);
	    		data = exm;
	    		ret.setData(exm);
    		} catch (Exception e) {
    			logger.error ("Erreur lors de la lecture de la définition de la configuration",e);
    		}
    	} else {
    		logger.error("Impossible de trouver l'élément ROOT");
    	}
    	
    	return ret;
    }
    
    private Vector<ExportElementModel> readChildren (ElementModel p, EtatModel em, ExportElementModel parent) throws Exception {
    	Vector<ExportElementModel> ret = new Vector<ExportElementModel>();
    	for (String k:p.getEnfant().getEnfants().keySet()) {
    		ElementModel child = em.getElementById(k);
    		ExportElementModel eem = buildEEM(child, parent); 
    		if (child.getEnfant()!=null && child.getEnfant().getEnfants().size()>0) {
    			eem.setEnfants(readChildren(child, em, eem));
    		}
    		ret.add(eem);
    	}
    	return ret;
    }
    
    private ExportElementModel buildEEM (ElementModel em, ExportElementModel parent) throws Exception {
    	ExportElementModel ret = new ExportElementModel(ExportElementModel.QN);
		ret.setId(em.getId());
		ret.setLibelle(em.getTitre());
		ret.setParent(parent);
		
		// l'éventuel ExportElementModel présente dans la config correspondant
		ExportElementModel eemRef = null;
		if (dataToBeModified!=null) {
			eemRef = findCorrespondingEEM (ret, dataToBeModified.getEnfants());
		}
		
		// champs de l'élément ROOT
		for (ChampModel tmpC:em.getListeResultat().getListeChamps()) {
			if (tmpC.isExportable()) {
				ExportChampModel ecm = new ExportChampModel (ExportChampModel.QN);
				ecm.setId(tmpC.getId());
				ecm.setLibelle(tmpC.getLibelle());
				ecm.setEditable(!tmpC.isIdentifiant());
				ecm.setIdentifiant(tmpC.isIdentifiant());
				//TODO
				if (eemRef!=null) {
					ExportChampModel ecmRef = findCorrespondingECM (ecm, eemRef);
					if (ecmRef!=null) {
						ecm.setSelectionne (ecmRef.isSelectionne());
					} else {
						ecm.setSelectionne(false);
					}
				} else {
					ecm.setSelectionne(false);
				}
				ret.addChamp(ecm);
			}
		}  
		return ret;
    }
    
    private ExportChampModel findCorrespondingECM (ExportChampModel ecm, ExportElementModel eem) {
    	for (ExportChampModel e:eem.getChamps()) {
    		if (e.getId().equals(ecm.getId())) return ecm;
    	}
    	return null;
    }
    
    private ExportElementModel findCorrespondingEEM (ExportElementModel eem, Vector<ExportElementModel>liste) {
    	ExportElementModel ret = null;
    	for (ExportElementModel e:liste) {
    		if (e.getId().equals(eem.getId())) {
    			ret = e;
	    		break;
	    	} else if (e.getEnfants().size()>0){
	    		ret = findCorrespondingEEM (eem, e.getEnfants());
	    		if (ret != null) break;
	    	}
    	}
    	return ret;
    }
    
    /** This method is called from within the constructor to
     * initialize the form.
     * WARNING: Do NOT modify this code. The content of this method is
     * always regenerated by the Form Editor.
     */
    // <editor-fold defaultstate="collapsed" desc=" Generated Code ">//GEN-BEGIN:initComponents
    private void initComponents() {
        jPanel1 = new javax.swing.JPanel();
        jLabel1 = new javax.swing.JLabel();
        jLabel2 = new javax.swing.JLabel();
        tCode = new javax.swing.JTextField();
        tLibelle = new javax.swing.JTextField();
        jPanel2 = new javax.swing.JPanel();
        bSelectNone = new javax.swing.JButton();
        bSelectAll = new javax.swing.JButton();
        liste = new javax.swing.JScrollPane();
        treeTable = new JXTreeTablePropertyEditor();
        bEnregistrer = new javax.swing.JButton();
        bAnnuler = new javax.swing.JButton();
        
        treeTable.setRootVisible(true);
        treeTable.setShowHorizontalLines(true);

        setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
        jPanel1.setBorder(javax.swing.BorderFactory.createTitledBorder("Identification"));
        jLabel1.setText("Code");

        jLabel2.setText("Libell\u00e9");

        org.jdesktop.layout.GroupLayout jPanel1Layout = new org.jdesktop.layout.GroupLayout(jPanel1);
        jPanel1.setLayout(jPanel1Layout);
        jPanel1Layout.setHorizontalGroup(
            jPanel1Layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
            .add(jPanel1Layout.createSequentialGroup()
                .addContainerGap()
                .add(jPanel1Layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
                    .add(jLabel1)
                    .add(jLabel2))
                .add(26, 26, 26)
                .add(jPanel1Layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
                    .add(tLibelle, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, 531, Short.MAX_VALUE)
                    .add(tCode, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, 531, Short.MAX_VALUE))
                .addContainerGap())
        );
        jPanel1Layout.setVerticalGroup(
            jPanel1Layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
            .add(jPanel1Layout.createSequentialGroup()
                .add(jPanel1Layout.createParallelGroup(org.jdesktop.layout.GroupLayout.BASELINE)
                    .add(jLabel1)
                    .add(tCode, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE))
                .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
                .add(jPanel1Layout.createParallelGroup(org.jdesktop.layout.GroupLayout.BASELINE)
                    .add(tLibelle, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)
                    .add(jLabel2))
                .addContainerGap(org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
        );

        jPanel2.setBorder(javax.swing.BorderFactory.createTitledBorder("Configuration"));
        bSelectNone.setText("Tout d\u00e9s\u00e9lectionner");
        bSelectNone.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                bSelectNoneActionPerformed(evt);
            }
        });

        bSelectAll.setText("Tout s\u00e9lectionner");
        bSelectAll.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                bSelectAllActionPerformed(evt);
            }
        });

        treeTable.setAutoResizeMode(javax.swing.JTable.AUTO_RESIZE_LAST_COLUMN);
        liste.setViewportView(treeTable);

        org.jdesktop.layout.GroupLayout jPanel2Layout = new org.jdesktop.layout.GroupLayout(jPanel2);
        jPanel2.setLayout(jPanel2Layout);
        jPanel2Layout.setHorizontalGroup(
            jPanel2Layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
            .add(org.jdesktop.layout.GroupLayout.TRAILING, jPanel2Layout.createSequentialGroup()
                .addContainerGap(358, Short.MAX_VALUE)
                .add(bSelectAll)
                .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
                .add(bSelectNone))
            .add(jPanel2Layout.createSequentialGroup()
                .add(liste, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, 596, Short.MAX_VALUE)
                .addContainerGap())
        );
        jPanel2Layout.setVerticalGroup(
            jPanel2Layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
            .add(jPanel2Layout.createSequentialGroup()
                .add(jPanel2Layout.createParallelGroup(org.jdesktop.layout.GroupLayout.BASELINE)
                    .add(bSelectNone)
                    .add(bSelectAll))
                .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED, 12, Short.MAX_VALUE)
                .add(liste, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)
                .addContainerGap())
        );

        bEnregistrer.setText("Enregistrer");
        bEnregistrer.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                bEnregistrerActionPerformed(evt);
            }
        });

        bAnnuler.setText("Annuler");
        bAnnuler.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                bAnnulerActionPerformed(evt);
            }
        });

        org.jdesktop.layout.GroupLayout layout = new org.jdesktop.layout.GroupLayout(getContentPane());
        getContentPane().setLayout(layout);
        layout.setHorizontalGroup(
            layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
            .add(layout.createSequentialGroup()
                .addContainerGap()
                .add(layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
                    .add(jPanel2, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                    .add(jPanel1, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                    .add(org.jdesktop.layout.GroupLayout.TRAILING, layout.createSequentialGroup()
                        .add(bAnnuler)
                        .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
                        .add(bEnregistrer)))
                .addContainerGap())
        );
        layout.setVerticalGroup(
            layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
            .add(layout.createSequentialGroup()
                .add(jPanel1, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)
                .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
                .add(jPanel2, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)
                .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                .add(layout.createParallelGroup(org.jdesktop.layout.GroupLayout.BASELINE)
                    .add(bEnregistrer)
                    .add(bAnnuler))
                .addContainerGap())
        );
        setDefaultCloseOperation(DISPOSE_ON_CLOSE);
        pack();
		setLocationRelativeTo(getParent());
        setVisible(true);
        setTitle("Configuration d'un export");
    }// </editor-fold>//GEN-END:initComponents

    private void bEnregistrerActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_bEnregistrerActionPerformed
    	if (cm == null) {
    		try {
	    		cm = new ConfigModel ();
	    		cm.setCode(tCode.getText());
	    		cm.setLibelle(tLibelle.getText());
                        data.setId(cm.getCode());
                        data.setLibelle(cm.getLibelle());
	    		cm.setDocID(docID);
	    		cm.setEtatID(etatID);
	    		cm.setOwner(MainWindow.getInstance().getConnectedUser().getId());
	    		ensureKeysSelected();
	    		ByteArrayOutputStream sos = new ByteArrayOutputStream ();
	    		XmlOutputter xo = new XmlOutputter (sos);
	    		data.marshall(xo);
                        sos.flush();
	    		cm.setConfigLines(sos.toByteArray());
	    		DataLayerManager.getImplementation().insertConfigExport(cm);
	    		((DlgSearchConfig)getParent()).bRechercherActionPerformed(null);
    		} catch (Exception e) {
    			logger.error("Erreur lors de la sauvegarde de la configuration", e);
    		}
    	} else {
    		try {
	    		cm.setCode(tCode.getText());
	    		cm.setLibelle(tLibelle.getText());
                        data.setId(cm.getCode());
                        data.setLibelle(cm.getLibelle());
	    		cm.setDocID(docID);
	    		cm.setEtatID(etatID);
	    		ensureKeysSelected();
	    		ByteArrayOutputStream sos = new ByteArrayOutputStream ();
	    		XmlOutputter xo = new XmlOutputter (sos);
	    		data.marshall(xo);
                        sos.flush();
	    		cm.setConfigLines(sos.toByteArray());
	    		DataLayerManager.getImplementation().updateConfigExport(cm);
	    		((DlgSearchConfig)getParent()).bRechercherActionPerformed(null);
    		} catch (Exception e) {
    			logger.error("Erreur lors de la sauvegarde de la configuration", e);
    		}    		
    	}
    	
    	this.dispose();

    }//GEN-LAST:event_bEnregistrerActionPerformed
    
    /**
     * Assure que pour chaque niveau, si un champs est sélectionné, les éléments formant la clef de ce niveau le sont aussi.
     * Assure aussi que si un champs est sélectionné pour un niveau, les clefs des niveaux parents le sont aussi.
     */
    private void ensureKeysSelected () {
    	// la liste des éléments dont il faut sélectionner la clef
    	Vector<ExportElementModel> toSelect = new Vector<ExportElementModel> ();
    	for (ExportElementModel ecm:data.getEnfants()) {
    		browseChildrenToSelect(ecm, toSelect);
    	}
    	
    	// sélection de la clef de chaque élément identifié
    	for (ExportElementModel e:toSelect) {
    		e.selectChampsKey();
    		e.selectParentChampsKey();
    	}    	
    }
    private void browseChildrenToSelect (ExportElementModel parent, Vector<ExportElementModel> toSelect) {
    	if (parent.hasChampSelected()) toSelect.add(parent);
    	
    	for (ExportElementModel ecm:parent.getEnfants()) {
    		browseChildrenToSelect(ecm, toSelect);
    	}
    }
    
    private void bAnnulerActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_bAnnulerActionPerformed
    	this.dispose();
    }//GEN-LAST:event_bAnnulerActionPerformed

    private void bSelectNoneActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_bSelectNoneActionPerformed
    	toggleAll(false);
    	treeTable.repaint();
    }//GEN-LAST:event_bSelectNoneActionPerformed

    private void bSelectAllActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_bSelectAllActionPerformed
    	toggleAll(true);
    	treeTable.repaint();
    }//GEN-LAST:event_bSelectAllActionPerformed
    
    /**
     * Change l'état sélectionné de toutes les feuilles de l'arbre
     * @param select true => sélectionne, false => désélectionne
     */
    private void toggleAll (boolean select) {
    	for (ExportElementModel eem:data.getEnfants()) {
    		toggle (eem, select);
    	}
    }
    private void toggle (ExportElementModel e, boolean select) {
    	for (ExportChampModel ecm:e.getChamps()) {
    		ecm.setSelectionne(select);
    	}
    	for (ExportElementModel eem:e.getEnfants()) {
    		toggle (eem, select);
    	}
    }
       
    // Variables declaration - do not modify//GEN-BEGIN:variables
    private javax.swing.JButton bAnnuler;
    private javax.swing.JButton bEnregistrer;
    private javax.swing.JButton bSelectAll;
    private javax.swing.JButton bSelectNone;
    private javax.swing.JLabel jLabel1;
    private javax.swing.JLabel jLabel2;
    private javax.swing.JPanel jPanel1;
    private javax.swing.JPanel jPanel2;
    private javax.swing.JScrollPane liste;
    private javax.swing.JTextField tCode;
    private javax.swing.JTextField tLibelle;
    private org.jdesktop.swingx.JXTreeTable treeTable;
    private Action escapeAction;
    // End of variables declaration//GEN-END:variables

    private static class JXTreeTablePropertyEditor extends JXTreeTable {
		private static final long serialVersionUID = -5756581514191559300L;
        private TableCellRenderer booleanRenderer, booleanDisabledRenderer, blankRenderer;
        public JXTreeTablePropertyEditor() {
            super();
            booleanRenderer = new DefaultTableCellRenderer() {
                private JCheckBox chk = new JCheckBox();
                public Component getTableCellRendererComponent(JTable table,Object value,boolean isSelected,boolean hasFocus,int row,int column) {
                    JLabel lbl = (JLabel)super.getTableCellRendererComponent(table,value,isSelected,hasFocus,row,column);
                    chk.setSelected(((Boolean)value).booleanValue());
                    chk.setBackground(lbl.getBackground());
                    chk.setBorder(lbl.getBorder());
                    return chk;
                }
            };
            booleanDisabledRenderer = new DefaultTableCellRenderer() {
                private JCheckBox chk = new JCheckBox();
                public Component getTableCellRendererComponent(JTable table,Object value,boolean isSelected,boolean hasFocus,int row,int column) {
                    JLabel lbl = (JLabel)super.getTableCellRendererComponent(table,value,isSelected,hasFocus,row,column);
                    chk.setSelected(((Boolean)value).booleanValue());
                    chk.setBackground(lbl.getBackground());
                    chk.setBorder(lbl.getBorder());
                    chk.setEnabled(false);
                    return chk;
                }
            };
            blankRenderer = new DefaultTableCellRenderer() {
                public Component getTableCellRendererComponent(JTable table,Object value,boolean isSelected,boolean hasFocus,int row,int column) {
                    JLabel lbl = (JLabel)super.getTableCellRendererComponent(table,value,isSelected,hasFocus,row,column);
                    lbl.setText("");
                    return lbl;
                }
            };
        }
        public TableCellRenderer getCellRenderer(int row, int column) {
            if(column==1 && getTreeTableModel() instanceof ConfigTreeTableModel)  {
            	ConfigTreeTableModel model = (ConfigTreeTableModel)getTreeTableModel();
                Object node = getPathForRow(row).getLastPathComponent();
                if(node instanceof ExportChampModel) {
//                	ExportChampModel ecm = (ExportChampModel)node;
//                    if(!ecm.isEditable()) {
//                   	return booleanDisabledRenderer;
//                    } else {
                        return booleanRenderer;
//                    }
                } else if (node instanceof ExportElementModel) {
                	return blankRenderer;
                }
                return super.getCellRenderer(row,column);
            } else {
                return super.getCellRenderer(row,column);
            }
        }
    }
    
    private static class ConfigTreeTableModel extends DefaultTreeTableModel {
    	private String[] columnNames = new String [] { "", "" };
    	private ExportModel _data;
    	
    	public ConfigTreeTableModel (ExportModel data) { _data = data; }

        public boolean isLeaf(Object node) {
        	if (node instanceof ExportElementModel) {
        		return (((ExportElementModel)node).getEnfants().size()==0 && ((ExportElementModel)node).getChamps().size()==0);
        	} else if (node instanceof ExportChampModel) {
        		return true;
        	} else {
        		return true;
        	}        	
        }

        public Class getColumnClass(int i) { 
        	if (i==0) return super.getColumnClass(i); 
        	else if (i==1) return Boolean.class;
        	else return super.getColumnClass(i);
        }

        public Object getValueAt(Object object, int i) {
        	if (object instanceof ExportElementModel) {
        		if (i==0) return ((ExportElementModel)object).getLibelle();
        		else if (i==1) return new Boolean(Boolean.FALSE);
        		else return "";
        	} else {
        		if (i==0) return ((ExportChampModel)object).getLibelle();
        		else if (i==1) return new Boolean (((ExportChampModel)object).isSelectionne());
        		else return "";
        	}
        }

        public void setValueAt(Object value, Object node, int column) {
            ExportChampModel ecm = (ExportChampModel)node;
            if (column==1) {
            	ecm.setSelectionne((Boolean)value);
            }
        }
        
        public int getChildCount(Object parent) {
        	if (parent instanceof ExportElementModel) {
        		ExportElementModel eem = (ExportElementModel)parent;
        		return (eem.getEnfants().size()+eem.getChamps().size());
        	} else if (parent instanceof ExportChampModel) {
        		return 0;
        	} else {
        		return 0;
        	}
        }

        public Object getChild(Object parent, int index) { 
        	if (parent instanceof ExportElementModel) {
        		ExportElementModel eem = (ExportElementModel)parent;
        		if (index < eem.getChamps().size()) {
        			return eem.getChamps().get(index);
        		} else {
        			// les enfants sont après les champs
        			return eem.getEnfants().get(index - eem.getChamps().size());
        		}
        	} else {
        		return null;
        	}
        }
        
        public boolean isCellEditable(Object object, int i) {
        	if (object instanceof ExportChampModel)
        		return true;//(i==1 && ((ExportChampModel)object).isEditable());
        	else
        		return false;
        }

        public int getIndexOfChild(Object parent, Object child) {
        	if (parent instanceof ExportElementModel) {
        		ExportElementModel p = (ExportElementModel)parent;
        		if (child instanceof ExportChampModel) {
	        		ExportChampModel c = (ExportChampModel)child;
	        		int i=0;
	            	for (;i<p.getChamps().size();i++) {
	            		ExportChampModel t = (ExportChampModel)p.getChamps().get(i);
	            		if (t.getId().equals(c.getId())) return i;
	            	}
        		} else {
        			ExportElementModel c = (ExportElementModel)child;
	        		int i=0;
	            	for (;i<p.getEnfants().size();i++) {
	            		ExportElementModel t = (ExportElementModel)p.getEnfants().get(i);
	            		if (t.getId().equals(c.getId())) return (i + p.getChamps().size());
	            	}
        		}
        	}
        	return -1;
        }

        public Object getRoot() { 
        	return _data.getEnfants().get(0); 
        }

        public int getColumnCount() { return columnNames.length; }
        
        public int getRowCount2 () {
        	int ret = getChampsCount(this._data);
        	if (this._data.getEnfants().size()>0) ret+=getChildsCount(_data);
        	return ret;
        }
        public int getChampsCount (Object parent) {
        	return ((ExportElementModel)parent).getChamps().size();
        }
        
        public int getChildsCount (Object parent) {
        	int ret = getChampsCount(parent);
        	for (ExportElementModel eem:((ExportElementModel)parent).getEnfants()) {
        		ret += getChildsCount(eem);
        	}
        	return ret;
        }
        
        @Override
		public String getColumnName(int arg0) {
			return columnNames[arg0];
		}
		public ExportModel getData() { return _data; }
		public void setData(ExportModel data) { this._data = data; }
    }
    @Override
	protected JRootPane createRootPane() {
	    KeyStroke ks = KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE,0);
	    JRootPane rp = new JRootPane();
		escapeAction = new AbstractAction("Fermer") {
		    /**
             * Comment for <code>serialVersionUID</code>
             */
            private static final long serialVersionUID = 1L;

            public void actionPerformed(ActionEvent evt) {
		        setVisible(false);
		    }
		};
	    rp.registerKeyboardAction(escapeAction,"TOTOTOTO",ks,JComponent.WHEN_IN_FOCUSED_WINDOW);
	    return rp;
	}

}
