001package jmri.jmrix.can.cbus.swing.nodeconfig;
002
003import java.awt.BorderLayout;
004import java.awt.Color;
005import java.awt.Component;
006import java.awt.Font;
007import java.awt.event.MouseEvent;
008import java.util.EventObject;
009
010import javax.swing.*;
011import javax.swing.event.ChangeEvent;
012import javax.swing.event.ChangeListener;
013import javax.swing.table.TableCellEditor;
014import javax.swing.table.TableCellRenderer;
015import javax.swing.table.TableColumnModel;
016
017import jmri.jmrix.can.cbus.node.CbusNode;
018import jmri.jmrix.can.cbus.node.CbusNodeNVTableDataModel;
019
020import org.slf4j.Logger;
021import org.slf4j.LoggerFactory;
022
023/**
024 * Pane providing a Cbus event table. Menu code copied from BeanTableFrame.
025 *
026 * @author Steve Young (C) 2019
027 *
028 * @since 4.15.5
029 */
030public class CbusNodeNVEditTablePane extends jmri.jmrix.can.swing.CanPanel {
031
032    private final CbusNodeNVTableDataModel nodeNVModel;
033    private int largerFont;
034    private final JTable nodeNvTable;
035    private JScrollPane eventVarScroll;
036    private JPanel pane1;
037
038    protected CbusNodeNVEditTablePane( CbusNodeNVTableDataModel nVModel ) {
039        super();
040        nodeNVModel = nVModel;
041        nodeNvTable = new JTable(nodeNVModel);
042        
043    }
044    
045    protected void setNode(CbusNode node ) {
046        
047        if (pane1==null){
048            initTable();
049        }
050        
051        CbusNode nodeOfInterest = node;
052        nodeNVModel.setNode( nodeOfInterest );
053        pane1.setVisible(!(node == null));
054    }
055    
056    private void initTable(){
057        
058        pane1 = new JPanel();
059    
060        TableColumnModel tableModel = nodeNvTable.getColumnModel();
061        
062        nodeNvTable.createDefaultColumnsFromModel();
063        
064        nodeNvTable.setRowSelectionAllowed(true);
065        nodeNvTable.setColumnSelectionAllowed(false);
066        nodeNvTable.setSelectionMode(javax.swing.ListSelectionModel.SINGLE_INTERVAL_SELECTION);
067        nodeNvTable.getTableHeader().setReorderingAllowed(true);
068        nodeNvTable.setRowHeight(27);
069        
070        tableModel.getColumn(CbusNodeNVTableDataModel.NV_NUMBER_COLUMN).setCellRenderer(getRenderer());
071        tableModel.getColumn(CbusNodeNVTableDataModel.NV_CURRENT_VAL_COLUMN).setCellRenderer( getRenderer() );
072        tableModel.getColumn(CbusNodeNVTableDataModel.NV_CURRENT_HEX_COLUMN).setCellRenderer(getRenderer());
073        tableModel.getColumn(CbusNodeNVTableDataModel.NV_CURRENT_BIT_COLUMN).setCellRenderer( getRenderer() );        
074        
075        log.debug("_editable : {} , tot column {}",_editable, nodeNVModel.getColumnCount());
076        
077        if (_editable) {
078            tableModel.getColumn(CbusNodeNVTableDataModel.NV_SELECT_COLUMN).setCellRenderer( new SpinnerRenderer() );
079            tableModel.getColumn(CbusNodeNVTableDataModel.NV_SELECT_COLUMN).setCellEditor( new NvSpinnerEditor() );
080            tableModel.getColumn(CbusNodeNVTableDataModel.NV_SELECT_HEX_COLUMN).setCellRenderer(getRenderer());
081            tableModel.getColumn(CbusNodeNVTableDataModel.NV_SELECT_BIT_COLUMN).setCellRenderer( getRenderer() );
082        }
083        else {
084            tableModel.getColumn(CbusNodeNVTableDataModel.NV_SELECT_COLUMN).setMinWidth(0);
085            tableModel.getColumn(CbusNodeNVTableDataModel.NV_SELECT_COLUMN).setMaxWidth(0);
086            tableModel.getColumn(CbusNodeNVTableDataModel.NV_SELECT_COLUMN).setWidth(0);
087            
088            tableModel.getColumn(CbusNodeNVTableDataModel.NV_SELECT_HEX_COLUMN).setMinWidth(0);
089            tableModel.getColumn(CbusNodeNVTableDataModel.NV_SELECT_HEX_COLUMN).setMaxWidth(0);
090            tableModel.getColumn(CbusNodeNVTableDataModel.NV_SELECT_HEX_COLUMN).setWidth(0);
091            
092            tableModel.getColumn(CbusNodeNVTableDataModel.NV_SELECT_BIT_COLUMN).setMinWidth(0);
093            tableModel.getColumn(CbusNodeNVTableDataModel.NV_SELECT_BIT_COLUMN).setMaxWidth(0);
094            tableModel.getColumn(CbusNodeNVTableDataModel.NV_SELECT_BIT_COLUMN).setWidth(0);
095        }
096        
097        largerFont = new JTextField().getFont().getSize()+2;
098        
099        setLayout(new BorderLayout() );
100        
101        pane1.setLayout(new BorderLayout());
102        
103        // scroller for main table
104        eventVarScroll = new JScrollPane(nodeNvTable);
105
106        pane1.add(eventVarScroll);
107        
108        add(pane1);
109        pane1.setVisible(true);
110        
111        nodeNvTable.setAutoCreateColumnsFromModel( false );
112        
113        add(eventVarScroll);
114    
115    }
116    
117    private boolean _editable = true;
118    
119    protected void setNonEditable() {
120        _editable = false;
121    }
122    
123    public static final Color WHITE_GREEN = new Color(0xf5,0xf5,0xf5);
124    
125    /**
126     * Cell Renderer for string table columns, highlights any text in filter input
127     */    
128    private TableCellRenderer getRenderer() {
129        return new TableCellRenderer() {
130            
131            JTextField f = new JTextField();
132            
133            @Override
134            public Component getTableCellRendererComponent(
135                JTable table, Object arg1, boolean isSelected, boolean hasFocus, int row, int col) {
136                
137                f.setHorizontalAlignment(JTextField.CENTER);
138                f.setBorder( table.getBorder() );
139                
140                int tablecol = nodeNvTable.convertColumnIndexToModel(col);
141
142                if ( tablecol == CbusNodeNVTableDataModel.NV_NUMBER_COLUMN ){
143                    f.setFont(f.getFont().deriveFont(Font.BOLD, largerFont ));
144                }
145                
146                    int oldval = (int) nodeNVModel.getValueAt(row, CbusNodeNVTableDataModel.NV_CURRENT_VAL_COLUMN);
147                    int newval = (int) nodeNVModel.getValueAt(row, CbusNodeNVTableDataModel.NV_SELECT_COLUMN);
148
149                String string;
150                if(arg1 != null){
151                    string = arg1.toString();
152                    try {
153                        if (Integer.parseInt(string)<0){
154                            string="";
155                        }
156                    } catch (NumberFormatException ex) {
157                    }
158
159                    f.setText(string.toUpperCase());
160                } else {
161                    f.setText("");
162                }
163
164                if (( tablecol == CbusNodeNVTableDataModel.NV_SELECT_HEX_COLUMN
165                    || tablecol == CbusNodeNVTableDataModel.NV_SELECT_BIT_COLUMN)
166                    && ( oldval == newval ) ){
167                    f.setText("");
168                }
169
170
171                if (isSelected) {
172                    if ( oldval != newval ) {
173                        f.setBackground( Color.orange );
174                    }
175                    else {
176                        f.setBackground( table.getSelectionBackground() );
177                    }
178                } else {
179                    if ( oldval != newval ) {
180                        f.setBackground( Color.yellow );
181                    }
182                    else {
183                        if ( row % 2 == 0 ) {
184                            f.setBackground( table.getBackground() );
185                        }
186                        else {
187                            f.setBackground( WHITE_GREEN );
188                        }
189                    }
190                }
191                return f;
192            }
193        };
194    }
195
196    protected static class NvSpinnerEditor extends AbstractCellEditor implements ChangeListener, TableCellEditor {
197        
198        final JSpinner spinner = new JSpinner(new SpinnerNumberModel(0, 0, 255, 1));
199
200        public NvSpinnerEditor() {
201            init();
202        }
203        
204        final void init() {
205            spinner.addChangeListener(this);
206        }
207
208        @Override
209        public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected,
210            int row, int column) {
211            spinner.setValue( value);
212            spinner.setBorder(null);
213            
214            return spinner;
215        }
216
217        @Override
218        public boolean isCellEditable(EventObject evt) {
219            if (evt instanceof MouseEvent) {
220                return ((MouseEvent) evt).getClickCount() >= 1;
221            }
222            return true;
223        }
224
225        @Override
226        public Object getCellEditorValue() {
227            return spinner.getValue();
228        }
229        
230        @Override
231        public void stateChanged(ChangeEvent eve) {
232            stopCellEditing();
233        }
234    }
235
236    protected static class SpinnerRenderer extends JSpinner implements TableCellRenderer {
237        
238        public SpinnerRenderer() {
239        }
240   
241        @Override
242        public Component getTableCellRendererComponent(JTable table, Object value,
243            boolean isSelected, boolean hasFocus, int row, int column) {
244            setModel(new SpinnerNumberModel( (int) value, -1, 255, 1));
245            setEnabled((int)value >-1);
246            this.setOpaque(true);
247            this.setBorder(null);
248            return this;
249        }
250    }
251
252    private final static Logger log = LoggerFactory.getLogger(CbusNodeNVEditTablePane.class);
253
254}