001package jmri.jmrix.can.cbus.swing.nodeconfig; 002 003import java.awt.*; 004import java.text.DateFormat; 005import java.text.SimpleDateFormat; 006 007import javax.swing.*; 008import javax.swing.event.TableModelEvent; 009import javax.swing.table.TableCellRenderer; 010import javax.swing.table.TableRowSorter; 011 012import jmri.jmrix.can.CanSystemConnectionMemo; 013import jmri.jmrix.can.cbus.CbusConfigurationManager; 014import jmri.jmrix.can.cbus.node.CbusNodeTableDataModel; 015import jmri.jmrix.can.cbus.swing.CbusCommonSwing; 016import jmri.util.ThreadingUtil; 017import jmri.util.swing.XTableColumnModel; 018import jmri.util.table.*; 019 020/** 021 * Pane providing a CBUS node table. 022 * 023 * @author Steve Young (C) 2019 024 * @see CbusNodeTableDataModel 025 * 026 * @since 2.99.2 027 */ 028public class CbusNodeTablePane extends JPanel { 029 030 private CbusNodeTableDataModel nodeModel; 031 protected JTable nodeTable; 032 033 private final DateFormat DATE_FORMAT = new SimpleDateFormat("HH:mm EEE d MMM"); 034 035 public void initComponents(CanSystemConnectionMemo memo) { 036 nodeModel = memo.get(CbusConfigurationManager.class) 037 .provide(CbusNodeTableDataModel.class); 038 039 init(); 040 041 } 042 043 public CbusNodeTablePane() { 044 super(); 045 } 046 047 public void init() { 048 049 nodeTable = new JTableWithColumnToolTips(nodeModel,CbusNodeTableDataModel.COLUMNTOOLTIPS){ 050 051 @Override 052 public Component prepareRenderer(TableCellRenderer renderer, int row, int column) { 053 int modelRow = convertRowIndexToModel(row); 054 int modelColumn = convertColumnIndexToModel(column); 055 Component comp = super.prepareRenderer(renderer, row, column); 056 if (!isRowSelected(modelRow) && 057 ( modelColumn == CbusNodeTableDataModel.NODE_IN_LEARN_MODE_COLUMN 058 || modelColumn == CbusNodeTableDataModel.NODE_EVENT_INDEX_VALID_COLUMN 059 )) { 060 comp.setBackground(( row % 2 == 0 ) ? this.getBackground() : jmri.jmrix.can.cbus.swing.CbusCommonSwing.WHITE_GREEN ); 061 } 062 return comp; 063 } 064 }; 065 066 // Use XTableColumnModel so we can control which columns are visible 067 XTableColumnModel tcm = new XTableColumnModel(); 068 nodeTable.setColumnModel(tcm); 069 070 TableRowSorter<CbusNodeTableDataModel>sorter = new TableRowSorter<>(nodeModel); 071 nodeTable.setRowSorter(sorter); 072 073 // configure items for GUI 074 CbusCommonSwing.configureTable(nodeTable); 075 076 tcm.getColumn(CbusNodeTableDataModel.NODE_NUMBER_COLUMN).setCellRenderer(getRenderer()); 077 tcm.getColumn(CbusNodeTableDataModel.NODE_TYPE_NAME_COLUMN).setCellRenderer(getRenderer()); 078 tcm.getColumn(CbusNodeTableDataModel.NODE_USER_NAME_COLUMN).setCellRenderer(getRenderer()); 079 tcm.getColumn(CbusNodeTableDataModel.NODE_EVENTS_COLUMN).setCellRenderer(getRenderer()); 080 tcm.getColumn(CbusNodeTableDataModel.COMMAND_STAT_NUMBER_COLUMN).setCellRenderer(getRenderer()); 081 tcm.getColumn(CbusNodeTableDataModel.CANID_COLUMN).setCellRenderer(getRenderer()); 082 tcm.getColumn(CbusNodeTableDataModel.NODE_TOTAL_BYTES_COLUMN).setCellRenderer(getRenderer()); 083 tcm.getColumn(CbusNodeTableDataModel.BYTES_REMAINING_COLUMN).setCellRenderer(new ProgressCellRender(CbusCommonSwing.WHITE_GREEN)); 084 tcm.getColumn(CbusNodeTableDataModel.NUMBER_BACKUPS_COLUMN).setCellRenderer(getRenderer()); 085 tcm.getColumn(CbusNodeTableDataModel.SESSION_BACKUP_STATUS_COLUMN).setCellRenderer(getRenderer()); 086 tcm.getColumn(CbusNodeTableDataModel.LAST_BACKUP_COLUMN).setCellRenderer(getRenderer()); 087 088 tcm.getColumn(CbusNodeTableDataModel.NODE_RESYNC_BUTTON_COLUMN).setCellEditor(new ButtonEditor(new JButton())); 089 tcm.getColumn(CbusNodeTableDataModel.NODE_RESYNC_BUTTON_COLUMN).setCellRenderer(new ButtonRenderer()); 090 091 tcm.getColumn(CbusNodeTableDataModel.NODE_EDIT_BUTTON_COLUMN).setCellEditor(new ButtonEditor(new JButton())); 092 tcm.getColumn(CbusNodeTableDataModel.NODE_EDIT_BUTTON_COLUMN).setCellRenderer(new ButtonRenderer()); 093 094 ((JComponent) tcm.getColumn(CbusNodeTableDataModel.NODE_RESYNC_BUTTON_COLUMN).getCellRenderer()).setOpaque(false); 095 ((JComponent) tcm.getColumn(CbusNodeTableDataModel.NODE_EDIT_BUTTON_COLUMN).getCellRenderer()).setOpaque(false); 096 097 setLayout(new BorderLayout()); 098 JScrollPane eventScroll = new JScrollPane(nodeTable); 099 eventScroll.setVisible(true); 100 eventScroll.setPreferredSize(new Dimension(300, 40)); 101 add(eventScroll); 102 103 validate(); 104 repaint(); 105 106 nodeModel.addTableModelListener((TableModelEvent e) -> { 107 if (nodeModel.getRequestNodeRowToDisplay()>-1) { 108 setRowToNode(); 109 } 110 }); 111 nodeModel.fireTableDataChanged(); 112 } 113 114 private void setRowToNode(){ 115 ThreadingUtil.runOnGUIEventually(() -> { 116 int newRow = nodeModel.getRequestNodeRowToDisplay(); 117 if ( newRow>-1 ) { 118 nodeTable.setRowSelectionInterval(newRow, newRow); 119 nodeTable.scrollRectToVisible(nodeTable.getCellRect(newRow, 0, true)); 120 nodeModel.setRequestNodeDisplay(-1); 121 } 122 }); 123 } 124 125 /** 126 * Cell Renderer for string table columns 127 */ 128 private TableCellRenderer getRenderer() { 129 return new TableCellRenderer() { 130 JTextField f = new JTextField(); 131 132 @Override 133 public Component getTableCellRendererComponent( 134 JTable table, Object arg1, boolean isSelected, boolean hasFocus, 135 int row, int col) { 136 String string; 137 if(arg1 != null){ 138 string = arg1.toString(); 139 f.setText(string); 140 f.setHorizontalAlignment(SwingConstants.CENTER); 141 CbusCommonSwing.hideNumbersLessThan(0, string, f); 142 CbusCommonSwing.setCellFromDate(arg1,f,DATE_FORMAT); 143 CbusCommonSwing.setCellFromBackupEnum(arg1,f); 144 145 } else { 146 f.setText(""); 147 } 148 149 CbusCommonSwing.setCellBackground(isSelected, f, table,row); 150 CbusCommonSwing.setCellFocus(hasFocus, f, table); 151 152 checkDuplicateCanId(f, table, arg1, col); 153 154 return f; 155 } 156 157 private void checkDuplicateCanId(JTextField f, JTable table, Object val, int col) { 158 159 int modelCol = table.convertColumnIndexToModel(col); 160 if (( modelCol == CbusNodeTableDataModel.CANID_COLUMN ) && (val instanceof Integer )) { 161 int numCanIds = nodeModel.getNumberNodesWithCanId((int)val); 162 if ( numCanIds > 1 ) { 163 f.setBackground(CbusCommonSwing.VERY_LIGHT_RED); 164 f.setToolTipText(Bundle.getMessage("DuplicateCanIdTip")); 165 } else { 166 f.setToolTipText(null); 167 } 168 } 169 } 170 }; 171 } 172 173 public void dispose() { 174 nodeTable = null; 175 } 176 177 // private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(CbusNodeTablePane.class); 178 179}