001package jmri.jmrit.beantable.block;
002
003import java.awt.Component;
004import java.text.DecimalFormat;
005import java.util.HashMap;
006
007import javax.swing.JLabel;
008import javax.swing.JTable;
009import javax.swing.table.TableCellEditor;
010import javax.swing.table.TableCellRenderer;
011
012import jmri.*;
013import jmri.util.table.NamedBeanBoxRenderer;
014import jmri.util.table.JComboBoxEditor;
015
016/**
017 * JTable for displaying Block BeanTable.
018 * @author Steve Young Copyright (C) 2024
019 */
020public class BlockTableJTable extends jmri.jmrit.beantable.BeanTableJTable<Block> implements Disposable {
021
022    private final HashMap<Block, NamedBeanBoxRenderer<Sensor>> sensorComboMap = new HashMap<>();
023    private final HashMap<Block, NamedBeanBoxRenderer<Reporter>> reporterComboMap = new HashMap<>();
024
025    public BlockTableJTable( BlockTableDataModel blockTableDataModel) {
026        super(blockTableDataModel);
027        setDefaultRenderer(Float.class, new LengthRenderer());
028    }
029
030    @Override
031    public TableCellRenderer getCellRenderer(int row, int column) {
032        // Convert the displayed index to the model index, rather than the displayed index
033        switch (convertColumnIndexToModel(column)) {
034            case BlockTableDataModel.SENSORCOL:
035                return getSensorRenderer(convertRowIndexToModel(row));
036            case BlockTableDataModel.REPORTERCOL:
037                return getReporterRenderer(convertRowIndexToModel(row));
038            default:
039                return super.getCellRenderer(row, column);
040        }
041    }
042
043    @Override
044    public TableCellEditor getCellEditor(int row, int column) {
045        //Convert the displayed index to the model index, rather than the displayed index
046        switch (convertColumnIndexToModel(column)) {
047            case BlockTableDataModel.SENSORCOL:
048                Block t = (Block) getModel().getValueAt(convertRowIndexToModel(row), BlockTableDataModel.SYSNAMECOL);
049                return new JComboBoxEditor(sensorComboMap.get(t),null );
050            case BlockTableDataModel.REPORTERCOL:
051                Block tt = (Block) getModel().getValueAt(convertRowIndexToModel(row), BlockTableDataModel.SYSNAMECOL);
052                return new JComboBoxEditor(reporterComboMap.get(tt), null);
053            default:
054                return super.getCellEditor(row, column);
055        }
056    }
057
058    private TableCellRenderer getSensorRenderer(int modelRow) {
059        Block t = (Block) getModel().getValueAt(modelRow, BlockTableDataModel.SYSNAMECOL);
060        java.util.Objects.requireNonNull(t, "SYSNAMECOL column content must be nonnull");
061        return sensorComboMap.computeIfAbsent(t, k ->
062            new NamedBeanBoxRenderer<Sensor>(InstanceManager.getDefault(SensorManager.class)));
063    }
064
065    private TableCellRenderer getReporterRenderer(int modelRow) {
066        Block t = (Block) getModel().getValueAt(modelRow, BlockTableDataModel.SYSNAMECOL);
067        java.util.Objects.requireNonNull(t, "SYSNAMECOL column content must be nonnull");
068        return reporterComboMap.computeIfAbsent(t, k ->
069            new NamedBeanBoxRenderer<Reporter>(InstanceManager.getDefault(ReporterManager.class)));
070    }
071
072    private static class LengthRenderer extends javax.swing.table.DefaultTableCellRenderer{
073
074        private static final DecimalFormat twoDigit = new DecimalFormat("0.00");
075
076        @Override
077        public Component getTableCellRendererComponent(JTable table, Object value,
078            boolean isSelected, boolean hasFocus, int row, int column) {
079
080            Component comp = super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
081            if ( value instanceof Float && comp instanceof JLabel ) {
082                ((JLabel)comp).setText(twoDigit.format(value));
083            }
084            return comp;
085        }
086
087    }
088
089    @Override
090    public void dispose(){
091        sensorComboMap.forEach( (b,s) -> s.dispose() );
092        sensorComboMap.clear();
093        reporterComboMap.forEach( (b,r) -> r.dispose() );
094        reporterComboMap.clear();
095    }
096
097}