001package jmri.jmrix.openlcb.swing.lccpro; 002 003import java.awt.event.ActionEvent; 004import java.awt.event.ActionListener; 005import java.util.ArrayList; 006import java.util.Enumeration; 007import java.util.EventObject; 008import java.util.List; 009 010import javax.swing.*; 011import javax.swing.table.*; 012 013import jmri.InstanceManager; 014 015import jmri.jmrix.can.CanSystemConnectionMemo; 016 017import jmri.util.gui.GuiLafPreferencesManager; 018import jmri.util.swing.JmriPanel; 019import jmri.util.swing.JmriMouseAdapter; 020import jmri.util.swing.JmriMouseEvent; 021import jmri.util.swing.JmriMouseListener; 022import jmri.util.swing.XTableColumnModel; 023import jmri.util.table.*; 024 025/** 026 * Provide a table of LCC node entries as a JmriJPanel. 027 * <p> 028 * Despite the name, this is-a JPanel, not a JTable. You 029 * access the contained JTable with the {@link #getTable()} method. 030 * 031 * @author Bob Jacobsen Copyright (C) 2003, 2010, 2024 032 * @author Randall Wood Copyright (C) 2013 033 */ 034public class LccProTable extends JmriPanel { 035 036 private LccProTableModel dataModel; 037 TableRowSorter<LccProTableModel> sorter; 038 private JTable dataTable; 039 private JScrollPane dataScroll; 040 private final XTableColumnModel columnModel = new XTableColumnModel(); 041 042 public LccProTable(CanSystemConnectionMemo memo) { 043 super(); 044 dataModel = new LccProTableModel(memo) { 045 @Override 046 public void forceFocus() { 047 requestFocus(); 048 } 049 }; 050 051 sorter = new TableRowSorter<>(dataModel); 052 dataTable = new JTable(dataModel); 053 dataTable.setRowSorter(sorter); 054 dataScroll = new JScrollPane(dataTable); 055 dataTable.setRowHeight(InstanceManager.getDefault(GuiLafPreferencesManager.class).getFontSize() + 4); 056 057 sorter.setComparator(LccProTableModel.IDCOL, new jmri.util.AlphanumComparator()); 058 059 // set initial sort 060 List<RowSorter.SortKey> sortKeys = new ArrayList<>(); 061 sortKeys.add(new RowSorter.SortKey(LccProTableModel.NAMECOL, SortOrder.ASCENDING)); 062 sorter.setSortKeys(sortKeys); 063 064 // allow reordering of the columns 065 dataTable.getTableHeader().setReorderingAllowed(true); 066 067 // have to shut off autoResizeMode to get horizontal scroll to work (JavaSwing p 541) 068 dataTable.setAutoResizeMode(JTable.AUTO_RESIZE_OFF); 069 070 dataTable.setColumnModel(columnModel); 071 dataTable.createDefaultColumnsFromModel(); 072 dataTable.setAutoCreateColumnsFromModel(false); 073 074 // resize columns as requested 075 resetColumnWidths(); 076 077 // Button rendering 078 ButtonRenderer buttonRenderer = new ButtonRenderer(); 079 columnModel.getColumn(LccProTableModel.CONFIGURECOL).setCellRenderer(buttonRenderer); 080 columnModel.getColumn(LccProTableModel.UPGRADECOL).setCellRenderer(buttonRenderer); 081 columnModel.getColumn(LccProTableModel.BACKUPCOL).setCellRenderer(buttonRenderer); 082 TableCellEditor buttonEditor = new ButtonEditor(new JButton()){ 083 // don't want keystrokes to repeatedly fire buttons 084 @Override 085 public void editingStarted(EventObject event) { 086 } 087 }; 088 dataTable.setDefaultEditor(JButton.class, buttonEditor); 089 090 // general GUI config 091 setLayout(new BoxLayout(this, BoxLayout.Y_AXIS)); 092 093 // install items in GUI 094 add(dataScroll); 095 096 // set Viewport preferred size from size of table 097 java.awt.Dimension dataTableSize = dataTable.getPreferredSize(); 098 // width is right, but if table is empty, it's not high 099 // enough to reserve much space. 100 dataTableSize.height = Math.max(dataTableSize.height, 400); 101 dataTableSize.width = Math.max(dataTableSize.width, 400); 102 dataScroll.getViewport().setPreferredSize(dataTableSize); 103 104 dataTable.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); 105 JmriMouseListener mouseHeaderListener = new TableHeaderListener(); 106 dataTable.getTableHeader().addMouseListener(JmriMouseListener.adapt(mouseHeaderListener)); 107 } 108 109 /** 110 * A LccProTable is actually a JPanel 111 * containing a JTable. This returns 112 * that contained JTable. 113 */ 114 public JTable getTable() { 115 return dataTable; 116 } 117 118 /** 119 * Provides the DataModel for the contained JTable. 120 */ 121 public LccProTableModel getModel() { 122 return dataModel; 123 } 124 125 public final void resetColumnWidths() { 126 Enumeration<TableColumn> en = columnModel.getColumns(false); 127 while (en.hasMoreElements()) { 128 TableColumn tc = en.nextElement(); 129 int width = dataModel.getPreferredWidth(tc.getModelIndex()); 130 tc.setPreferredWidth(width); 131 } 132 dataTable.sizeColumnsToFit(-1); 133 } 134 135 @Override 136 public void dispose() { 137 if (dataModel != null) { 138 dataModel.dispose(); 139 } 140 dataModel = null; 141 dataTable = null; 142 super.dispose(); 143 } 144 145 protected void showTableHeaderPopup(JmriMouseEvent e) { 146 JPopupMenu popupMenu = new JPopupMenu(); 147 for (int i = 0; i < columnModel.getColumnCount(false); i++) { 148 TableColumn tc = columnModel.getColumnByModelIndex(i); 149 JCheckBoxMenuItem menuItem = new JCheckBoxMenuItem(dataTable.getModel() 150 .getColumnName(i), columnModel.isColumnVisible(tc)); 151 menuItem.addActionListener(new HeaderActionListener(tc)); 152 popupMenu.add(menuItem); 153 154 } 155 popupMenu.show(e.getComponent(), e.getX(), e.getY()); 156 } 157 158 public void setSelectionMode(int selectionMode) { 159 dataTable.setSelectionMode(selectionMode); 160 } 161 162 public int getSelectionMode() { 163 return dataTable.getSelectionModel().getSelectionMode(); 164 } 165 166 private class HeaderActionListener implements ActionListener { 167 168 TableColumn tc; 169 170 HeaderActionListener(TableColumn tc) { 171 this.tc = tc; 172 } 173 174 @Override 175 public void actionPerformed(ActionEvent e) { 176 JCheckBoxMenuItem check = (JCheckBoxMenuItem) e.getSource(); 177 //Do not allow the last column to be hidden 178 if (!check.isSelected() && columnModel.getColumnCount(true) == 1) { 179 return; 180 } 181 columnModel.setColumnVisible(tc, check.isSelected()); 182 } 183 } 184 185 private class TableHeaderListener extends JmriMouseAdapter { 186 187 @Override 188 public void mousePressed(JmriMouseEvent e) { 189 if (e.isPopupTrigger()) { 190 showTableHeaderPopup(e); 191 } 192 } 193 194 @Override 195 public void mouseReleased(JmriMouseEvent e) { 196 if (e.isPopupTrigger()) { 197 showTableHeaderPopup(e); 198 } 199 } 200 201 @Override 202 public void mouseClicked(JmriMouseEvent e) { 203 if (e.isPopupTrigger()) { 204 showTableHeaderPopup(e); 205 } 206 } 207 } 208 209 // private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(LccProTable.class); 210 211}