/*
 * DlgControl.java
 *
 * Created on 15 février 2007, 16:52
 */

package fr.gouv.finances.cp.xemelios.controls;

import fr.gouv.finances.cp.xemelios.controls.extend.MainControlWrapper;
import java.awt.Component;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.FocusEvent;
import java.awt.event.FocusListener;
import java.awt.event.KeyEvent;
import java.io.File;
import java.io.IOException;
import java.util.Hashtable;
import java.util.StringTokenizer;
import java.util.Vector;

import javax.swing.AbstractAction;
import javax.swing.ActionMap;
import javax.swing.DefaultCellEditor;
import javax.swing.InputMap;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JComboBox;
import javax.swing.JComponent;
import javax.swing.JFileChooser;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JRootPane;
import javax.swing.JTable;
import javax.swing.JTextField;
import javax.swing.KeyStroke;
import javax.swing.SwingConstants;
import javax.swing.SwingUtilities;
import javax.swing.event.PopupMenuEvent;
import javax.swing.event.PopupMenuListener;
import javax.swing.event.TableModelListener;
import javax.swing.filechooser.FileFilter;
import javax.swing.table.DefaultTableCellRenderer;
import javax.swing.table.TableCellEditor;
import javax.swing.table.TableCellRenderer;
import javax.swing.table.TableModel;
import javax.swing.text.Keymap;

import org.apache.log4j.Logger;
import org.jdesktop.swingx.JXTable;

import fr.gouv.finances.dgfip.utils.Pair;
import fr.gouv.finances.cp.utils.ui.InfiniteGlassPane;
import fr.gouv.finances.dgfip.xemelios.common.config.DocumentModel;
import fr.gouv.finances.cp.xemelios.controls.models.OptionModel;
import fr.gouv.finances.cp.xemelios.controls.models.ParamModel;
import fr.gouv.finances.cp.xemelios.ui.HtmlViewer;
import fr.gouv.finances.cp.xemelios.ui.MainWindow;

/**
 *
 * @author  chm
 */
public class DlgControl extends javax.swing.JDialog implements ControlProgressListener {
    private static final Logger logger = Logger.getLogger(DlgControl.class);
    private DocumentModel documentModel;
    private MainControlWrapper mc;
    private static String lastInputDirectory;
    private AbstractAction escapeAction;
    private MainControl.Triplet triplet;
    
    /** Creates new form DlgControl */
    public DlgControl(java.awt.Frame parent, DocumentModel documentModel, MainControlWrapper mc) {
        super(parent, false);
        this.documentModel = documentModel;
        this.mc = mc;
        initComponents();
        InfiniteGlassPane glassPane = new InfiniteGlassPane();
        this.setGlassPane(glassPane);
        
        mc.setDlgControl(this);
        table.packAll();
        setLocationRelativeTo(getParent());
        pbOk.setDefaultCapable(true);
        getRootPane().setDefaultButton(pbOk);
    }
    
