001package jmri.jmrix.dccpp.swing; 002 003import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; 004 005import java.awt.Component; 006import java.awt.Dimension; 007import java.awt.BorderLayout; 008import java.awt.event.ActionEvent; 009import java.awt.event.ActionListener; 010import java.awt.event.KeyEvent; 011import java.util.ArrayList; 012import java.util.HashMap; 013import java.util.List; 014import java.util.Map; 015 016import javax.swing.BoxLayout; 017import javax.swing.DefaultCellEditor; 018import javax.swing.JButton; 019import javax.swing.JCheckBox; 020import javax.swing.JLabel; 021import javax.swing.JMenu; 022import javax.swing.JMenuBar; 023import javax.swing.JMenuItem; 024import javax.swing.JPanel; 025import javax.swing.JScrollPane; 026import javax.swing.JTabbedPane; 027import javax.swing.JTable; 028import javax.swing.RowSorter; 029import javax.swing.SortOrder; 030import javax.swing.UIManager; 031import javax.swing.event.ChangeEvent; 032import javax.swing.event.EventListenerList; 033import javax.swing.table.TableCellRenderer; 034import javax.swing.table.TableModel; 035import javax.swing.table.TableRowSorter; 036 037import jmri.jmrix.dccpp.DCCppCommandStation; 038import jmri.jmrix.dccpp.DCCppConstants; 039import jmri.jmrix.dccpp.DCCppListener; 040import jmri.jmrix.dccpp.DCCppMessage; 041import jmri.jmrix.dccpp.DCCppReply; 042import jmri.jmrix.dccpp.DCCppSystemConnectionMemo; 043import jmri.jmrix.dccpp.DCCppTrafficController; 044import jmri.util.JmriJFrame; 045import jmri.util.swing.JmriJOptionPane; 046 047/* 048 * <hr> 049 * This file is part of JMRI. 050 * <p> 051 * JMRI is free software; you can redistribute it and/or modify it under 052 * the terms of version 2 of the GNU General Public License as published 053 * by the Free Software Foundation. See the "COPYING" file for a copy 054 * of this license. 055 * <p> 056 * JMRI is distributed in the hope that it will be useful, but WITHOUT 057 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 058 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 059 * for more details. 060 * 061 * @author Mark Underwood Copyright (C) 2011 062 */ 063public class ConfigBaseStationFrame extends JmriJFrame implements DCCppListener { 064 065 // Map of Mnemonic KeyEvent values to GUI Components 066 private static final Map<String, Integer> Mnemonics = new HashMap<>(); 067 068 static { 069 Mnemonics.put("SensorTab", KeyEvent.VK_E); // NOI18N 070 Mnemonics.put("DCCTurnoutTab", KeyEvent.VK_T); // NOI18N 071 Mnemonics.put("ServoTurnoutTab", KeyEvent.VK_R); // NOI18N 072 Mnemonics.put("VpinTurnoutTab", KeyEvent.VK_V); // NOI18N 073 Mnemonics.put("OutputTab", KeyEvent.VK_O); // NOI18N 074 Mnemonics.put("ButtonAdd", KeyEvent.VK_A); // NOI18N 075 Mnemonics.put("CloseButton", KeyEvent.VK_X); // NOI18N 076 Mnemonics.put("SaveButton", KeyEvent.VK_S); // NOI18N 077 } 078 079 protected EventListenerList listenerList = new javax.swing.event.EventListenerList(); 080 081 private final DCCppTrafficController _tc; 082 083 private JTabbedPane tabbedPane; 084 private JLabel versionLabel = new JLabel(""); 085 086 private SensorTableModel sensorModel; 087 private DccTurnoutTableModel dccTurnoutModel; 088 private ServoTurnoutTableModel servoTurnoutModel; 089 private VpinTurnoutTableModel vpinTurnoutModel; 090 private OutputTableModel outputModel; 091 private JTable sensorTable; 092 private JTable dccTurnoutTable; 093 private JTable servoTurnoutTable; 094 private JTable vpinTurnoutTable; 095 private JTable outputTable; 096 private TableRowSorter<TableModel> sensorSorter; 097 private TableRowSorter<TableModel> dccTurnoutSorter; 098 private TableRowSorter<TableModel> servoTurnoutSorter; 099 private TableRowSorter<TableModel> vpinTurnoutSorter; 100 private TableRowSorter<TableModel> outputSorter; 101 102 private enum CurrentTab { 103 SENSOR, DCCTURNOUT, SERVOTURNOUT, VPINTURNOUT, OUTPUT 104 } 105 private CurrentTab cTab; 106 107 private DCCppSystemConnectionMemo _memo; 108 109 private static final int SENSOR_TAB_NUM = 0; 110 private static final int DCCTURNOUT_TAB_NUM = 1; 111 private static final int SERVOTURNOUT_TAB_NUM=2; 112 private static final int VPINTURNOUT_TAB_NUM= 3; 113 private static final int OUTPUT_TAB_NUM = 4; 114 115 @SuppressFBWarnings(value = "EI_EXPOSE_REP2", 116 justification = "2D array of different types passed as complex parameter. " 117 + "Better to switch to passing use-specific objects rather than " 118 + "papering this over with a deep copy of the arguments. " 119 + "In any case, there's no risk of exposure here.") 120 public ConfigBaseStationFrame(DCCppSystemConnectionMemo memo) { 121 super(false, false); 122 _memo = memo; 123 _tc = memo.getDCCppTrafficController(); 124 initGui(); 125 } 126 127 private void initGui() { 128 129 // NOTE: Look at jmri.jmrit.vsdecoder.swing.ManageLocationsFrame 130 // for how to add a tab for turnouts and other things. 131 this.setTitle(Bundle.getMessage("FieldManageBaseStationFrameTitle") + " (" + _memo.getSystemPrefix() + ")"); 132 this.buildMenu(); 133 134 //create Add, Save and Close buttons 135 JButton addButton = new JButton(Bundle.getMessage("ButtonAddX", Bundle.getMessage("BeanNameSensor"))); 136 addButton.setToolTipText(Bundle.getMessage("ToolTipButtonMSFAdd")); 137 addButton.setMnemonic(Mnemonics.get("ButtonAdd")); // NOI18N 138 addButton.addActionListener((ActionEvent e) -> { 139 addButtonPressed(e); 140 }); 141 JButton closeButton = new JButton(Bundle.getMessage("ButtonClose")); 142 closeButton.setToolTipText(Bundle.getMessage("ToolTipButtonClose")); 143 closeButton.setMnemonic(Mnemonics.get("CloseButton")); // NOI18N 144 closeButton.addActionListener((ActionEvent e) -> { 145 closeButtonPressed(e); 146 }); 147 JButton saveButton = new JButton(Bundle.getMessage("ButtonSaveX", Bundle.getMessage("Sensors"))); 148 saveButton.setToolTipText(Bundle.getMessage("ToolTipButtonMSFSave")); 149 saveButton.setMnemonic(Mnemonics.get("SaveButton")); // NOI18N 150 saveButton.addActionListener((ActionEvent e) -> { 151 saveButtonPressed(e); 152 }); 153 154 //SENSOR TAB --------------------- 155 JScrollPane sensorScrollPanel = new JScrollPane(); 156 sensorModel = new SensorTableModel(); 157 sensorTable = new JTable(sensorModel); 158 sensorTable.setFillsViewportHeight(true); 159 sensorScrollPanel.getViewport().add(sensorTable); 160 sensorTable.setPreferredScrollableViewportSize(new Dimension(520, 200)); 161 sensorTable.getColumn(Bundle.getMessage("ColumnDelete")).setCellRenderer(new ButtonRenderer()); 162 sensorTable.removeColumn(sensorTable.getColumn("isNew")); 163 sensorTable.removeColumn(sensorTable.getColumn("isDirty")); 164 sensorTable.removeColumn(sensorTable.getColumn("isDelete")); 165 sensorTable.addMouseListener(new java.awt.event.MouseAdapter() { 166 @Override 167 public void mouseClicked(java.awt.event.MouseEvent evt) { 168 handleTableMouseClick(sensorTable, evt); 169 } 170 }); 171 sensorTable.setAutoCreateRowSorter(true); 172 sensorSorter = new TableRowSorter<>(sensorTable.getModel()); 173 sensorTable.setRowSorter(sensorSorter); 174 List<RowSorter.SortKey> sensorSortKeys = new ArrayList<>(); 175 sensorSortKeys.add(new RowSorter.SortKey(sensorTable.getColumn(Bundle.getMessage("IDCol")).getModelIndex(), SortOrder.ASCENDING)); 176 sensorSorter.setSortKeys(sensorSortKeys); 177 sensorSorter.sort(); 178 sensorSorter.setSortable(sensorTable.getColumn(Bundle.getMessage("ColumnDelete")).getModelIndex(), false); 179 180 //TURNOUT TAB --------------------- 181 JScrollPane dccTurnoutScrollPanel = new JScrollPane(); 182 dccTurnoutModel = new DccTurnoutTableModel(); 183 dccTurnoutTable = new JTable(dccTurnoutModel); 184 dccTurnoutTable.setFillsViewportHeight(true); 185 dccTurnoutScrollPanel.getViewport().add(dccTurnoutTable); 186 dccTurnoutTable.setPreferredScrollableViewportSize(new Dimension(520, 200)); 187 dccTurnoutTable.getColumn(Bundle.getMessage("ColumnDelete")).setCellRenderer(new ButtonRenderer()); 188 dccTurnoutTable.removeColumn(dccTurnoutTable.getColumn("isNew")); 189 dccTurnoutTable.removeColumn(dccTurnoutTable.getColumn("isDirty")); 190 dccTurnoutTable.removeColumn(dccTurnoutTable.getColumn("isDelete")); 191 dccTurnoutTable.addMouseListener(new java.awt.event.MouseAdapter() { 192 @Override 193 public void mouseClicked(java.awt.event.MouseEvent evt) { 194 handleTableMouseClick(dccTurnoutTable, evt); 195 } 196 }); 197 dccTurnoutTable.setAutoCreateRowSorter(true); 198 dccTurnoutSorter = new TableRowSorter<>(dccTurnoutTable.getModel()); 199 dccTurnoutTable.setRowSorter(dccTurnoutSorter); 200 List<RowSorter.SortKey> dccTurnoutSortKeys = new ArrayList<>(); 201 dccTurnoutSortKeys.add(new RowSorter.SortKey(dccTurnoutTable.getColumn(Bundle.getMessage("IDCol")).getModelIndex(), SortOrder.ASCENDING)); 202 dccTurnoutSorter.setSortKeys(dccTurnoutSortKeys); 203 dccTurnoutSorter.setSortable(dccTurnoutTable.getColumn(Bundle.getMessage("ColumnDelete")).getModelIndex(), false); 204 dccTurnoutSorter.sort(); 205 206 //SERVO TURNOUT TAB --------------------- 207 JScrollPane servoTurnoutScrollPanel = new JScrollPane(); 208 servoTurnoutModel = new ServoTurnoutTableModel(); 209 servoTurnoutTable = new JTable(servoTurnoutModel); 210 servoTurnoutTable.setFillsViewportHeight(true); 211 servoTurnoutScrollPanel.getViewport().add(servoTurnoutTable); 212 servoTurnoutTable.setPreferredScrollableViewportSize(new Dimension(520, 200)); 213 servoTurnoutTable.getColumn(Bundle.getMessage("ColumnDelete")).setCellRenderer(new ButtonRenderer()); 214 servoTurnoutTable.removeColumn(servoTurnoutTable.getColumn("isNew")); 215 servoTurnoutTable.removeColumn(servoTurnoutTable.getColumn("isDirty")); 216 servoTurnoutTable.removeColumn(servoTurnoutTable.getColumn("isDelete")); 217 servoTurnoutTable.addMouseListener(new java.awt.event.MouseAdapter() { 218 @Override 219 public void mouseClicked(java.awt.event.MouseEvent evt) { 220 handleTableMouseClick(servoTurnoutTable, evt); 221 } 222 }); 223 servoTurnoutTable.setAutoCreateRowSorter(true); 224 servoTurnoutSorter = new TableRowSorter<>(servoTurnoutTable.getModel()); 225 servoTurnoutTable.setRowSorter(servoTurnoutSorter); 226 List<RowSorter.SortKey> servoTurnoutSortKeys = new ArrayList<>(); 227 servoTurnoutSortKeys.add(new RowSorter.SortKey(servoTurnoutTable.getColumn(Bundle.getMessage("IDCol")).getModelIndex(), SortOrder.ASCENDING)); 228 servoTurnoutSorter.setSortKeys(servoTurnoutSortKeys); 229 servoTurnoutSorter.setSortable(servoTurnoutTable.getColumn(Bundle.getMessage("ColumnDelete")).getModelIndex(), false); 230 servoTurnoutSorter.sort(); 231 232 //VPIN TURNOUT TAB --------------------- 233 JScrollPane vpinTurnoutScrollPanel = new JScrollPane(); 234 vpinTurnoutModel = new VpinTurnoutTableModel(); 235 vpinTurnoutTable = new JTable(vpinTurnoutModel); 236 vpinTurnoutTable.setFillsViewportHeight(true); 237 vpinTurnoutScrollPanel.getViewport().add(vpinTurnoutTable); 238 vpinTurnoutTable.setPreferredScrollableViewportSize(new Dimension(520, 200)); 239 vpinTurnoutTable.getColumn(Bundle.getMessage("ColumnDelete")).setCellRenderer(new ButtonRenderer()); 240 vpinTurnoutTable.removeColumn(vpinTurnoutTable.getColumn("isNew")); 241 vpinTurnoutTable.removeColumn(vpinTurnoutTable.getColumn("isDirty")); 242 vpinTurnoutTable.removeColumn(vpinTurnoutTable.getColumn("isDelete")); 243 vpinTurnoutTable.addMouseListener(new java.awt.event.MouseAdapter() { 244 @Override 245 public void mouseClicked(java.awt.event.MouseEvent evt) { 246 handleTableMouseClick(vpinTurnoutTable, evt); 247 } 248 }); 249 vpinTurnoutTable.setAutoCreateRowSorter(true); 250 vpinTurnoutSorter = new TableRowSorter<>(vpinTurnoutTable.getModel()); 251 vpinTurnoutTable.setRowSorter(vpinTurnoutSorter); 252 List<RowSorter.SortKey> vpinTurnoutSortKeys = new ArrayList<>(); 253 vpinTurnoutSortKeys.add(new RowSorter.SortKey(vpinTurnoutTable.getColumn(Bundle.getMessage("IDCol")).getModelIndex(), SortOrder.ASCENDING)); 254 vpinTurnoutSorter.setSortKeys(vpinTurnoutSortKeys); 255 vpinTurnoutSorter.setSortable(vpinTurnoutTable.getColumn(Bundle.getMessage("ColumnDelete")).getModelIndex(), false); 256 vpinTurnoutSorter.sort(); 257 258 //OUTPUT TAB --------------------- 259 JScrollPane outputScrollPanel = new JScrollPane(); 260 outputModel = new OutputTableModel(); 261 outputTable = new JTable(outputModel); 262 outputTable.setFillsViewportHeight(true); 263 outputScrollPanel.getViewport().add(outputTable); 264 outputTable.setPreferredScrollableViewportSize(new Dimension(520, 200)); 265 outputTable.getColumn(Bundle.getMessage("ColumnDelete")).setCellRenderer(new ButtonRenderer()); 266 outputTable.removeColumn(outputTable.getColumn("isNew")); 267 outputTable.removeColumn(outputTable.getColumn("isDirty")); 268 outputTable.removeColumn(outputTable.getColumn("isDelete")); 269 outputTable.addMouseListener(new java.awt.event.MouseAdapter() { 270 @Override 271 public void mouseClicked(java.awt.event.MouseEvent evt) { 272 handleTableMouseClick(outputTable, evt); 273 } 274 }); 275 outputTable.setAutoCreateRowSorter(true); 276 outputSorter = new TableRowSorter<>(outputTable.getModel()); 277 outputTable.setRowSorter(outputSorter); 278 List<RowSorter.SortKey> outputSortKeys = new ArrayList<>(); 279 outputSortKeys.add(new RowSorter.SortKey(sensorTable.getColumn(Bundle.getMessage("IDCol")).getModelIndex(), SortOrder.ASCENDING)); 280 outputSorter.setSortKeys(outputSortKeys); 281 outputSorter.setSortable(sensorTable.getColumn(Bundle.getMessage("ColumnDelete")).getModelIndex(), false); 282 outputSorter.sort(); 283 284 // add the 5 tabs to the pane 285 tabbedPane = new JTabbedPane(); 286 tabbedPane.addTab(Bundle.getMessage("Sensors"), sensorScrollPanel); 287 tabbedPane.setToolTipTextAt(SENSOR_TAB_NUM, Bundle.getMessage("ToolTipSensorTab")); 288 tabbedPane.setMnemonicAt(SENSOR_TAB_NUM, Mnemonics.get("SensorTab")); // NOI18N 289 tabbedPane.addTab(Bundle.getMessage("DCCTurnouts"), dccTurnoutScrollPanel); 290 tabbedPane.setToolTipTextAt(DCCTURNOUT_TAB_NUM, Bundle.getMessage("ToolTipDccTurnoutTab")); 291 tabbedPane.setMnemonicAt(DCCTURNOUT_TAB_NUM, Mnemonics.get("DCCTurnoutTab")); // NOI18N 292 tabbedPane.addTab(Bundle.getMessage("ServoTurnouts"), servoTurnoutScrollPanel); 293 tabbedPane.setToolTipTextAt(SERVOTURNOUT_TAB_NUM, Bundle.getMessage("ToolTipServoTurnoutTab")); 294 tabbedPane.setMnemonicAt(SERVOTURNOUT_TAB_NUM, Mnemonics.get("ServoTurnoutTab")); // NOI18N 295 tabbedPane.addTab(Bundle.getMessage("VpinTurnouts"), vpinTurnoutScrollPanel); 296 tabbedPane.setToolTipTextAt(VPINTURNOUT_TAB_NUM, Bundle.getMessage("ToolTipVpinTurnoutTab")); 297 tabbedPane.setMnemonicAt(VPINTURNOUT_TAB_NUM, Mnemonics.get("VpinTurnoutTab")); // NOI18N 298 tabbedPane.addTab(Bundle.getMessage("FieldOutputsTabTitle"), outputScrollPanel); 299 tabbedPane.setToolTipTextAt(OUTPUT_TAB_NUM, Bundle.getMessage("ToolTipOutputTab")); 300 tabbedPane.setMnemonicAt(OUTPUT_TAB_NUM, Mnemonics.get("OutputTab")); // NOI18N 301 cTab = CurrentTab.SENSOR; 302 tabbedPane.setSelectedIndex(0); 303 tabbedPane.addChangeListener((ChangeEvent e) -> { 304 switch (tabbedPane.getSelectedIndex()) { // set button text and tooltips for selected tabs 305 case 4: 306 cTab = CurrentTab.OUTPUT; 307 addButton.setText(Bundle.getMessage("ButtonAddX", Bundle.getMessage("Output"))); 308 addButton.setToolTipText(Bundle.getMessage("ToolTipButtonMOFAdd")); 309 saveButton.setText(Bundle.getMessage("ButtonSaveX", Bundle.getMessage("FieldOutputsTabTitle"))); 310 saveButton.setToolTipText(Bundle.getMessage("ToolTipButtonMOFSave")); 311 log.debug("Current Tab is: {}", tabbedPane.getSelectedIndex()); 312 break; 313 case 3: 314 cTab = CurrentTab.VPINTURNOUT; 315 addButton.setText(Bundle.getMessage("ButtonAddX", Bundle.getMessage("VpinTurnout"))); 316 addButton.setToolTipText(Bundle.getMessage("ToolTipButtonMTFAdd")); 317 saveButton.setText(Bundle.getMessage("ButtonSaveX", Bundle.getMessage("VpinTurnouts"))); 318 saveButton.setToolTipText(Bundle.getMessage("ToolTipButtonMTFSave")); 319 log.debug("Current Tab is: {}", tabbedPane.getSelectedIndex()); 320 break; 321 case 2: 322 cTab = CurrentTab.SERVOTURNOUT; 323 addButton.setText(Bundle.getMessage("ButtonAddX", Bundle.getMessage("ServoTurnout"))); 324 addButton.setToolTipText(Bundle.getMessage("ToolTipButtonMTFAdd")); 325 saveButton.setText(Bundle.getMessage("ButtonSaveX", Bundle.getMessage("ServoTurnouts"))); 326 saveButton.setToolTipText(Bundle.getMessage("ToolTipButtonMTFSave")); 327 log.debug("Current Tab is: {}", tabbedPane.getSelectedIndex()); 328 break; 329 case 1: 330 cTab = CurrentTab.DCCTURNOUT; 331 addButton.setText(Bundle.getMessage("ButtonAddX", Bundle.getMessage("DCCTurnout"))); 332 addButton.setToolTipText(Bundle.getMessage("ToolTipButtonMTFAdd")); 333 saveButton.setText(Bundle.getMessage("ButtonSaveX", Bundle.getMessage("DCCTurnouts"))); 334 saveButton.setToolTipText(Bundle.getMessage("ToolTipButtonMTFSave")); 335 log.debug("Current Tab is: {}", tabbedPane.getSelectedIndex()); 336 break; 337 case 0: 338 default: 339 cTab = CurrentTab.SENSOR; 340 addButton.setText(Bundle.getMessage("ButtonAddX", Bundle.getMessage("BeanNameSensor"))); 341 addButton.setToolTipText(Bundle.getMessage("ToolTipButtonMSFAdd")); 342 saveButton.setText(Bundle.getMessage("ButtonSaveX", Bundle.getMessage("Sensors"))); 343 saveButton.setToolTipText(Bundle.getMessage("ToolTipButtonMSFSave")); 344 log.debug("Current Tab is: {}", tabbedPane.getSelectedIndex()); 345 } 346 }); 347 348 //Create and add various parts to the window 349 JPanel bottomPanel = new JPanel(new BorderLayout()); 350 JPanel bottomPanelLeft = new JPanel(); 351 JPanel bottomPanelRight = new JPanel(); 352 353 bottomPanelLeft.add(addButton); 354 bottomPanelLeft.add(saveButton); 355 bottomPanel.add(bottomPanelLeft, BorderLayout.WEST); 356 357 bottomPanelRight.add(versionLabel); 358 bottomPanelRight.add(closeButton); 359 bottomPanel.add(bottomPanelRight, BorderLayout.EAST); 360 361 this.getContentPane().setLayout(new BoxLayout(this.getContentPane(), BoxLayout.Y_AXIS)); 362 this.getContentPane().add(tabbedPane); 363 this.getContentPane().add(bottomPanel); 364 this.pack(); 365 this.setVisible(true); 366 } 367 368 private void buildMenu() { 369 this.setJMenuBar(new JMenuBar()); //set up the menuBar for the window 370 371 JMenu fileMenu = new JMenu(Bundle.getMessage("MenuFile")); 372 this.getJMenuBar().add(fileMenu); 373 374 JMenu mSend = new JMenu(Bundle.getMessage("MenuSend")); 375 JMenuItem iRequestDefs = new JMenuItem(Bundle.getMessage("RequestDefs")); 376 iRequestDefs.addActionListener(new ActionListener() { 377 @Override 378 public void actionPerformed(ActionEvent event) { 379 _tc.sendDCCppMessage(new DCCppMessage(String.valueOf(DCCppConstants.SENSOR_CMD)), null); 380 _tc.sendDCCppMessage(new DCCppMessage(String.valueOf(DCCppConstants.TURNOUT_CMD)), null); 381 _tc.sendDCCppMessage(new DCCppMessage(String.valueOf(DCCppConstants.OUTPUT_CMD)), null); 382 _tc.sendDCCppMessage(DCCppMessage.makeTurnoutIDsMsg(), null); 383 } 384 }); 385 mSend.add(iRequestDefs); 386 387 JMenuItem iRequestStates = new JMenuItem(Bundle.getMessage("RequestStates")); 388 iRequestStates.addActionListener(new ActionListener() { 389 @Override 390 public void actionPerformed(ActionEvent event) { 391 _tc.sendDCCppMessage(new DCCppMessage(String.valueOf(DCCppConstants.READ_CS_STATUS)), null); 392 } 393 }); 394 mSend.add(iRequestStates); 395 396 JMenuItem iSaveToEeprom = new JMenuItem(Bundle.getMessage("SaveToEEPROM")); 397 iSaveToEeprom.addActionListener(new ActionListener() { 398 @Override 399 public void actionPerformed(ActionEvent event) { 400 _tc.sendDCCppMessage(new DCCppMessage(String.valueOf(DCCppConstants.WRITE_TO_EEPROM_CMD)), null); 401 } 402 }); 403 mSend.add(iSaveToEeprom); 404 405 JMenuItem iEraseEeprom = new JMenuItem(Bundle.getMessage("ClearEEPROM")); 406 iEraseEeprom.addActionListener(new ActionListener() { 407 @Override 408 public void actionPerformed(ActionEvent event) { 409 _tc.sendDCCppMessage(new DCCppMessage(String.valueOf(DCCppConstants.CLEAR_EEPROM_CMD)), null); 410 } 411 }); 412 mSend.add(iEraseEeprom); 413 414 JMenuItem iReadLocoId = new JMenuItem(Bundle.getMessage("ReadLocoId")); 415 iReadLocoId.addActionListener(new ActionListener() { 416 @Override 417 public void actionPerformed(ActionEvent event) { 418 _tc.sendDCCppMessage(new DCCppMessage(String.valueOf(DCCppConstants.PROG_READ_CV)), null); 419 } 420 }); 421 mSend.add(iReadLocoId); 422 423 JMenuItem iTrackManagerCmd = new JMenuItem(Bundle.getMessage("TrackManagerCmd")); 424 iTrackManagerCmd.addActionListener(new ActionListener() { 425 @Override 426 public void actionPerformed(ActionEvent event) { 427 _tc.sendDCCppMessage(DCCppMessage.makeTrackManagerRequestMsg(), null); 428 } 429 }); 430 mSend.add(iTrackManagerCmd); 431 432 this.getJMenuBar().add(mSend); 433 434 JMenu dccppMenu = new DCCppMenu(_memo); 435 dccppMenu.setText(Bundle.getMessage("MenuDCC++")); // always use generic text 436 this.getJMenuBar().add(dccppMenu); 437 } 438 439 // handle incoming object creation messages by adding them to the appropriate table 440 // handle incoming status message by disabling unsupported functions 441 @Override 442 public void message(DCCppReply r) { 443 // When we get a SensorDefReply message, add the 444 // sensor information to the data map for the model. 445 if (r.isSensorDefReply()) { 446 List<Object> v = new ArrayList<>(); 447 v.add(r.getSensorDefNumInt()); 448 v.add(r.getSensorDefPinInt()); 449 v.add(r.getSensorDefPullupBool()); 450 sensorModel.insertData(v, false); 451 sensorSorter.sort(); 452 } else if (r.isTurnoutDefReply() || r.isTurnoutDefDCCReply()) { 453 List<Object> v = new ArrayList<>(); 454 v.add(r.getTOIDInt()); 455 v.add(r.getTurnoutDefAddrInt()); 456 v.add(r.getTurnoutDefSubAddrInt()); 457 dccTurnoutModel.insertData(v, false); 458 dccTurnoutSorter.sort(); 459 } else if (r.isTurnoutDefServoReply()) { 460 List<Object> v = new ArrayList<>(); 461 v.add(r.getTOIDInt()); 462 v.add(r.getTOPinInt()); 463 v.add(r.getTOThrownPositionInt()); 464 v.add(r.getTOClosedPositionInt()); 465 v.add(r.getTOProfileInt()); 466 servoTurnoutModel.insertData(v, false); 467 servoTurnoutSorter.sort(); 468 } else if (r.isTurnoutDefVpinReply()) { 469 List<Object> v = new ArrayList<>(); 470 v.add(r.getTOIDInt()); 471 v.add(r.getTOPinInt()); 472 vpinTurnoutModel.insertData(v, false); 473 vpinTurnoutSorter.sort(); 474 } else if (r.isOutputDefReply()) { 475 List<Object> v = new ArrayList<>(); 476 v.add(r.getOutputNumInt()); 477 v.add(r.getOutputListPinInt()); 478 v.add((r.getOutputListIFlagInt() & 0x01) == 1); // (bool) Invert 479 v.add((r.getOutputListIFlagInt() & 0x02) == 2); // (bool) Restore State 480 v.add((r.getOutputListIFlagInt() & 0x04) == 4); // (bool) Force High 481 outputModel.insertData(v, false); 482 outputSorter.sort(); 483 } else if (r.isStatusReply()) { 484 DCCppCommandStation cs = _tc.getCommandStation(); 485 //enable or disable some tabs based on support by command station 486 if (cs.isServoTurnoutCreationSupported()) { 487 tabbedPane.setEnabledAt(SERVOTURNOUT_TAB_NUM, true); 488 tabbedPane.setEnabledAt(VPINTURNOUT_TAB_NUM, true); 489 } else { 490 tabbedPane.setEnabledAt(SERVOTURNOUT_TAB_NUM, false); 491 tabbedPane.setEnabledAt(VPINTURNOUT_TAB_NUM, false); 492 } 493 //populate the version line 494 String v = cs.getStationType() + " " + cs.getVersion() + " " + cs.getBuild(); 495 if (v.length() > 40) { 496 v = ""; //don't try to show really long version strings here 497 } 498 versionLabel.setText(v); 499 } 500 } 501 502 @Override 503 public void message(DCCppMessage m) { 504 // Do nothing 505 } 506 507 @Override 508 public void notifyTimeout(DCCppMessage m) { 509 // Do nothing 510 } 511 512 /** 513 * Handle mouse clicks within a table. 514 * <p> 515 * This is currently the workings behind the "Delete" button in the table. 516 * 517 * @param table the table where the event occurred 518 * @param evt the mouse click 519 */ 520 private void handleTableMouseClick(JTable table, java.awt.event.MouseEvent evt) { 521 int row = table.rowAtPoint(evt.getPoint()); 522 int col = table.columnAtPoint(evt.getPoint()); 523 if (row < 0 || col < 0) { 524 return; 525 } 526 DCCppTableModel model = (DCCppTableModel) table.getModel(); 527 if (col == table.convertColumnIndexToView(model.getDeleteColumn())) { 528 // This is a row delete action. Handle it as such. 529 int sel = table.convertRowIndexToModel(row); 530 int idx = (int) model.getValueAt(sel, 0); 531 log.debug("idx = {}", sel); 532 int value = JmriJOptionPane.showConfirmDialog(null, Bundle.getMessage("DeleteWarningMessage", Integer.toString(idx)), 533 Bundle.getMessage("WarningTitle"), 534 JmriJOptionPane.OK_CANCEL_OPTION); 535 if (value == JmriJOptionPane.OK_OPTION) { 536 if (null != cTab) { 537 switch (cTab) { 538 case SENSOR: 539 _tc.sendDCCppMessage(DCCppMessage.makeSensorDeleteMsg(idx), this); 540 sensorModel.removeRow(sel); 541 log.debug("Delete sensor {}", idx); 542 break; 543 case DCCTURNOUT: 544 DCCppMessage m = new DCCppMessage("T " + Integer.toString(idx)); 545 _tc.sendDCCppMessage(m, this); 546 log.debug("Sending: {}", m); 547 dccTurnoutModel.removeRow(sel); 548 break; 549 case SERVOTURNOUT: 550 m = new DCCppMessage("T " + Integer.toString(idx)); 551 _tc.sendDCCppMessage(m, this); 552 log.debug("Sending: {}", m); 553 servoTurnoutModel.removeRow(sel); 554 break; 555 case VPINTURNOUT: 556 m = new DCCppMessage("T " + Integer.toString(idx)); 557 _tc.sendDCCppMessage(m, this); 558 log.debug("Sending: {}", m); 559 vpinTurnoutModel.removeRow(sel); 560 break; 561 case OUTPUT: 562 _tc.sendDCCppMessage(DCCppMessage.makeOutputDeleteMsg(idx), this); 563 outputModel.removeRow(sel); 564 break; 565 default: 566 jmri.util.LoggingUtil.warnOnce(log, "Unexpected cTab value = {}", cTab); 567 break; 568 } 569 } 570 } 571 572 } 573 } 574 575 /** 576 * Responder for pressing the "Add" button. Response depends on which tab is 577 * active. 578 * 579 * @param e the press event 580 */ 581 private void addButtonPressed(ActionEvent e) { 582 if (null != cTab) { 583 switch (cTab) { 584 case SENSOR: { 585 List<Object> v = new ArrayList<>(); 586 v.add(0); // Index 587 v.add(0); // Pin 588 v.add(false); // Pullup 589 sensorModel.insertData(v, true); 590 break; 591 } 592 case DCCTURNOUT: { 593 List<Object> v = new ArrayList<>(); 594 v.add(0); // ID 595 v.add(0); // Address 596 v.add(0); // Subaddress 597 dccTurnoutModel.insertData(v, true); 598 break; 599 } 600 case SERVOTURNOUT: { 601 List<Object> v = new ArrayList<>(); 602 v.add(0); // ID 603 v.add(0); // pin 604 v.add(0); // thrownposition 605 v.add(0); // closedposition 606 v.add(0); // profile 607 servoTurnoutModel.insertData(v, true); 608 break; 609 } 610 case VPINTURNOUT: { 611 List<Object> v = new ArrayList<>(); 612 v.add(0); // ID 613 v.add(0); // Pin 614 vpinTurnoutModel.insertData(v, true); 615 break; 616 } 617 case OUTPUT: { 618 List<Object> v = new ArrayList<>(); 619 v.add(0); // Index 620 v.add(0); // Pin 621 v.add(false); // Invert 622 v.add(false); // Restore state 623 v.add(false); // Force high/low 624 outputModel.insertData(v, true); 625 break; 626 } 627 default: 628 break; 629 } 630 } 631 } 632 633 /** 634 * Respond to the user pressing the "Save Sensors/Turnouts/Outputs" button. 635 * 636 * @param e the button press event 637 */ 638 private void saveButtonPressed(ActionEvent e) { 639 int value = JmriJOptionPane.showConfirmDialog(null, Bundle.getMessage("FieldMCFSaveDialogConfirmMessage"), 640 Bundle.getMessage("ConfirmSaveDialogTitle"), 641 JmriJOptionPane.YES_NO_OPTION); 642 if (sensorTable.getCellEditor() != null) { 643 sensorTable.getCellEditor().stopCellEditing(); 644 } 645 if (dccTurnoutTable.getCellEditor() != null) { 646 dccTurnoutTable.getCellEditor().stopCellEditing(); 647 } 648 if (servoTurnoutTable.getCellEditor() != null) { 649 servoTurnoutTable.getCellEditor().stopCellEditing(); 650 } 651 if (vpinTurnoutTable.getCellEditor() != null) { 652 vpinTurnoutTable.getCellEditor().stopCellEditing(); 653 } 654 if (outputTable.getCellEditor() != null) { 655 outputTable.getCellEditor().stopCellEditing(); 656 } 657 if (value == JmriJOptionPane.YES_OPTION) { 658 saveTableValues(); 659 } 660 } 661 662 /** 663 * Save the values for the currently selected tab. 664 */ 665 private void saveTableValues() { 666 if (null != cTab) { 667 switch (cTab) { 668 case SENSOR: 669 for (int i = 0; i < sensorModel.getRowData().size(); i++) { 670 671 List<Object> r = sensorModel.getRowData().get(i); 672 boolean isnew = (boolean) r.get(4); 673 boolean isdirty = (boolean) r.get(5); 674 boolean isdelete = (boolean) r.get(6); 675 int row = sensorModel.getRowData().indexOf(r); 676 if (isnew) { 677 _tc.sendDCCppMessage(DCCppMessage.makeSensorAddMsg((int) r.get(0), 678 (int) r.get(1), 679 ((boolean) r.get(2) ? 1 : 0)), this); 680 sensorModel.setNewRow(row, false); 681 } else if (isdelete) { 682 _tc.sendDCCppMessage(DCCppMessage.makeSensorDeleteMsg((int) r.get(0)), this); 683 sensorModel.getRowData().remove(r); 684 } else if (isdirty) { 685 // Send a Delete, then an Add (for now). 686 _tc.sendDCCppMessage(DCCppMessage.makeSensorDeleteMsg((int) r.get(0)), this); 687 // WARNING: Conversions here are brittle. Be careful. 688 _tc.sendDCCppMessage(DCCppMessage.makeSensorAddMsg((int) r.get(0), 689 (int) r.get(1), 690 ((boolean) r.get(2) ? 1 : 0)), this); 691 sensorModel.setNewRow(row, false); 692 sensorModel.setDirtyRow(row, false); 693 } 694 } 695 _tc.sendDCCppMessage(DCCppMessage.makeSensorListMsg(), this); //request updated definitions list 696 break; 697 case DCCTURNOUT: 698 for (int i = 0; i < dccTurnoutModel.getRowData().size(); i++) { 699 700 List<Object> r = dccTurnoutModel.getRowData().get(i); 701 boolean isnew = (boolean) r.get(4); 702 boolean isdirty = (boolean) r.get(5); 703 boolean isdelete = (boolean) r.get(6); 704 int row = dccTurnoutModel.getRowData().indexOf(r); 705 if (isnew) { 706 // WARNING: Conversions here are brittle. Be careful. 707 _tc.sendDCCppMessage(DCCppMessage.makeTurnoutAddMsg((int) r.get(0), 708 (int) r.get(1), (int) r.get(2)), this); 709 dccTurnoutModel.setNewRow(row, false); 710 } else if (isdelete) { 711 DCCppMessage m = new DCCppMessage("T " + Integer.toString((int) r.get(0))); 712 _tc.sendDCCppMessage(m, this); 713 log.debug("Sending: {}", m); 714 dccTurnoutModel.getRowData().remove(r); 715 } else if (isdirty) { 716 _tc.sendDCCppMessage(DCCppMessage.makeTurnoutDeleteMsg((int) r.get(0)), this); 717 // Send a Delete, then an Add (for now). 718 // WARNING: Conversions here are brittle. Be careful. 719 _tc.sendDCCppMessage(DCCppMessage.makeTurnoutAddMsg((int) r.get(0), 720 (int) r.get(1), (int) r.get(2)), this); 721 dccTurnoutModel.setNewRow(row, false); 722 dccTurnoutModel.setDirtyRow(row, false); 723 } 724 } 725 //request updated definitions list 726 if (_tc.getCommandStation().isTurnoutIDsMessageRequired()) { 727 _tc.sendDCCppMessage(DCCppMessage.makeTurnoutIDsMsg(), this); 728 } else { 729 _tc.sendDCCppMessage(DCCppMessage.makeTurnoutListMsg(), this); 730 } 731 break; 732 case SERVOTURNOUT: 733 for (int i = 0; i < servoTurnoutModel.getRowData().size(); i++) { 734 735 List<Object> r = servoTurnoutModel.getRowData().get(i); 736 boolean isnew = (boolean) r.get(6); 737 boolean isdirty = (boolean) r.get(7); 738 boolean isdelete = (boolean) r.get(8); 739 int row = servoTurnoutModel.getRowData().indexOf(r); 740 if (isnew) { 741 // WARNING: Conversions here are brittle. Be careful. 742 DCCppMessage m = new DCCppMessage("T "+(int)r.get(0)+" SERVO "+(int)r.get(1)+" "+ 743 +(int)r.get(2)+" "+(int)r.get(3)+" "+(int)r.get(4)); 744 log.debug("Sending: {}", m); 745 _tc.sendDCCppMessage(m, this); 746 servoTurnoutModel.setNewRow(row, false); 747 } else if (isdelete) { 748 DCCppMessage m = new DCCppMessage("T " + Integer.toString((int) r.get(0))); 749 _tc.sendDCCppMessage(m, this); 750 log.debug("Sending: {}", m); 751 servoTurnoutModel.getRowData().remove(r); 752 } else if (isdirty) { 753 _tc.sendDCCppMessage(DCCppMessage.makeTurnoutDeleteMsg((int) r.get(0)), this); 754 // Send a Delete, then an Add (for now). 755 // WARNING: Conversions here are brittle. Be careful. 756 _tc.sendDCCppMessage(DCCppMessage.makeTurnoutAddMsg((int) r.get(0), 757 (int) r.get(1), (int) r.get(2)), this); 758 servoTurnoutModel.setNewRow(row, false); 759 servoTurnoutModel.setDirtyRow(row, false); 760 } 761 } 762 //request updated definitions list 763 if (_tc.getCommandStation().isTurnoutIDsMessageRequired()) { 764 _tc.sendDCCppMessage(DCCppMessage.makeTurnoutIDsMsg(), this); 765 } else { 766 _tc.sendDCCppMessage(DCCppMessage.makeTurnoutListMsg(), this); 767 } 768 break; 769 case VPINTURNOUT: 770 for (int i = 0; i < vpinTurnoutModel.getRowData().size(); i++) { 771 772 List<Object> r = vpinTurnoutModel.getRowData().get(i); 773 boolean isnew = (boolean) r.get(3); 774 boolean isdirty = (boolean) r.get(4); 775 boolean isdelete = (boolean) r.get(5); 776 int row = vpinTurnoutModel.getRowData().indexOf(r); 777 if (isnew) { 778 // WARNING: Conversions here are brittle. Be careful. 779 DCCppMessage m = new DCCppMessage("T "+(int)r.get(0)+" VPIN "+(int)r.get(1)); 780 log.debug("Sending: {}", m); 781 _tc.sendDCCppMessage(m, this); 782 vpinTurnoutModel.setNewRow(row, false); 783 } else if (isdelete) { 784 DCCppMessage m = new DCCppMessage("T " + (int)r.get(0)); 785 log.debug("Sending: {}", m); 786 _tc.sendDCCppMessage(m, this); 787 vpinTurnoutModel.getRowData().remove(r); 788 } else if (isdirty) { 789 // Send a Delete, then an Add (for now). 790 DCCppMessage m = new DCCppMessage("T " + (int)r.get(0)); 791 log.debug("Sending: {}", m); 792 _tc.sendDCCppMessage(m, this); 793 vpinTurnoutModel.setNewRow(row, false); 794 vpinTurnoutModel.setDirtyRow(row, false); 795 } 796 } 797 //request updated definitions list 798 if (_tc.getCommandStation().isTurnoutIDsMessageRequired()) { 799 _tc.sendDCCppMessage(DCCppMessage.makeTurnoutIDsMsg(), this); 800 } else { 801 _tc.sendDCCppMessage(DCCppMessage.makeTurnoutListMsg(), this); 802 } 803 break; 804 case OUTPUT: 805 for (int i = 0; i < outputModel.getRowData().size(); i++) { 806 807 List<Object> r = outputModel.getRowData().get(i); 808 boolean isnew = (boolean) r.get(6); 809 boolean isdirty = (boolean) r.get(7); 810 boolean isdelete = (boolean) r.get(8); 811 int row = outputModel.getRowData().indexOf(r); 812 if (isnew) { 813 // WARNING: Conversions here are brittle. Be careful. 814 int f = ((boolean) r.get(2) ? 1 : 0); // Invert 815 f += ((boolean) r.get(3) ? 2 : 0); // Restore 816 f += ((boolean) r.get(4) ? 4 : 0); // Force 817 _tc.sendDCCppMessage(DCCppMessage.makeOutputAddMsg((int) r.get(0), 818 (int) r.get(1), f), this); 819 outputModel.setNewRow(row, false); 820 } else if (isdelete) { 821 _tc.sendDCCppMessage(DCCppMessage.makeOutputDeleteMsg((int) r.get(0)), this); 822 outputModel.getRowData().remove(r); 823 } else if (isdirty) { 824 // Send a Delete, then an Add (for now). 825 _tc.sendDCCppMessage(DCCppMessage.makeOutputDeleteMsg((int) r.get(0)), this); 826 int f = ((boolean) r.get(2) ? 1 : 0); // Invert 827 f += ((boolean) r.get(3) ? 2 : 0); // Restore 828 f += ((boolean) r.get(4) ? 4 : 0); // Force 829 _tc.sendDCCppMessage(DCCppMessage.makeOutputAddMsg((int) r.get(0), 830 (int) r.get(1), f), this); 831 outputModel.setNewRow(row, false); 832 outputModel.setDirtyRow(row, false); 833 } 834 } 835 _tc.sendDCCppMessage(DCCppMessage.makeOutputListMsg(), this); //request updated definitions list 836 break; 837 default: 838 break; 839 } 840 } 841 842 // Offer to write the changes to EEPROM 843 int value = JmriJOptionPane.showConfirmDialog(null, Bundle.getMessage("FieldMCFCloseDialogConfirmMessage"), 844 Bundle.getMessage("FieldMCFCloseDialogTitle"), 845 JmriJOptionPane.YES_NO_OPTION); 846 847 if (value == JmriJOptionPane.YES_OPTION) { 848 _tc.sendDCCppMessage(new DCCppMessage(String.valueOf(DCCppConstants.WRITE_TO_EEPROM_CMD)), this); 849 log.debug("Sending: <E> (Write To EEPROM)"); 850 } 851 } 852 853 /** 854 * Respond to the user pressing the "Close" button. 855 * 856 * @param e the button press event 857 */ 858 private void closeButtonPressed(ActionEvent e) { 859 // If clicked while editing, stop the cell editor(s) 860 if (sensorTable.getCellEditor() != null) { 861 sensorTable.getCellEditor().stopCellEditing(); 862 } 863 if (dccTurnoutTable.getCellEditor() != null) { 864 dccTurnoutTable.getCellEditor().stopCellEditing(); 865 } 866 if (servoTurnoutTable.getCellEditor() != null) { 867 servoTurnoutTable.getCellEditor().stopCellEditing(); 868 } 869 if (vpinTurnoutTable.getCellEditor() != null) { 870 vpinTurnoutTable.getCellEditor().stopCellEditing(); 871 } 872 if (outputTable.getCellEditor() != null) { 873 outputTable.getCellEditor().stopCellEditing(); 874 } 875 876 // If clicked while changes not saved to BaseStation, offer 877 // the option of saving. 878 if (sensorModel.isDirty() || dccTurnoutModel.isDirty() || servoTurnoutModel.isDirty() 879 || vpinTurnoutModel.isDirty() || outputModel.isDirty()) { 880 int value = JmriJOptionPane.showConfirmDialog(null, Bundle.getMessage("FieldMCFSaveDialogConfirmMessage"), 881 Bundle.getMessage("ConfirmSaveDialogTitle"), 882 JmriJOptionPane.YES_NO_OPTION); 883 if (value == JmriJOptionPane.YES_OPTION) { 884 saveTableValues(); 885 } 886 887 // Offer to write the changes to EEPROM 888 value = JmriJOptionPane.showConfirmDialog(null, Bundle.getMessage("FieldMCFCloseDialogConfirmMessage"), 889 Bundle.getMessage("FieldMCFCloseDialogTitle"), 890 JmriJOptionPane.YES_NO_OPTION); 891 892 if (value == JmriJOptionPane.YES_OPTION) { 893 _tc.sendDCCppMessage(new DCCppMessage(String.valueOf(DCCppConstants.WRITE_TO_EEPROM_CMD)), this); 894 log.debug("Sending: <E> (Write To EEPROM)"); 895 } 896 897 } else { 898 JmriJOptionPane.showMessageDialog(null, Bundle.getMessage("FieldMCFCloseNoChangesDialog")); 899 } 900 901 // Close the window 902 dispose(); 903 } 904 905 private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(ConfigBaseStationFrame.class); 906 907 /** 908 * Private class to serve as TableModel for Sensors. 909 */ 910 private static class SensorTableModel extends DCCppTableModel { 911 912 public SensorTableModel() { 913 super(4, 5, 6, 7); 914 // Use i18n-ized column titles. 915 columnNames = new String[7]; 916 columnNames[0] = Bundle.getMessage("IDCol"); 917 columnNames[1] = Bundle.getMessage("FieldTablePinColumn"); 918 columnNames[2] = Bundle.getMessage("FieldTablePullupColumn"); 919 columnNames[3] = Bundle.getMessage("ColumnDelete"); 920 columnNames[4] = "isNew"; // hidden column // NOI18N 921 columnNames[5] = "isDirty"; // hidden column // NOI18N 922 columnNames[6] = "isDelete"; // hidden column // NOI18N 923 } 924 925 @Override 926 public Class<?> getColumnClass(int columnIndex) { 927 switch (columnIndex) { 928 case 0: 929 case 1: 930 return Integer.class; 931 case 2: 932 return Boolean.class; 933 case 3: 934 return ButtonEditor.class; 935 case 4: 936 case 5: 937 case 6: 938 return Boolean.class; 939 default: 940 return super.getColumnClass(columnIndex); 941 } 942 } 943 } 944 945 /** 946 * Private class to serve as TableModel for DCC Turnouts 947 */ 948 private static class DccTurnoutTableModel extends DCCppTableModel { 949 950 public DccTurnoutTableModel() { 951 super(4, 5, 6, 7); 952 // Use i18n-ized column titles. 953 columnNames = new String[7]; 954 columnNames[0] = Bundle.getMessage("IDCol"); 955 columnNames[1] = Bundle.getMessage("AddressCol"); 956 columnNames[2] = Bundle.getMessage("FieldTableSubaddrColumn"); 957 columnNames[3] = Bundle.getMessage("ColumnDelete"); 958 columnNames[4] = "isNew"; // hidden column // NOI18N 959 columnNames[5] = "isDirty"; // hidden column // NOI18N 960 columnNames[6] = "isDelete"; // hidden column // NOI18N 961 } 962 963 @Override 964 public Class<?> getColumnClass(int columnIndex) { 965 switch (columnIndex) { 966 case 0: 967 case 1: 968 case 2: 969 return Integer.class; 970 case 3: 971 return ConfigBaseStationFrame.ButtonEditor.class; 972 case 4: 973 case 5: 974 case 6: 975 return Boolean.class; 976 default: 977 return super.getColumnClass(columnIndex); 978 } 979 } 980 } 981 982 /** 983 * Private class to serve as TableModel for Servo Turnouts 984 */ 985 private static class ServoTurnoutTableModel extends DCCppTableModel { 986 987 public ServoTurnoutTableModel() { 988 super(6, 7, 8, 9); 989 // Use i18n-ized column titles. 990 columnNames = new String[9]; 991 columnNames[0] = Bundle.getMessage("IDCol"); 992 columnNames[1] = Bundle.getMessage("PinCol"); 993 columnNames[2] = Bundle.getMessage("ThrownPosCol"); 994 columnNames[3] = Bundle.getMessage("ClosedPosCol"); 995 columnNames[4] = Bundle.getMessage("ProfileCol"); 996 columnNames[5] = Bundle.getMessage("ColumnDelete"); 997 columnNames[6] = "isNew"; // hidden column // NOI18N 998 columnNames[7] = "isDirty"; // hidden column // NOI18N 999 columnNames[8] = "isDelete"; // hidden column // NOI18N 1000 } 1001 @Override 1002 public int getDeleteColumn() { 1003 return (5); 1004 } 1005 1006 @Override 1007 public Class<?> getColumnClass(int columnIndex) { 1008 switch (columnIndex) { 1009 case 0: 1010 case 1: 1011 case 2: 1012 case 3: 1013 case 4: 1014 return Integer.class; 1015 case 5: 1016 return ConfigBaseStationFrame.ButtonEditor.class; 1017 case 6: 1018 case 7: 1019 case 8: 1020 return Boolean.class; 1021 default: 1022 return super.getColumnClass(columnIndex); 1023 } 1024 } 1025 } 1026 1027 /** 1028 * Private class to serve as TableModel for Vpin Turnouts 1029 */ 1030 private static class VpinTurnoutTableModel extends DCCppTableModel { 1031 1032 public VpinTurnoutTableModel() { 1033 super(3, 4, 5, 6); 1034 // Use i18n-ized column titles. 1035 columnNames = new String[6]; 1036 columnNames[0] = Bundle.getMessage("IDCol"); 1037 columnNames[1] = Bundle.getMessage("PinCol"); 1038 columnNames[2] = Bundle.getMessage("ColumnDelete"); 1039 columnNames[3] = "isNew"; // hidden column // NOI18N 1040 columnNames[4] = "isDirty"; // hidden column // NOI18N 1041 columnNames[5] = "isDelete"; // hidden column // NOI18N 1042 } 1043 1044 @Override 1045 public int getDeleteColumn() { 1046 return (2); 1047 } 1048 1049 @Override 1050 public Class<?> getColumnClass(int columnIndex) { 1051 switch (columnIndex) { 1052 case 0: 1053 case 1: 1054 return Integer.class; 1055 case 2: 1056 return ConfigBaseStationFrame.ButtonEditor.class; 1057 case 3: 1058 case 4: 1059 case 5: 1060 return Boolean.class; 1061 default: 1062 return super.getColumnClass(columnIndex); 1063 } 1064 } 1065 } 1066 1067 /** 1068 * Private class to serve as TableModel for Outputs 1069 */ 1070 private static class OutputTableModel extends DCCppTableModel { 1071 1072 public OutputTableModel() { 1073 super(6, 7, 8, 9); 1074 // Use i18n-ized column titles. 1075 columnNames = new String[9]; 1076 columnNames[0] = Bundle.getMessage("IDCol"); 1077 columnNames[1] = Bundle.getMessage("FieldTablePinColumn"); 1078 columnNames[2] = Bundle.getMessage("FieldTableInvertColumn"); 1079 columnNames[3] = Bundle.getMessage("FieldTableOutputRestoreStateColumn"); 1080 columnNames[4] = Bundle.getMessage("FieldTableOutputForceToColumn"); 1081 columnNames[5] = Bundle.getMessage("ColumnDelete"); 1082 columnNames[6] = "isNew"; // hidden column // NOI18N 1083 columnNames[7] = "isDirty"; // hidden column // NOI18N 1084 columnNames[8] = "isDelete"; // hidden column // NOI18N 1085 } 1086 1087 @Override 1088 public int getDeleteColumn() { 1089 return (5); 1090 } 1091 1092 @Override 1093 public Class<?> getColumnClass(int columnIndex) { 1094 switch (columnIndex) { 1095 case 0: 1096 case 1: 1097 return Integer.class; 1098 case 2: 1099 case 3: 1100 case 4: 1101 return Boolean.class; 1102 case 5: 1103 return ConfigBaseStationFrame.ButtonEditor.class; 1104 case 6: 1105 case 7: 1106 case 8: 1107 return Boolean.class; 1108 default: 1109 return super.getColumnClass(columnIndex); 1110 } 1111 } 1112 } 1113 1114 static class ButtonRenderer extends JButton implements TableCellRenderer { 1115 1116 public ButtonRenderer() { 1117 super.setOpaque(true); 1118 super.setSelected(false); 1119 } 1120 1121 @Override 1122 public Component getTableCellRendererComponent(JTable table, Object value, 1123 boolean isSelected, boolean hasFocus, int row, int column) { 1124 if (isSelected) { 1125 setForeground(table.getSelectionForeground()); 1126 setBackground(table.getSelectionBackground()); 1127 } else { 1128 setForeground(table.getForeground()); 1129 setBackground(UIManager.getColor("Button.background")); 1130 } 1131 setText((value == null) ? "" : value.toString()); 1132 return this; 1133 } 1134 } 1135 1136 /** 1137 * Button Editor class to replace the DefaultCellEditor in the table for the 1138 * delete button. 1139 * <p> 1140 * NOTE: This isn't actually used anymore except as being a unique class 1141 * type that can be returned from the TableModel classes for the column that 1142 * includes the Delete buttons. 1143 */ 1144 private static class ButtonEditor extends DefaultCellEditor { 1145 1146 protected JButton button; 1147 private String label; 1148 public ButtonEditor(JCheckBox checkBox, JTable t) { 1149 super(checkBox); 1150 button = new JButton(); 1151 button.setOpaque(true); 1152 button.addActionListener((ActionEvent e) -> { 1153 //fireEditingStopped(); 1154 }); 1155 } 1156 1157 @Override 1158 public Component getTableCellEditorComponent(JTable table, Object value, 1159 boolean isSelected, int row, int column) { 1160 if (isSelected) { 1161 button.setForeground(table.getSelectionForeground()); 1162 button.setBackground(table.getSelectionBackground()); 1163 } else { 1164 button.setForeground(table.getForeground()); 1165 button.setBackground(table.getBackground()); 1166 } 1167 label = (value == null) ? "" : value.toString(); 1168 button.setText(label); 1169 return button; 1170 } 1171 1172 @Override 1173 public Object getCellEditorValue() { 1174 return label; 1175 } 1176 } 1177 1178}