001package jmri.jmrit.beantable.turnout;
002
003import java.awt.Component;
004
005import java.util.HashMap;
006
007import javax.swing.JTable;
008import javax.swing.table.*;
009
010import jmri.InstanceManager;
011import jmri.NamedBean;
012import jmri.Sensor;
013import jmri.SensorManager;
014import jmri.Turnout;
015import jmri.swing.NamedBeanComboBox;
016
017/**
018 * JTable to display a TurnoutTableDataModel.
019 * Code originally within TurnoutTableAction.
020 *
021 * @author Bob Jacobsen Copyright (C) 2003, 2004, 2007
022 * @author Egbert Broerse Copyright (C) 2017
023 * @author Steve Young Copyright (C) 2021, 2024
024 */
025public class TurnoutTableJTable extends jmri.jmrit.beantable.BeanTableJTable<Turnout> {
026
027    final HashMap<Turnout, TableCellRenderer> rendererMapSensor1 = new HashMap<>();
028    final HashMap<Turnout, TableCellEditor> editorMapSensor1 = new HashMap<>();
029
030    final HashMap<Turnout, TableCellRenderer> rendererMapSensor2 = new HashMap<>();
031    final HashMap<Turnout, TableCellEditor> editorMapSensor2 = new HashMap<>();
032
033    public TurnoutTableJTable(TurnoutTableDataModel mdl){
034        super(mdl);
035    }
036
037    @Override
038    public TableCellRenderer getCellRenderer(int row, int column) {
039        // Convert the displayed index to the model index, rather than the displayed index
040        int modelColumn = convertColumnIndexToModel(column);
041        if (modelColumn == TurnoutTableDataModel.SENSOR1COL || modelColumn == TurnoutTableDataModel.SENSOR2COL) {
042            return getRenderer(convertRowIndexToModel(row), modelColumn);
043        } else {
044            return super.getCellRenderer(row, column);
045        }
046    }
047
048    @Override
049    public TableCellEditor getCellEditor(final int row, final int column) {
050        //Convert the displayed index to the model index, rather than the displayed index
051        int modelColumn = this.convertColumnIndexToModel(column);
052        if (modelColumn == TurnoutTableDataModel.SENSOR1COL || modelColumn == TurnoutTableDataModel.SENSOR2COL) {
053            return getEditor(convertRowIndexToModel(row), modelColumn);
054        } else {
055            return super.getCellEditor(row, column);
056        }
057    }
058
059    private TableCellRenderer getRenderer(int modelRow, int modelColumn) {
060        TableCellRenderer retval;
061        Turnout t = (Turnout) getModel().getValueAt(modelRow, TurnoutTableDataModel.SYSNAMECOL);
062        java.util.Objects.requireNonNull(t, "SYSNAMECOL column content must be nonnull");
063        switch (modelColumn) {
064            case TurnoutTableDataModel.SENSOR1COL:
065                retval = rendererMapSensor1.get(t);
066                break;
067            case TurnoutTableDataModel.SENSOR2COL:
068                retval = rendererMapSensor2.get(t);
069                break;
070            default:
071                return null;
072        }
073
074        if (retval == null) {
075            if (modelColumn == TurnoutTableDataModel.SENSOR1COL) {
076                loadRenderEditMaps(rendererMapSensor1, editorMapSensor1, t, t.getFirstSensor());
077            } else {
078                loadRenderEditMaps(rendererMapSensor2, editorMapSensor2, t, t.getSecondSensor());
079            }
080            retval = rendererMapSensor1.get(t);
081        }
082        log.debug("fetched for Turnout \"{}\" renderer {}", t, retval);
083        return retval;
084    }
085
086    private TableCellEditor getEditor(int modelRow, int modelColumn) {
087        TableCellEditor retval;
088        Turnout t = (Turnout) getModel().getValueAt(modelRow, TurnoutTableDataModel.SYSNAMECOL);
089        java.util.Objects.requireNonNull(t, "SYSNAMECOL column content must be nonnull");
090        switch (modelColumn) {
091            case TurnoutTableDataModel.SENSOR1COL:
092                retval = editorMapSensor1.get(t);
093                break;
094            case TurnoutTableDataModel.SENSOR2COL:
095                retval = editorMapSensor2.get(t);
096                break;
097            default:
098                return null;
099        }
100        if (retval == null) {
101            if (modelColumn == TurnoutTableDataModel.SENSOR1COL) {
102                loadRenderEditMaps(rendererMapSensor1, editorMapSensor1, t, t.getFirstSensor());
103                retval = editorMapSensor1.get(t);
104            } else { //Must be two
105                loadRenderEditMaps(rendererMapSensor2, editorMapSensor2, t, t.getSecondSensor());
106                retval = editorMapSensor2.get(t);
107            }
108        }
109        log.debug("fetched for Turnout \"{}\" editor {}", t, retval);
110        return retval;
111    }
112
113    private void loadRenderEditMaps(HashMap<Turnout, TableCellRenderer> r, HashMap<Turnout, TableCellEditor> e,
114            Turnout t, Sensor s) {
115        NamedBeanComboBox<Sensor> c = new NamedBeanComboBox<>(InstanceManager.getDefault(
116            SensorManager.class), s, NamedBean.DisplayOptions.DISPLAYNAME);
117
118        TurnoutTableSensorBoxRenderer renderer = new TurnoutTableSensorBoxRenderer();
119        r.put(t, renderer);
120
121        TableCellEditor editor = new jmri.util.table.JComboBoxEditor(c, null);
122        e.put(t, editor);
123        log.debug("initialize for Turnout \"{}\" Sensor \"{}\"", t, s);
124    }
125
126    private static class TurnoutTableSensorBoxRenderer extends jmri.util.table.NamedBeanBoxRenderer<Sensor> {
127
128        TurnoutTableSensorBoxRenderer() {
129            super(InstanceManager.getDefault(SensorManager.class));
130            setAllowNull(true);
131        }
132
133        @Override
134        public Component getTableCellRendererComponent(JTable table, Object value,
135                boolean isSelected, boolean hasFocus, int row, int column) {
136
137            super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
138
139            int tableCol = table.convertColumnIndexToModel(column);
140            int tableRow = table.convertRowIndexToModel(row);
141            
142            Turnout t = (Turnout)table.getModel().getValueAt(tableRow, TurnoutTableDataModel.SYSNAMECOL);
143            if ( t == null ) {
144                return this;
145            }
146            if (value instanceof Sensor) {
147                if (( tableCol == TurnoutTableDataModel.SENSOR1COL ) && 
148                    (t.getFeedbackMode() != Turnout.ONESENSOR && t.getFeedbackMode() != Turnout.TWOSENSOR )) {
149                    setErrorBorder();
150                } else if ( tableCol == TurnoutTableDataModel.SENSOR2COL && t.getFeedbackMode() != Turnout.TWOSENSOR ) {
151                    setErrorBorder();
152                } else {
153                    setNormalBorder();
154                }
155            } else {
156                if (( tableCol == TurnoutTableDataModel.SENSOR1COL ) && 
157                        (t.getFeedbackMode() == Turnout.ONESENSOR || t.getFeedbackMode() == Turnout.TWOSENSOR )) {
158                    setErrorBorder();
159                } else if ( tableCol == TurnoutTableDataModel.SENSOR2COL && t.getFeedbackMode() == Turnout.TWOSENSOR ) {
160                    setErrorBorder();
161                } else {
162                    setNormalBorder();
163                }
164            }
165            return this;
166        }
167    }
168
169    private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(TurnoutTableJTable.class);
170
171}