001package jmri.jmrix.loconet.slotmon; 002 003import java.awt.Component; 004import java.awt.event.ActionEvent; 005import java.awt.event.ActionListener; 006import java.awt.event.ItemListener; 007import java.util.ArrayList; 008import java.util.List; 009import javax.swing.*; 010import javax.swing.event.ListSelectionEvent; 011import javax.swing.event.ListSelectionListener; 012import javax.swing.table.DefaultTableCellRenderer; 013import javax.swing.table.TableCellEditor; 014import javax.swing.table.TableColumn; 015import javax.swing.table.TableColumnModel; 016import javax.swing.table.TableRowSorter; 017 018import jmri.InstanceManager; 019import jmri.UserPreferencesManager; 020import jmri.jmrix.loconet.LnConstants; 021import jmri.jmrix.loconet.LocoNetSlot; 022import jmri.jmrix.loconet.SlotListener; 023import jmri.jmrix.loconet.SlotMapEntry.SlotType; 024import jmri.swing.JmriJTablePersistenceManager; 025import jmri.util.MenuScroller; 026import jmri.util.swing.JmriMouseAdapter; 027import jmri.util.swing.JmriMouseEvent; 028import jmri.util.swing.JmriMouseListener; 029import jmri.util.swing.WrapLayout; 030import jmri.util.swing.XTableColumnModel; 031import jmri.util.table.*; 032 033/** 034 * Frame providing a command station slot manager. 035 * <p> 036 * Slots 102 through 127 are normally not used for loco control, so are shown 037 * separately. 038 * 039 * @author Bob Jacobsen Copyright (C) 2001 040 */ 041public class SlotMonPane extends jmri.jmrix.loconet.swing.LnPanel implements SlotListener { 042 043 /** 044 * Controls whether not-in-use slots are shown 045 */ 046 protected final JCheckBox showUnusedCheckBox = new JCheckBox(); 047 /** 048 * Controls whether system slots (0, 121-127) are shown 049 */ 050 protected final JCheckBox showSystemCheckBox = new JCheckBox(); 051 052 private JLabel dcsCSLabel = new JLabel(Bundle.getMessage("SlotMonCSLabel")); 053 private JTextField dcsType = new JTextField(); 054 private JLabel dcsSlotsLabel = new JLabel(Bundle.getMessage("SlotMonTotalSlots")); 055 private JTextField dcsSlots = new JTextField(); 056 057 private final JButton estopAllButton = new JButton(Bundle.getMessage("ButtonSlotMonEStopAll")); 058 059 private JLabel inUseCount = new JLabel(" "); 060 061 //Added by Jeffrey Machacek 2013 062 private final JButton clearAllButton = new JButton(Bundle.getMessage("ButtonSlotMonClearAll")); 063 private final JButton refreshAllButton = new JButton(Bundle.getMessage("ButtonSlotRefresh")); 064 065 private JPanel topPanel; // the panel across the top that holds buttons 066 067 private SlotMonDataModel slotModel; 068 private JTable slotTable; 069 private JScrollPane slotScroll; 070 private transient TableRowSorter<SlotMonDataModel> sorter; 071 072 // Options menu 073 private JCheckBoxMenuItem optionHideTopPanel = new JCheckBoxMenuItem(Bundle.getMessage("SlotMonHideTopPanel")); 074 075 // filter menu 076 private JCheckBoxMenuItem filterShowIdle = new JCheckBoxMenuItem(Bundle.getMessage("SlotMonShowIdle")); 077 private JCheckBoxMenuItem filterShowUnUsed = new JCheckBoxMenuItem(Bundle.getMessage("TextSlotMonShowUnused")); 078 private JCheckBoxMenuItem filterShowSystem = new JCheckBoxMenuItem(Bundle.getMessage("TextSlotMonShowSystem")); 079 080 // Actions menu 081 private JMenuItem actionRefreshAll = new JMenuItem(Bundle.getMessage("ButtonSlotRefresh")); 082 private JMenuItem actionEStopAll = new JMenuItem(Bundle.getMessage("ButtonSlotMonEStopAll")); 083 private JMenuItem actionSaveFiltersAndOptions = new JMenuItem(Bundle.getMessage("SlotMonSaveFiltersAndOptions")); 084 private JMenuItem actionResetColumnsLayout = new JMenuItem(Bundle.getMessage("SlotMonResetColumnsLayout")); 085 086 // popup menu 087 private JPopupMenu popUp = new JPopupMenu(); 088 private JMenuItem popUpRefresh = new JMenuItem("Refresh"); 089 private int selectedRow = -1; 090 091 private final String slotMonHideTopPanel = this.getClass().getName() + "SlotMonHideTopPanel"; // NOI18N 092 private final String slotMonShowIdle = this.getClass().getName() + "SlotMonShowIdle"; // NOI18N 093 private final String slotMonShowUnused = this.getClass().getName() + "SlotMonShowUnused"; // NOI18N 094 private final String slotMonShowSystem = this.getClass().getName() + "SlotMonShowSystem"; // NOI18N 095 096 private void restorePreferences() { 097 UserPreferencesManager pm = InstanceManager.getDefault(UserPreferencesManager.class); 098 optionHideTopPanel.setSelected(pm.getSimplePreferenceState(slotMonHideTopPanel)); 099 filterShowIdle.setSelected(pm.getSimplePreferenceState(slotMonShowIdle)); 100 filterShowUnUsed.setSelected(pm.getSimplePreferenceState(slotMonShowUnused)); 101 filterShowSystem.setSelected(pm.getSimplePreferenceState(slotMonShowSystem)); 102 } 103 104 private void resetColumnLayout() { 105 //slotTable.getColumnModel(); 106 slotTable.createDefaultColumnsFromModel(); 107 InstanceManager.getOptionalDefault(JmriJTablePersistenceManager.class).ifPresent( tpm -> 108 tpm.cacheState(slotTable) ); 109 } 110 111 private void savePreferences() { 112 UserPreferencesManager pm = InstanceManager.getDefault(UserPreferencesManager.class); 113 pm.setSimplePreferenceState(slotMonHideTopPanel, optionHideTopPanel.isSelected()); 114 pm.setSimplePreferenceState(slotMonShowIdle, filterShowIdle.isSelected()); 115 pm.setSimplePreferenceState(slotMonShowUnused, filterShowUnUsed.isSelected()); 116 pm.setSimplePreferenceState(slotMonShowSystem, filterShowSystem.isSelected()); 117 } 118 119 public SlotMonPane() { 120 super(); 121 } 122 123 @Override 124 public boolean isMultipleInstances() { 125 return false; 126 } 127 128 private boolean runningFilterSystem = false; 129 private boolean runningFilterUnUsed = false; 130 131 @Override 132 public void initComponents(jmri.jmrix.loconet.LocoNetSystemConnectionMemo memo) { 133 super.initComponents(memo); 134 boolean hideColumnsF9toF28 = true; //(memo.getSlotManager().getLoconetProtocol() != LnConstants.LOCONETPROTOCOL_TWO); 135 slotModel = new SlotMonDataModel(memo.getSlotManager().getNumSlots(), memo); 136 slotTable = new JTable(slotModel); 137 slotTable.setColumnModel(new XTableColumnModel()); 138 slotTable.createDefaultColumnsFromModel(); 139 //XTableColumnModel SlotMonDataModel = (XTableColumnModel)slotTable.getColumnModel(); 140 141 slotTable.setName(this.getTitle()); 142 143 sorter = new TableRowSorter<>(slotModel); 144 slotTable.setRowSorter(sorter); 145 slotScroll = new JScrollPane(slotTable); 146 147 // configure items for GUI 148 showUnusedCheckBox.setText(Bundle.getMessage("TextSlotMonShowUnused")); 149 showUnusedCheckBox.setVisible(true); 150 showUnusedCheckBox.setSelected(false); 151 showUnusedCheckBox.setToolTipText(Bundle.getMessage("TooltipSlotMonShowUnused")); 152 153 showSystemCheckBox.setText(Bundle.getMessage("TextSlotMonShowSystem")); 154 showSystemCheckBox.setVisible(true); 155 showSystemCheckBox.setSelected(false); 156 showSystemCheckBox.setToolTipText(Bundle.getMessage("TooltipSlotMonShowSystem")); 157 158 // allow reordering of the columns 159 slotTable.getTableHeader().setReorderingAllowed(true); 160 161 // shut off autoResizeMode to get horizontal scroll to work (JavaSwing p 541) 162 slotTable.setAutoResizeMode(JTable.AUTO_RESIZE_OFF); 163 164 // resize columns as requested 165 for (int i = 0; i < slotTable.getColumnCount(); i++) { 166 int width = slotModel.getPreferredWidth(i); 167 slotTable.getColumnModel().getColumn(i).setPreferredWidth(width); 168 } 169 slotTable.sizeColumnsToFit(-1); 170 171 // install a button renderer & editor in the "DISP" column for freeing a slot 172 setColumnToHoldButton(slotTable, slotTable.convertColumnIndexToView(SlotMonDataModel.ColumnNumber.DISPCOLUMN.ordinal())); 173 174 // install a button renderer & editor in the "ESTOP" column for stopping a loco 175 setColumnToHoldEStopButton(slotTable, slotTable.convertColumnIndexToView(SlotMonDataModel.ColumnNumber.ESTOPCOLUMN.ordinal())); 176 177 // Install a numeric format for ConsistAddress 178 slotTable.getColumnModel().getColumn(SlotMonDataModel.ColumnNumber.CONSISTADDRESS.ordinal()).setCellRenderer(new TableRendererToBlankToNA()); 179 slotTable.getColumnModel().getColumn(slotTable.convertColumnIndexToView(SlotMonDataModel.ColumnNumber.JMRITHROTTLECOUNT.ordinal())).setCellRenderer(new TableRendererToBlankToNA()); 180 181 InstanceManager.getOptionalDefault(JmriJTablePersistenceManager.class).ifPresent((tpm) -> { 182 try { 183 tpm.persist(slotTable, true); 184 } catch (IllegalArgumentException Ex) { 185 log.warn("SlotMon Can only save layout changes for second and subsequent invocations"); 186 } 187 }); 188 189 // Hide functions F9 thru F28 if not used. 190 if (hideColumnsF9toF28) { 191 XTableColumnModel tcm = (XTableColumnModel) slotTable.getColumnModel(); 192 for (int ixCol = SlotMonDataModel.ColumnNumber.F9COLUMN.ordinal() ; 193 ixCol <= SlotMonDataModel.ColumnNumber.F28COLUMN.ordinal() ; 194 ixCol ++ ) { 195 TableColumn tc = tcm.getColumnByModelIndex(ixCol); 196 tcm.setColumnVisible(tc, false); 197 } 198 } 199 200 ActionListener refreshListener = e -> { 201 slotModel.refreshSlots(); 202 }; 203 // add listener object so checkboxes functio 204 refreshAllButton.addActionListener(refreshListener); 205 actionRefreshAll.addActionListener(refreshListener); 206 207 ItemListener filterShowSystemListen = e -> { 208 if (runningFilterSystem) { 209 return; 210 } 211 runningFilterSystem = true; 212 boolean state; 213 if (e.getSource() instanceof JCheckBox) { 214 state = ((JCheckBox) e.getSource()).isSelected(); 215 } else { 216 state = ((JCheckBoxMenuItem) e.getSource()).isSelected(); 217 } 218 filterShowSystem.setSelected(state); 219 showSystemCheckBox.setSelected(state); 220 runningFilterSystem = false; 221 filter(); 222 } ; 223 showSystemCheckBox.addItemListener(filterShowSystemListen); 224 filterShowSystem.addItemListener(filterShowSystemListen); 225 226 ItemListener filterShowUnUsedListen = e -> { 227 if (runningFilterUnUsed) { 228 return; 229 } 230 runningFilterUnUsed = true; 231 boolean state; 232 if (e.getSource() instanceof JCheckBox) { 233 state = ((JCheckBox) e.getSource()).isSelected(); 234 } else { 235 state = ((JCheckBoxMenuItem) e.getSource()).isSelected(); 236 } 237 filterShowUnUsed.setSelected(state); 238 showUnusedCheckBox.setSelected(state); 239 runningFilterUnUsed = false; 240 filter(); 241 }; 242 filterShowUnUsed.addItemListener(filterShowUnUsedListen); 243 showUnusedCheckBox.addItemListener(filterShowUnUsedListen); 244 245 // add listener object so stop all button functions 246 optionHideTopPanel.addActionListener((ActionEvent e) -> { 247 topPanel.setVisible(!optionHideTopPanel.getState()); 248 }); 249 250 estopAllButton.addActionListener((ActionEvent e) -> { 251 slotModel.estopAll(); 252 }); 253 actionEStopAll.addActionListener((ActionEvent e) -> { 254 slotModel.estopAll(); 255 }); 256 actionSaveFiltersAndOptions.addActionListener((ActionEvent e) -> { 257 savePreferences(); 258 }); 259 actionResetColumnsLayout.addActionListener((ActionEvent e) -> { 260 resetColumnLayout(); 261 }); 262 263 //Jeffrey 6/29/2013 264 clearAllButton.addActionListener((ActionEvent e) -> { 265 slotModel.clearAllSlots(); 266 }); 267 268 // adjust model to default settings 269 filter(); 270 271 // This listener is needed when there are a large number of slots being updated 272 // 273 slotTable.getSelectionModel().addListSelectionListener(new ListSelectionListener() { 274 @Override 275 public void valueChanged(ListSelectionEvent e) { 276 if (slotTable.getSelectedRow() != -1) { // Ensure a row is actually selected 277 selectedRow = slotTable.getSelectedRow(); 278 Object value = slotTable.getValueAt(selectedRow, 0); 279 log.debug("Selected Row:[{}] Value[{}]", selectedRow, value); 280 } 281 } 282 }); 283 popUp.add(popUpRefresh); 284 popUpRefresh.addActionListener((ActionEvent e) -> { 285 int row = slotTable.getSelectedRow(); 286 if (row != -1) { 287 memo.getSlotManager().sendReadSlot((int)slotTable.getValueAt(row, 0)); 288 } else { 289 String response = jmri.util.swing.JmriJOptionPane.showInputDialog(this, 290 "Enter Slot", Integer.toString(selectedRow) ); 291 try { 292 int slotNo = Integer.parseInt(response) ; 293 memo.getSlotManager().sendReadSlot(slotNo); 294 } catch (NumberFormatException ex) { 295 log.error("Non Number[{}], ignored",response); 296 } 297 } 298 }); 299 slotTable.setComponentPopupMenu(popUp); 300 301 // general GUI config 302 setLayout(new BoxLayout(this, BoxLayout.Y_AXIS)); 303 304 // install items in GUI 305 topPanel = new JPanel(); 306 topPanel.setLayout(new WrapLayout()); 307 308 topPanel.add(dcsCSLabel); 309 dcsType.setEditable(false); 310 topPanel.add(dcsType); 311 topPanel.add(dcsSlotsLabel); 312 dcsSlots.setEditable(false); 313 topPanel.add(dcsSlots); 314 showHideSlot250Data(false); 315 topPanel.add(refreshAllButton); 316 topPanel.add(showUnusedCheckBox); 317 topPanel.add(showSystemCheckBox); 318 topPanel.add(estopAllButton); 319 topPanel.add(clearAllButton); 320 topPanel.add(clearAllButton); 321 topPanel.add(new JLabel(Bundle.getMessage("SlotMonUnUseCountLabel"))); 322 topPanel.add(inUseCount); 323 324 add(topPanel); 325 add(slotScroll); 326 327 restorePreferences(); 328 329 addMouseListenerToHeader(slotTable); 330 331 332 memo.getSlotManager().addSlotListener(this); 333 334 // set top panel size 335 if (topPanel.getMaximumSize().height > 0 && topPanel.getMaximumSize().width > 0) { 336 topPanel.setMaximumSize(topPanel.getPreferredSize()); 337 } 338 topPanel.setVisible(!optionHideTopPanel.getState()); 339 } 340 341 void setColumnToHoldButton(JTable slotTable, int column) { 342 TableColumnModel tcm = slotTable.getColumnModel(); 343 // install the button renderers & editors in this column 344 ButtonRenderer buttonRenderer = new ButtonRenderer(); 345 tcm.getColumn(column).setCellRenderer(buttonRenderer); 346 // ensure the table rows, columns have enough room for buttons 347 TableCellEditor buttonEditor = new ButtonEditor(new JButton()); 348 slotTable.setDefaultEditor(JButton.class, buttonEditor); 349 slotTable.setRowHeight(new JButton(" " + slotModel.getValueAt(1, column)).getPreferredSize().height); 350 slotTable.getColumnModel().getColumn(column) 351 .setPreferredWidth(new JButton(" " + slotModel.getValueAt(1, column)).getPreferredSize().width); 352 } 353 354 355 static class TableRendererToBlankToNA extends DefaultTableCellRenderer { 356 @Override 357 public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, 358 int row, int column) { 359 if ((Integer) value == 0) { 360 setText(""); 361 } else if ((Integer) value == -1) { 362 setText(Bundle.getMessage("SlotDataNotApplicable")); 363 } else { 364 setText(Integer.toString((Integer) value)); 365 } 366 return this; 367 } 368 } 369 370 void setColumnToHoldEStopButton(JTable slotTable, int column) { 371 TableColumnModel tcm = slotTable.getColumnModel(); 372 // install the button renderers & editors in this column 373 ButtonRenderer buttonRenderer = new ButtonRenderer(); 374 tcm.getColumn(column).setCellRenderer(buttonRenderer); 375 // ensure the table rows, columns have enough room for buttons 376 TableCellEditor buttonEditor = new ButtonEditor(new JButton()); 377 slotTable.setDefaultEditor(JButton.class, buttonEditor); 378 slotTable.setRowHeight(new JButton(" " + slotModel.getValueAt(1, column)).getPreferredSize().height); 379 slotTable.getColumnModel().getColumn(column) 380 .setPreferredWidth(new JButton(" " + slotModel.getValueAt(1, column)).getPreferredSize().width); 381 } 382 383 @Override 384 public String getHelpTarget() { 385 return "package.jmri.jmrix.loconet.slotmon.SlotMonFrame"; // NOI18N 386 } 387 388 @Override 389 public String getTitle() { 390 return getTitle(Bundle.getMessage("MenuItemSlotMonitor")); 391 } 392 393 @Override 394 public void dispose() { 395 InstanceManager.getOptionalDefault(JmriJTablePersistenceManager.class).ifPresent( tpm -> 396 tpm.stopPersisting(slotTable) ); 397 savePreferences(); 398 slotModel.dispose(); 399 slotModel = null; 400 slotTable = null; 401 slotScroll = null; 402 super.dispose(); 403 } 404 405 406 private void filter() { 407 RowFilter<SlotMonDataModel, Integer> rf = new RowFilter<SlotMonDataModel, Integer>() { 408 @Override 409 public boolean include(RowFilter.Entry<? extends SlotMonDataModel, ? extends Integer> entry) { 410 // default filter is IN-USE and regular systems slot 411 // the default is whatever the person last closed it with 412 jmri.jmrix.loconet.LocoNetSlot slot = entry.getModel().getSlot(entry.getIdentifier()); 413 boolean include = entry.getModel().getSlot(entry.getIdentifier()).slotStatus() != LnConstants.LOCO_FREE 414 && slot.getSlotType() == SlotType.LOCO; 415 if (slot.getSlotType() == SlotType.UNKNOWN) { 416 return false; // dont ever show unknown 417 } 418 if (!include && showUnusedCheckBox.isSelected() && !slot.isSystemSlot()) { 419 include = true; 420 } 421 if (!include && showSystemCheckBox.isSelected() && slot.isSystemSlot()) { 422 include = true; 423 } 424 return include; 425 } 426 }; 427 sorter.setRowFilter(rf); 428 } 429 430 @Override 431 public List<JMenu> getMenus() { 432 List<JMenu> menuList = new ArrayList<>(); 433 menuList.add(getFileMenu()); 434 menuList.add(getOptionsMenu()); 435 menuList.add(getFiltersMenu()); 436 menuList.add(getActionsMenu()); 437 return menuList; 438 } 439 440 private JMenu getOptionsMenu() { 441 JMenu optionsMenu = new JMenu(Bundle.getMessage("MenuOptions")); 442 optionsMenu.add(optionHideTopPanel); 443 return optionsMenu; 444 } 445 446 private JMenu getFiltersMenu() { 447 JMenu filtersMenu = new JMenu(Bundle.getMessage("MenuFilters")); 448 filtersMenu.add(filterShowIdle); 449 filtersMenu.add(filterShowSystem); 450 filtersMenu.add(filterShowUnUsed); 451 return filtersMenu; 452 } 453 454 private JMenu getActionsMenu() { 455 JMenu actionsMenu = new JMenu(Bundle.getMessage("MenuActions")); 456 actionsMenu.add(actionRefreshAll); 457 actionsMenu.add(actionEStopAll); 458 actionsMenu.add(actionResetColumnsLayout); 459 actionsMenu.add(actionSaveFiltersAndOptions); 460 return actionsMenu; 461 } 462 463 private JMenu getFileMenu(){ 464 JMenu fileMenu = new JMenu(Bundle.getMessage("MenuFile")); // NOI18N 465 fileMenu.add(new JTableToCsvAction((Bundle.getMessage("ExportCsvAll")), 466 null, slotModel, "Slot_Monitor_All.csv", new int[]{ 467 SlotMonDataModel.ColumnNumber.ESTOPCOLUMN.ordinal()})); // NOI18N 468 fileMenu.add(new JTableToCsvAction((Bundle.getMessage("ExportCsvView")), 469 slotTable, slotModel, "Slot_Monitor_View.csv", new int[]{ 470 SlotMonDataModel.ColumnNumber.ESTOPCOLUMN.ordinal()})); // NOI18N 471 return fileMenu; 472 } 473 474 // methods to communicate with SlotManager 475 @Override 476 public synchronized void notifyChangedSlot(LocoNetSlot s) { 477 // update model from this slot 478 if (s.getSlot() == 250) { 479 if (memo.getSlotManager().getSlot250CSSlots() > 0) { 480 showHideSlot250Data(true); 481 dcsSlots.setText(Integer.toString(memo.getSlotManager().getSlot250CSSlots())); 482 dcsType.setText(memo.getSlotManager().getSlot248CommandStationType()); 483 484 // set scroll size 485 if (topPanel.getMaximumSize().height > 0 && topPanel.getMaximumSize().width > 0) { 486 topPanel.setMaximumSize(topPanel.getPreferredSize()); 487 } 488 topPanel.revalidate(); 489 490 } 491 } 492 493 // update count 494 int inUseSlotCount = 0; 495 for (var slot : memo.getSlotManager().getSlots()) { 496 if (!slot.isSystemSlot() && slot.slotStatus() == LnConstants.LOCO_IN_USE) { 497 inUseSlotCount++; 498 } 499 } 500 inUseCount.setText(""+inUseSlotCount); 501 } 502 503 void showHideSlot250Data(boolean b) { 504 dcsCSLabel.setVisible(b); 505 dcsSlots.setVisible(b); 506 dcsSlotsLabel.setVisible(b); 507 dcsType.setVisible(b); 508 // set scroll size 509 if (topPanel.getMaximumSize().height > 0 && topPanel.getMaximumSize().width > 0) { 510 topPanel.setMaximumSize(topPanel.getPreferredSize()); 511 } 512 topPanel.revalidate(); 513 } 514 515 /* 516 * Mouse popup stuff 517 */ 518 519 /** 520 * Process the column header click 521 * @param e the evnt data 522 * @param table the JTable 523 */ 524 protected void showTableHeaderPopup(JmriMouseEvent e, JTable table) { 525 JPopupMenu popupMenu = new JPopupMenu(); 526 XTableColumnModel tcm = (XTableColumnModel) table.getColumnModel(); 527 for (int i = 0; i < tcm.getColumnCount(false); i++) { 528 TableColumn tc = tcm.getColumnByModelIndex(i); 529 String columnName = table.getModel().getColumnName(i); 530 if (columnName != null && !columnName.equals("")) { 531 JCheckBoxMenuItem menuItem = new JCheckBoxMenuItem(table.getModel().getColumnName(i), tcm.isColumnVisible(tc)); 532 menuItem.addActionListener(new HeaderActionListener(tc, tcm)); 533 popupMenu.add(menuItem); 534 } 535 } 536 MenuScroller.setScrollerFor(popupMenu,10,200,0,0); 537 popupMenu.show(e.getComponent(), e.getX(), e.getY()); 538 539 } 540 541 /** 542 * Adds the column header pop listener to a JTable using XTableColumnModel 543 * @param table The JTable effected. 544 */ 545 protected void addMouseListenerToHeader(JTable table) { 546 JmriMouseListener mouseHeaderListener = new TableHeaderListener(table); 547 table.getTableHeader().addMouseListener(JmriMouseListener.adapt(mouseHeaderListener)); 548 } 549 550 protected static class HeaderActionListener implements ActionListener { 551 552 TableColumn tc; 553 XTableColumnModel tcm; 554 555 HeaderActionListener(TableColumn tc, XTableColumnModel tcm) { 556 this.tc = tc; 557 this.tcm = tcm; 558 } 559 560 @Override 561 public void actionPerformed(ActionEvent e) { 562 JCheckBoxMenuItem check = (JCheckBoxMenuItem) e.getSource(); 563 //Do not allow the last column to be hidden 564 if (!check.isSelected() && tcm.getColumnCount(true) == 1) { 565 return; 566 } 567 tcm.setColumnVisible(tc, check.isSelected()); 568 } 569 } 570 571 /** 572 * Class to support Columnheader popup menu on XTableColum model. 573 */ 574 class TableHeaderListener extends JmriMouseAdapter { 575 576 JTable table; 577 578 TableHeaderListener(JTable tbl) { 579 super(); 580 table = tbl; 581 } 582 583 /** 584 * {@inheritDoc} 585 */ 586 @Override 587 public void mousePressed(JmriMouseEvent e) { 588 if (e.isPopupTrigger()) { 589 showTableHeaderPopup(e, table); 590 } 591 } 592 593 /** 594 * {@inheritDoc} 595 */ 596 @Override 597 public void mouseReleased(JmriMouseEvent e) { 598 if (e.isPopupTrigger()) { 599 showTableHeaderPopup(e, table); 600 } 601 } 602 603 /** 604 * {@inheritDoc} 605 */ 606 @Override 607 public void mouseClicked(JmriMouseEvent e) { 608 if (e.isPopupTrigger()) { 609 showTableHeaderPopup(e, table); 610 } 611 } 612 } 613 614 private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(SlotMonPane.class); 615 616}