    @Override
    protected JRootPane createRootPane() {
        KeyStroke ks = KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE,0);
        JRootPane rp = new JRootPane();
        escapeAction = new AbstractAction("Annuler") {
            /**
             * Comment for <code>serialVersionUID</code>
             */
            private static final long serialVersionUID = 1L;
            
            public void actionPerformed(ActionEvent evt) {
                cancel(evt);
            }
        };
        rp.registerKeyboardAction(escapeAction,"TOTOTOTO",ks,JComponent.WHEN_IN_FOCUSED_WINDOW);
        return rp;
    }
    
    /** 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() {
        javax.swing.JLabel lblFileToImport;
        javax.swing.JLabel lblParams;
        javax.swing.JButton pbBrowse;

        lblFileToImport = new javax.swing.JLabel();
        pbBrowse = new javax.swing.JButton();
        dfFileToImport = new javax.swing.JTextField();
        lblParams = new javax.swing.JLabel();
        jScrollPane1 = new javax.swing.JScrollPane();
        table = new JParamTable(createModel());
        pbOk = new javax.swing.JButton();
        pbCancel = new javax.swing.JButton();

    	setTitle("Analyser un flux");
        lblFileToImport.setText("Fichier \u00e0 analyser");

        pbBrowse.setText("...");
        pbBrowse.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                browse(evt);
            }
        });

        lblParams.setText("Param\u00e8tres");

        table.setModel(createModel());
        table.setSortable(false);
        jScrollPane1.setViewportView(table);

        pbOk.setText("Ok");
        pbOk.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                doControl(evt);
            }
        });

        pbCancel.setText("Annuler");
        pbCancel.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                cancel(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()
                .add(layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
                    .add(layout.createSequentialGroup()
                        .addContainerGap()
                        .add(layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
                            .add(org.jdesktop.layout.GroupLayout.TRAILING, jScrollPane1, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, 482, Short.MAX_VALUE)
                            .add(org.jdesktop.layout.GroupLayout.TRAILING, layout.createSequentialGroup()
                                .add(pbCancel)
                                .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
                                .add(pbOk))
                            .add(org.jdesktop.layout.GroupLayout.TRAILING, layout.createSequentialGroup()
                                .add(dfFileToImport, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, 433, Short.MAX_VALUE)
                                .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
                                .add(pbBrowse))))
                    .add(layout.createSequentialGroup()
                        .add(12, 12, 12)
                        .add(lblFileToImport))
                    .add(layout.createSequentialGroup()
                        .add(12, 12, 12)
                        .add(lblParams)))
                .addContainerGap())
        );
        layout.setVerticalGroup(
            layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
            .add(layout.createSequentialGroup()
                .addContainerGap()
                .add(lblFileToImport)
                .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
                .add(layout.createParallelGroup(org.jdesktop.layout.GroupLayout.BASELINE)
                    .add(dfFileToImport, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)
                    .add(pbBrowse))
                .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
                .add(lblParams)
                .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
                .add(jScrollPane1, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, 257, Short.MAX_VALUE)
                .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
                .add(layout.createParallelGroup(org.jdesktop.layout.GroupLayout.BASELINE)
                    .add(pbOk)
                    .add(pbCancel))
                .addContainerGap())
        );
        pack();
    }// </editor-fold>//GEN-END:initComponents
    
    private void cancel(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_cancel
        setVisible(false);
    }//GEN-LAST:event_cancel
    
    private void doControl(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_doControl
        // TODO: implement
        if(doChecks()) {
            try {
                mc.writeControlConfigFile();
            } catch(IOException ioEx) {
                logger.error("while writting control config file",ioEx);
            }
            runControl();
        }
    }//GEN-LAST:event_doControl
    
    private void displayRapport(MainControl.Triplet infoRapport) {
        StringBuffer uri = new StringBuffer();
        uri.append("xemelios:/query?collectivite=").append(infoRapport.codeCollectivite).append("&budget=").append(infoRapport.codeBudget);
        uri.append("&docId=DocumentRapport&etatId=DonneesRapport&path=[n:Id/@n:V='").append(infoRapport.iDrapport.replaceAll("'","''")).append("']");
        MainWindow mw = (MainWindow)getParent();
        HtmlViewer viewer = new HtmlViewer(uri.toString(),"Rapport de contrôle",mw);
        mw.getDesk().add(viewer);
        mw.getDesk().getDesktopManager().maximizeFrame(viewer);
        viewer.show();
    }
    private void browse(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_browse
        JFileChooser fc = new JFileChooser();
        fc.addChoosableFileFilter(new FileFilter() {
            public boolean accept(File f) {
                return f.isDirectory() || f.getName().toUpperCase().endsWith("XML");
            }
            public String getDescription() {
                return "Fichiers XML";
            }
        });
        
        if(documentModel.getExtension()!=null) {
            fc.addChoosableFileFilter( new FileFilter() {
                public boolean accept(File f) {
                    return f.isDirectory() || f.getName().toUpperCase().endsWith(documentModel.getExtension().toUpperCase());
                }
                public String getDescription() {
                    return documentModel.getLibelleExtension();
                }
            });
        }
        
        if(lastInputDirectory!=null) {
            try {
                fc.setCurrentDirectory(new File(lastInputDirectory));
            } catch(Throwable t) {
                // on s'affranchit de la suppression du repertoire
            }
        }
        if(fc.showOpenDialog(this)==JFileChooser.APPROVE_OPTION) {
            dfFileToImport.setText(fc.getSelectedFile().getAbsolutePath());
            lastInputDirectory = fc.getSelectedFile().getParent();
        }
        
    }//GEN-LAST:event_browse
    
    private boolean doChecks() {
        if(dfFileToImport.getText()==null || dfFileToImport.getText().length()==0) {
            JOptionPane.showMessageDialog(this,"Le fichier à importer est obligatoire","Erreur",JOptionPane.ERROR_MESSAGE);
            dfFileToImport.grabFocus();
            return false;
        }
        for(ParamModel pm:mc.getDocumentControl().getParams()) {
            if(!pm.isOptional() && pm.getValue()==null) {
                JOptionPane.showMessageDialog(this,"Le paramètre "+pm.getName()+" est obligatoire.","Erreur",JOptionPane.ERROR_MESSAGE);
                return false;
            }
        }
        return true;
    }
    
    private void runControl() {
        
//        InfiniteGlassPane glassPane = new InfiniteGlassPane();
//        logger.debug("runcontrol");
//        this.setGlassPane(glassPane);
//        getGlassPane().setVisible(true);
//        logger.debug("runcontrol");
        File fToCtrl = new File(dfFileToImport.getText());
        if(!fToCtrl.exists()) {
            JOptionPane.showMessageDialog(this,"Le fichier indiqué n'existe pas :\n"+dfFileToImport.getText(),"Erreur",JOptionPane.ERROR_MESSAGE);
            return;
        }
        mc.setFileToControl(fToCtrl);
        Hashtable<String,Object> params = new Hashtable<String,Object>();
        for(ParamModel pm:mc.getDocumentControl().getParams()) {
            Object value = null;
            if(pm.getValue()==null) {
                logger.debug(pm.getName()+" has no value");
                continue;
            } else {
                if(pm.getSelect()!=null && pm.getSelect().isMultiValued()) {
                    StringTokenizer tokenizer = new StringTokenizer((String)pm.getValue(),DlgEditParam.SEPARATOR);
                    int  count = tokenizer.countTokens();
                    String[] values = new String[count];
                    for(int i=0;i<count;i++) {
                        values[i]=tokenizer.nextToken();
                    }
                    value = values;
                } else {
                    value = pm.getValue();
                }
            }
            params.put(pm.getId(),value);
            logger.debug("param -> "+pm.getId()+" : "+value.toString());
        }
        mc.setParameters(params);
        getGlassPane().setVisible(true);
        try {
            if(SwingUtilities.isEventDispatchThread()) {
                logger.debug("invoke later");
                SwingUtilities.invokeLater(mc);
            } else {
                logger.debug("invoke now");
                mc.run();
            }
//            mc.run();
        } catch(Throwable t) {
            t.printStackTrace();
            // TODO: FIXME
        }
        //MainControl.Triplet ret = null;
    }
    public void stopVentilateur() {
        getGlassPane().setVisible(false);
    }
    public void startVentilateur() {
        getGlassPane().setVisible(true);
    }
    public void notifyImportFailed() {
        JOptionPane.showMessageDialog(this,"L'import du rapport a échoué.","",JOptionPane.ERROR);
        setVisible(false);
    }
    public void notifyImportInterrupted(boolean hide) {
        JOptionPane.showMessageDialog(this,"L'import du rapport a été imterrompu.","",JOptionPane.CANCEL_OPTION);
        stopVentilateur();
        if(hide) setVisible(false);
    }
    public void notifyTechniqueValidationFailed() {
        setVisible(false);
    }
    public void notifyImportFinished(MainControl.Triplet triplet) {
        if(triplet!=null) displayRapport(triplet);
        setVisible(false);
    }
    
    private TableModel createModel() {
        return new ParamTableModel(null);
    }
    
    // Variables declaration - do not modify//GEN-BEGIN:variables
    private javax.swing.JTextField dfFileToImport;
    private javax.swing.JScrollPane jScrollPane1;
    private javax.swing.JButton pbCancel;
    private javax.swing.JButton pbOk;
    private org.jdesktop.swingx.JXTable table;
    // End of variables declaration//GEN-END:variables
    
    private class ParamTableModel implements TableModel {
        private Vector<ParamModel> params;
        public ParamTableModel(Hashtable<String,Object> existingParams) {
            super();
            this.params = mc.getDocumentControl().getParams();
            
        }
        public void removeTableModelListener(TableModelListener l) {
        }
        
        public void addTableModelListener(TableModelListener l) {
        }
        
        public void setValueAt(Object aValue, int rowIndex, int columnIndex) {
            ParamModel pm = getParam(rowIndex);
            if(columnIndex==1) pm.setValue(aValue);
        }
        
        public String getColumnName(int columnIndex) {
            if(columnIndex==0) return "Paramètre";
            return "Valeur";
        }
        
        public Class<?> getColumnClass(int columnIndex) {
            return String.class;
        }
        
        public boolean isCellEditable(int rowIndex, int columnIndex) {
            return columnIndex==1;
        }
        
        public Object getValueAt(int rowIndex, int columnIndex) {
            ParamModel pm = params.get(rowIndex);
            if(columnIndex==0) return pm.getName();
            else if(columnIndex==1) return pm.getValue();
            return "";
        }
        
        public int getRowCount() {
            return params.size();
        }
        
        public int getColumnCount() {
            return 2;
        }
        public ParamModel getParam(int rowIndex) {
            return params.get(rowIndex);
        }
    }
    
    private class JParamTable extends JXTable {
        private MyCellRenderer cellRenderer;
        private MyCellEditor cellEditor;
        public JParamTable(TableModel model) {
            super(model);
            if(model instanceof ParamTableModel) {
                cellRenderer = new MyCellRenderer((ParamTableModel)model);
                cellEditor = new MyCellEditor((ParamTableModel)model);
            }
        }
        public JParamTable() {
            super();
            cellRenderer = new MyCellRenderer(null);
        }
        public TableCellEditor getCellEditor(int row, int column) {
            return cellEditor;
        }
        public TableCellRenderer getCellRenderer(int row, int column) {
            return cellRenderer;
        }
        
        public void setModel(TableModel tableModel) {
            super.setModel(tableModel);
            if(tableModel!=null && tableModel instanceof ParamTableModel && cellRenderer!=null) {
                cellRenderer.setModel((ParamTableModel)tableModel);
                cellEditor.setModel((ParamTableModel)tableModel);
            }
        }
    }
    public class MyCellRenderer extends DefaultTableCellRenderer {
        private ParamTableModel ptm;
        public MyCellRenderer(ParamTableModel ptm) {
            super();
            this.ptm=ptm;
        }
        public Component getTableCellRendererComponent(JTable table,Object value,boolean isSelected,boolean hasFocus,int row,int column) {
            Component ret;
            if(column==0) {
                ret = super.getTableCellRendererComponent(table,value,isSelected,hasFocus,row,column);
                JLabel lbl=(JLabel)ret;
                lbl.setHorizontalAlignment(SwingConstants.LEFT);
            } else {
                ParamModel pm = ptm.getParam(row);
                JLabel lbl;
                Component c = super.getTableCellRendererComponent(table,value,isSelected,hasFocus,row,column);
                if("string".equals(pm.getDatatype()) || "integer".equals(pm.getDatatype()) || "decimal".equals(pm.getDatatype()) || "date".equals(pm.getDatatype()) ) {
                    lbl = (JLabel)c;
                    if(pm.getValue()==null) lbl.setText("");
                    else {
                        lbl.setText(pm.getValue().toString());
                    }
                    if("integer".equals(pm.getDatatype()) || "decimal".equals(pm.getDatatype())) lbl.setHorizontalAlignment(SwingConstants.RIGHT);
                    else lbl.setHorizontalAlignment(SwingConstants.LEFT);
                    ret = lbl;
                } else if("boolean".equals(pm.getDatatype())) {
                    JCheckBox chk = new JCheckBox();
                    chk.setBackground(c.getBackground());
                    chk.setHorizontalAlignment(SwingConstants.CENTER);
                    if(pm.getValue()!=null && pm.getValue() instanceof Boolean) {
                        Boolean b = (Boolean)pm.getValue();
                        chk.setSelected(b.booleanValue());
                    }
                    ret = chk;
                } else {
                    ret = super.getTableCellRendererComponent(table,value,isSelected,hasFocus,row,column);
                }
                if(pm.getSelect()!=null&& (pm.getSelect().isMultiValued()||pm.getSelect().isEditable())) {
                    final JButton pbEdit = new ButtonEditParam(pm);
                    double height = table.getRowHeight();
                    pbEdit.setSize((int)height,(int)height);
                    JPanel pane = new JPanel();
                    org.jdesktop.layout.GroupLayout layout = new org.jdesktop.layout.GroupLayout(pane);
                    pane.setLayout(layout);
                    layout.setHorizontalGroup(
                            layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
                            .add(org.jdesktop.layout.GroupLayout.TRAILING, layout.createSequentialGroup()
                            .add(ret, (int)height, 100, Short.MAX_VALUE)
                            .add(pbEdit, (int)height, (int)height, (int)height))
                            );
                    layout.setVerticalGroup(
                            layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
                            .add(layout.createParallelGroup(org.jdesktop.layout.GroupLayout.BASELINE)
                            .add(pbEdit, (int)height, (int)height, Short.MAX_VALUE)
                            .add(ret, (int)height, (int)height, (int)height))
                            );
                    InputMap iMap = pane.getInputMap();
                    Object actionKey = "helpButton";
                    iMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_F3,0),actionKey);
                    ActionMap am = pane.getActionMap();
                    am.put(actionKey,new AbstractAction() {
                        public void actionPerformed(ActionEvent e) {
                            pbEdit.doClick();
                        }
                    });
                    ret = pane;
                }
            }
            return ret;
        }
        public void setModel(ParamTableModel tpm) { this.ptm=tpm; }
    }
    public class MyCellEditor extends DefaultCellEditor {
        private DefaultCellEditor chkEditor, cbxEditor, dfEditor, currentEditor;
        private JComponent editorComponent;
        private ParamTableModel ptm;
        private PopupMenuListener cbxPopupListener;
        private FocusListener chkFocusListener;
        public MyCellEditor(ParamTableModel ptm) {
            super(new JTextField());
            chkEditor = new DefaultCellEditor(new JCheckBox());
            cbxEditor = new DefaultCellEditor(new JComboBox());
            dfEditor = new DefaultCellEditor(new JTextField());
            setClickCountToStart(1);
            this.ptm=ptm;
        }
        public Component getTableCellEditorComponent(JTable table,Object value,boolean isSelected,int row,int column) {
            ParamModel pm = ptm.getParam(row);
            Component ret;
            if(pm.getSelect()!=null && !pm.getSelect().isMultiValued()) {
                JComboBox cbx = (JComboBox)cbxEditor.getTableCellEditorComponent(table,value,isSelected,row,column);
                editorComponent = cbx;
                if(cbxPopupListener==null) {
                    cbxPopupListener = new PopupMenuListener() {
                        public void popupMenuWillBecomeVisible(PopupMenuEvent e) { }
                        public void popupMenuWillBecomeInvisible(PopupMenuEvent e) {
                            stopCellEditing();
                        }
                        public void popupMenuCanceled(PopupMenuEvent e) { }
                    };
                    cbx.addPopupMenuListener(cbxPopupListener);
                }
                cbx.removeAllItems();
                int selectedItem = -1;
                for(OptionModel om:pm.getSelect().getOptions()) {
                    cbx.addItem(new Pair(om.getValue(),om.getLibelle()));
                    if(value!=null && om.getValue().equals(value)) selectedItem = cbx.getItemCount()-1;
                }
                if(selectedItem!=-1) cbx.setSelectedIndex(selectedItem);
                ret = cbx;
                currentEditor = cbxEditor;
            } else if("boolean".equals(pm.getDatatype())) {
                JCheckBox chk = (JCheckBox)chkEditor.getTableCellEditorComponent(table,value,isSelected,row,column);
                chk.setHorizontalAlignment(SwingConstants.CENTER);
                chk.setBackground(table.getCellRenderer(row,column).getTableCellRendererComponent(table,value,isSelected,hasFocus(),row,column).getBackground());
                if(chkFocusListener==null) {
                    chkFocusListener = new FocusListener() {
                        public void focusGained(FocusEvent e) {
                        }
                        public void focusLost(FocusEvent e) {
                            stopCellEditing();
                        }
                    };
                    chk.addFocusListener(chkFocusListener);
                }
                ret = chk;
                currentEditor = chkEditor;
                editorComponent = chk;
            } else {
                JTextField df = (JTextField)dfEditor.getTableCellEditorComponent(table,value,isSelected,row,column);
                Keymap km = df.getKeymap();
                if(km.getAction(KeyStroke.getKeyStroke('\n'))==null) {
                    km.addActionForKeyStroke(KeyStroke.getKeyStroke('\n'),new AbstractAction() {
                        public void actionPerformed(ActionEvent e) {
                            stopCellEditing();
                        }
                    });
                }
                ret = df;
                currentEditor = dfEditor;
                editorComponent = df;
            }
            if(pm.getSelect()!=null&& (pm.getSelect().isMultiValued()||pm.getSelect().isEditable())) {
                final JButton pbEdit;
                if(ret instanceof JComboBox) pbEdit = new ButtonEditParam(pm,(JComboBox)ret);
                else pbEdit = new ButtonEditParam(pm,(JTextField)ret);
                double height = table.getRowHeight();
                pbEdit.setSize((int)height,(int)height);
                JPanel pane = new JPanel();
                org.jdesktop.layout.GroupLayout layout = new org.jdesktop.layout.GroupLayout(pane);
                pane.setLayout(layout);
                layout.setHorizontalGroup(
                        layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
                        .add(org.jdesktop.layout.GroupLayout.TRAILING, layout.createSequentialGroup()
                        .add(ret, (int)height, 100, Short.MAX_VALUE)
                        .add(pbEdit, (int)height, (int)height, (int)height))
                        );
                layout.setVerticalGroup(
                        layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
                        .add(layout.createParallelGroup(org.jdesktop.layout.GroupLayout.BASELINE)
                        .add(pbEdit, (int)height, (int)height, Short.MAX_VALUE)
                        .add(ret, (int)height, (int)height, (int)height))
                        );
                ret.addFocusListener(new FocusListener() {
                    public void focusGained(FocusEvent e) {
                    }
                    public void focusLost(FocusEvent e) {
                        stopCellEditing();
                    }
                });
                pane.addFocusListener(new FocusListener() {
                    public void focusGained(FocusEvent e) {
                        editorComponent.grabFocus();
                    }
                    public void focusLost(FocusEvent e) {
                    }
                });
                InputMap iMap = pane.getInputMap();
                Object actionKey = "helpButton";
                iMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_F3,0),actionKey);
                ActionMap am = pane.getActionMap();
                am.put(actionKey,new AbstractAction() {
                    public void actionPerformed(ActionEvent e) {
                        pbEdit.doClick();
                    }
                });
                ret = pane;
            }
            return ret;
        }
        public void setModel(ParamTableModel ptm) { this.ptm=ptm; }
        public Object getCellEditorValue() { return currentEditor.getCellEditorValue(); }
    }
    private class ButtonEditParam extends JButton {
        private final ParamModel pm;
        private JComboBox cbx;
        private JTextField df;
        private ButtonEditParam(ParamModel pm) {
            super("...");
            this.pm = pm;
            addActionListener(new ActionListener() {
                public void actionPerformed(ActionEvent e) {
                    doEdit();
                }
            });
        }
        public ButtonEditParam(ParamModel pm, JComboBox cbx) {
            this(pm);
            this.cbx=cbx;
        }
        public ButtonEditParam(ParamModel pm, JTextField df) {
            this(pm);
            this.df=df;
        }
        private void doEdit() {
            DlgEditParam dep = new DlgEditParam(DlgControl.this,pm);
            dep.setVisible(true);
            if(cbx!=null) {
                Object value = cbx.getSelectedItem();
                cbx.removeAllItems();
                int selectedItem = -1;
                for(OptionModel om:pm.getSelect().getOptions()) {
                    cbx.addItem(new Pair(om.getValue(),om.getLibelle()));
                    if(value!=null && om.getValue().equals(value)) selectedItem = cbx.getItemCount()-1;
                }
                if(selectedItem!=-1) cbx.setSelectedIndex(selectedItem);
            } else if(df!=null) {
                df.setText(pm.getValue().toString());
            }
        }
    }

    public void stopWaiting() { stopVentilateur(); }

}
