001package jmri.jmrix.dcc4pc.swing.boardlists;
002
003import java.awt.BorderLayout;
004import java.beans.PropertyChangeListener;
005import java.util.List;
006import java.util.ResourceBundle;
007
008import javax.swing.BoxLayout;
009import javax.swing.JButton;
010import javax.swing.JPanel;
011import javax.swing.JScrollPane;
012import javax.swing.JTable;
013import javax.swing.JTextField;
014import javax.swing.SortOrder;
015import javax.swing.table.AbstractTableModel;
016import javax.swing.table.TableCellEditor;
017import javax.swing.table.TableRowSorter;
018
019import jmri.jmrix.dcc4pc.Dcc4PcSystemConnectionMemo;
020import jmri.jmrix.dcc4pc.swing.Dcc4PcPanelInterface;
021import jmri.swing.RowSorterUtil;
022import jmri.util.swing.JmriJOptionPane;
023import jmri.util.table.ButtonEditor;
024import jmri.util.table.ButtonRenderer;
025
026/**
027 * Frame for Signal Mast Add / Edit Panel
028 *
029 * @author Kevin Dickerson Copyright (C) 2011
030 * 
031 */
032public class BoardListPanel extends jmri.jmrix.dcc4pc.swing.Dcc4PcPanel implements Dcc4PcPanelInterface {
033
034    static final ResourceBundle rb = ResourceBundle.getBundle("jmri.jmrix.dcc4pc.swing.boardlists.BoardListBundle");
035
036    jmri.jmrix.dcc4pc.Dcc4PcSensorManager senMan;
037    ReaderBoardModel _BoardModel;
038
039    JScrollPane _BoardScrollPane;
040
041    public BoardListPanel() {
042        super();
043    }
044
045    /**
046     * {@inheritDoc}
047     */
048    @Override
049    public void initComponents(Dcc4PcSystemConnectionMemo memo) {
050        super.initComponents(memo);
051        senMan = memo.getSensorManager();
052        _boardListCount = senMan.getBoards();
053
054        setLayout(new BorderLayout());
055
056        JPanel header = new JPanel();
057        header.setLayout(new BoxLayout(header, BoxLayout.Y_AXIS));
058
059        JPanel sourcePanel = new JPanel();
060        header.add(sourcePanel);
061        add(header, BorderLayout.NORTH);
062
063        _BoardModel = new ReaderBoardModel();
064        JTable boardTable = new JTable(_BoardModel);
065        TableRowSorter<ReaderBoardModel> sorter = new TableRowSorter<>(_BoardModel); // leave default comparator for Integers
066        RowSorterUtil.setSortOrder(sorter, ReaderBoardModel.ADDRESS_COLUMN, SortOrder.ASCENDING);
067        
068        boardTable.setRowSelectionAllowed(false);
069        boardTable.setPreferredScrollableViewportSize(new java.awt.Dimension(600, 120));
070        _BoardModel.configureTable(boardTable);
071        _BoardScrollPane = new JScrollPane(boardTable);
072        _BoardModel.fireTableDataChanged();
073        add(_BoardScrollPane, BorderLayout.CENTER);
074
075        JPanel footer = new JPanel();
076
077        add(footer, BorderLayout.SOUTH);
078    }
079
080    private List<Integer> _boardListCount;
081
082    public class ReaderBoardModel extends AbstractTableModel implements PropertyChangeListener {
083
084        ReaderBoardModel() {
085            super();
086            if (senMan != null) {
087                senMan.addPropertyChangeListener(ReaderBoardModel.this);
088            }
089        }
090
091        /*void updateSignalMastLogic(SignalMastLogic senManOld, SignalMastLogic senManNew){
092         if(senManOld!=null)
093         senManOld.removePropertyChangeListener(this);
094         if(senManNew!=null)
095         senManNew.addPropertyChangeListener(this);
096         fireTableDataChanged();
097         }*/
098        @Override
099        public Class<?> getColumnClass(int c) {
100            if (c == EDIT_COLUMN) {
101                return JButton.class;
102            }
103            return String.class;
104        }
105
106        public void configureTable(JTable table) {
107            // allow reordering of the columns
108            table.getTableHeader().setReorderingAllowed(true);
109
110            // have to shut off autoResizeMode to get horizontal scroll to work (JavaSwing p 541)
111            table.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
112
113            // resize columns as requested
114            for (int i = 0; i < table.getColumnCount(); i++) {
115                int width = getPreferredWidth(i);
116                table.getColumnModel().getColumn(i).setPreferredWidth(width);
117            }
118            table.sizeColumnsToFit(-1);
119
120            configEditColumn(table);
121
122        }
123
124        public int getPreferredWidth(int col) {
125            switch (col) {
126                case ADDRESS_COLUMN:
127                case VERSION_COLUMN:
128                case INPUTS_COLUMN:
129                    return new JTextField(5).getPreferredSize().width;
130                case ENCODING_COLUMN:
131                case DESCRIPTION_COLUMN: // not actually used due to the configureTable, setColumnToHoldButton, configureButton
132                case EDIT_COLUMN: // not actually used due to the configureTable, setColumnToHoldButton, configureButton
133                    return new JTextField(22).getPreferredSize().width;
134                default:
135                    log.warn("Unexpected column in getPreferredWidth: {}", col);
136                    return new JTextField(8).getPreferredSize().width;
137            }
138        }
139
140        @Override
141        public String getColumnName(int col) {
142            switch (col) {
143                case INPUTS_COLUMN:
144                    return rb.getString("ColumnInput");
145                case ADDRESS_COLUMN:
146                    return rb.getString("ColumnAddress");
147                case ENCODING_COLUMN:
148                    return rb.getString("ColumnEncoding");
149                case VERSION_COLUMN:
150                    return rb.getString("ColumnVersion");
151                case DESCRIPTION_COLUMN:
152                    return rb.getString("ColumnDescription");
153                case EDIT_COLUMN: // no title above Edit buttons
154                default:
155                    return "";
156            }
157        }
158
159        public void dispose() {
160            if (senMan != null) {
161                senMan.removePropertyChangeListener(this);
162            }
163        }
164
165        @Override
166        public void propertyChange(java.beans.PropertyChangeEvent e) {
167            if (e.getPropertyName().equals("length")) {
168                _boardListCount = senMan.getBoards();
169                int length = (Integer) e.getNewValue();
170                if (length == 0) {
171                    senMan.removePropertyChangeListener(this);
172                    senMan = null;
173                }
174                fireTableDataChanged();
175            } /*else if (e.getPropertyName().equals("updatedDestination")) {
176             // a new NamedBean is available in the manager
177             _boardListCount = senMan.getBoards();
178             fireTableDataChanged();
179             } else if((e.getPropertyName().equals("state")) || (e.getPropertyName().equals("Enabled"))) {
180             fireTableDataChanged();
181             fireTableRowsUpdated(0, _boardListCount.size());
182             }*/
183
184        }
185
186        protected void configEditColumn(JTable table) {
187            // have the delete column hold a button
188            /*AbstractTableAction.rb.getString("EditDelete")*/
189            /*setColumnToHoldButton(table, DESCRIPTION_COLUMN, 
190             new JButton(rb.getString("ButtonEdit")));*/
191            setColumnToHoldButton(table, EDIT_COLUMN,
192                    new JButton(rb.getString("ButtonEdit")));
193        }
194
195        protected void setColumnToHoldButton(JTable table, int column, JButton sample) {
196            //TableColumnModel tcm = table.getColumnModel();
197            // install a button renderer & editor
198            ButtonRenderer buttonRenderer = new ButtonRenderer();
199            table.setDefaultRenderer(JButton.class, buttonRenderer);
200            TableCellEditor buttonEditor = new ButtonEditor(new JButton());
201            table.setDefaultEditor(JButton.class, buttonEditor);
202            // ensure the table rows, columns have enough room for buttons
203            table.setRowHeight(sample.getPreferredSize().height);
204            table.getColumnModel().getColumn(column)
205                    .setPreferredWidth((sample.getPreferredSize().width) + 4);
206        }
207
208        @Override
209        public int getColumnCount() {
210            return 6;
211        }
212
213        @Override
214        public boolean isCellEditable(int r, int c) {
215            return c == EDIT_COLUMN;
216        }
217
218        protected void editAddress(int r) {
219            int boardAddress = _boardListCount.get(r);
220
221            String retval = JmriJOptionPane.showInputDialog(_BoardScrollPane, rb.getString("ChangeAddress"),
222                rb.getString("ChangeAddressTitle"), JmriJOptionPane.INFORMATION_MESSAGE);
223            if ( retval == null ) { // Dialog closed
224                return;
225            }
226            //Need some validation!
227            senMan.changeBoardAddress(boardAddress, Integer.parseInt(retval));
228        }
229
230        public static final int ADDRESS_COLUMN = 0;
231        public static final int INPUTS_COLUMN = 1;
232        public static final int ENCODING_COLUMN = 2;
233        public static final int VERSION_COLUMN = 3;
234        public static final int DESCRIPTION_COLUMN = 4;
235        public static final int EDIT_COLUMN = 5;
236
237
238        @Override
239        public int getRowCount() {
240            if (_boardListCount == null) {
241                return 0;
242            }
243            return _boardListCount.size();
244        }
245
246        @Override
247        public Object getValueAt(int r, int c) {
248            if (senMan == null) {
249                return null;
250            }
251            // some error checking
252            if (r >= _boardListCount.size()) {
253                log.debug("row is greater than turnout list size");
254                return null;
255            }
256            switch (c) {
257                case INPUTS_COLUMN:
258                    return senMan.getBoardInputs(_boardListCount.get(r)) + 1;
259                case ADDRESS_COLUMN:  // slot number
260                    return _boardListCount.get(r);
261                case ENCODING_COLUMN:
262                    return senMan.getBoardEncodingAsString(_boardListCount.get(r));
263                case VERSION_COLUMN:
264                    return senMan.getBoardVersion(_boardListCount.get(r));
265                case DESCRIPTION_COLUMN:
266                    return senMan.getBoardDescription(_boardListCount.get(r));
267                case EDIT_COLUMN:
268                    return rb.getString("ButtonEdit");
269                default:
270                    return null;
271            }
272        }
273
274        @Override
275        public void setValueAt(Object type, int r, int c) {
276            if (c == EDIT_COLUMN) {
277                editAddress(r);
278            }
279            /*else if (c==EDIT_COLUMN)
280             deletePair(r);
281             else if (c==VERSION_COLUMN){
282             boolean b = ((Boolean)type).booleanValue();
283             if(b)
284             senMan.setEnabled(_boardListCount.get(r));
285             else
286             senMan.setDisabled(_boardListCount.get(r));
287                
288             }*/
289        }
290    }
291
292    /**
293     * Nested class to create one of these using old-style defaults
294     */
295    static public class Default extends jmri.jmrix.dcc4pc.swing.Dcc4PcNamedPaneAction {
296
297        public Default() {
298            super("Dcc4PC Command Monitor",
299                    new jmri.util.swing.sdi.JmriJFrameInterface(),
300                    BoardListPanel.class.getName(),
301                    jmri.InstanceManager.getDefault(Dcc4PcSystemConnectionMemo.class));
302        }
303    }
304
305    private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(BoardListPanel.class);
306
307}