001package jmri.jmrit.logixng.util.swing; 002 003import java.awt.event.ActionEvent; 004import java.util.ArrayList; 005import java.util.List; 006 007import javax.annotation.CheckForNull; 008import javax.annotation.Nonnull; 009import javax.swing.*; 010import javax.swing.table.*; 011 012import jmri.jmrit.logixng.*; 013import jmri.jmrit.logixng.util.LogixNG_SelectStringList; 014import jmri.jmrit.logixng.util.parser.ParserException; 015import jmri.util.table.ButtonEditor; 016import jmri.util.table.ButtonRenderer; 017 018/** 019 * Swing class for jmri.jmrit.logixng.util.LogixNG_SelectStringList. 020 * 021 * @author Daniel Bergqvist (C) 2025 022 */ 023public class LogixNG_SelectStringListSwing { 024 025 private JTabbedPane _tabbedPane; 026 private JTable _dataTable; 027 private StringListTableModel _dataTableModel; 028 private JPanel _panelDirect; 029 private JPanel _panelLocalVariable; 030 private JPanel _panelFormula; 031 private JTextField _localVariableTextField; 032 private JTextField _formulaTextField; 033 private JButton _addButton; 034 035 036 public JPanel createPanel(@CheckForNull LogixNG_SelectStringList selectStrList) { 037 038 JPanel panel = new JPanel(); 039 040 _tabbedPane = new JTabbedPane(); 041 _panelDirect = new javax.swing.JPanel(); 042 _panelLocalVariable = new javax.swing.JPanel(); 043 _panelFormula = new javax.swing.JPanel(); 044 if (selectStrList != null) { 045 if (selectStrList.isOnlyDirectAddressingAllowed()) { 046 _tabbedPane.setEnabled(false); 047 _panelLocalVariable.setEnabled(false); 048 _panelFormula.setEnabled(false); 049 } 050 } 051 052 _tabbedPane.addTab(NamedBeanAddressing.Direct.toString(), _panelDirect); 053 _tabbedPane.addTab(NamedBeanAddressing.LocalVariable.toString(), _panelLocalVariable); 054 _tabbedPane.addTab(NamedBeanAddressing.Formula.toString(), _panelFormula); 055 056 _dataTable = new JTable() { 057 //workaround for https://bugs.openjdk.org/browse/JDK-4127936 058 @Override 059 public boolean getScrollableTracksViewportWidth() { 060 return getRowCount() == 0 ? super.getScrollableTracksViewportWidth() 061 : getPreferredSize().width < getParent().getWidth(); 062 } 063 }; 064 065 if (selectStrList != null) { 066 _dataTableModel = new StringListTableModel(selectStrList.getList()); 067 } else { 068 _dataTableModel = new StringListTableModel(null); 069 } 070 _dataTable.setModel(_dataTableModel); 071 _dataTable.getColumnModel().getColumn(0).setPreferredWidth(200); 072 _dataTable.getColumnModel().getColumn(1).setPreferredWidth( 073 new JButton(Bundle.getMessage("LogixNG_SelectStringListSwing_ColumnVariableMoveUp")).getPreferredSize().width); 074 _dataTable.getColumnModel().getColumn(2).setPreferredWidth( 075 new JButton(Bundle.getMessage("LogixNG_SelectStringListSwing_ColumnVariableMoveDown")).getPreferredSize().width); 076 _dataTable.getColumnModel().getColumn(3).setPreferredWidth( 077 new JButton(Bundle.getMessage("LogixNG_SelectStringListSwing_ColumnVariableRemove")).getPreferredSize().width); 078 ButtonRenderer buttonRenderer = new ButtonRenderer(); 079 _dataTable.setDefaultRenderer(JButton.class, buttonRenderer); 080 TableCellEditor buttonEditor = new ButtonEditor(new JButton()); 081 _dataTable.setDefaultEditor(JButton.class, buttonEditor); 082 JScrollPane scrollPane = new JScrollPane(_dataTable); 083 scrollPane.setPreferredSize(new java.awt.Dimension(600,200)); 084 JPanel tablePanel = new JPanel(); 085 tablePanel.setLayout(new BoxLayout(tablePanel, BoxLayout.Y_AXIS)); 086 tablePanel.add(scrollPane); 087 _addButton = new JButton(Bundle.getMessage("ButtonAdd")); 088 _addButton.addActionListener(_dataTableModel::add); 089 tablePanel.add(_addButton); 090 _panelDirect.add(tablePanel); 091 092 _localVariableTextField = new JTextField(); 093 _localVariableTextField.setColumns(30); 094 _panelLocalVariable.add(_localVariableTextField); 095 096 _formulaTextField = new JTextField(); 097 _formulaTextField.setColumns(30); 098 _panelFormula.add(_formulaTextField); 099 100 101 if (selectStrList != null) { 102 switch (selectStrList.getAddressing()) { 103 case Direct: _tabbedPane.setSelectedComponent(_panelDirect); break; 104 case LocalVariable: _tabbedPane.setSelectedComponent(_panelLocalVariable); break; 105 case Formula: _tabbedPane.setSelectedComponent(_panelFormula); break; 106 default: throw new IllegalArgumentException("invalid _addressing state: " + selectStrList.getAddressing().name()); 107 } 108 _localVariableTextField.setText(selectStrList.getLocalVariable()); 109 _formulaTextField.setText(selectStrList.getFormula()); 110 } 111 112 panel.add(_tabbedPane); 113 return panel; 114 } 115 116 public boolean validate( 117 @Nonnull LogixNG_SelectStringList selectStrList, 118 @Nonnull List<String> errorMessages) { 119 120 try { 121 selectStrList.setFormula(_formulaTextField.getText()); 122 if (_tabbedPane.getSelectedComponent() == _panelDirect) { 123 selectStrList.setAddressing(NamedBeanAddressing.Direct); 124 } else if (_tabbedPane.getSelectedComponent() == _panelLocalVariable) { 125 selectStrList.setAddressing(NamedBeanAddressing.LocalVariable); 126 selectStrList.setLocalVariable(_localVariableTextField.getText()); 127 } else if (_tabbedPane.getSelectedComponent() == _panelFormula) { 128 selectStrList.setAddressing(NamedBeanAddressing.Formula); 129 selectStrList.setFormula(_formulaTextField.getText()); 130 } else { 131 throw new IllegalArgumentException("_tabbedPane has unknown selection"); 132 } 133 } catch (ParserException e) { 134 errorMessages.add("Cannot parse formula: " + e.getMessage()); 135 return false; 136 } 137 138 return errorMessages.isEmpty(); 139 } 140 141 public void setEnabled(boolean value) { 142 _tabbedPane.setEnabled(value); 143 _dataTable.setEnabled(value); 144 _localVariableTextField.setEnabled(value); 145 _formulaTextField.setEnabled(value); 146 } 147 148 public void updateObject(@Nonnull LogixNG_SelectStringList selectStrList) { 149 150 if (_tabbedPane.getSelectedComponent() == _panelDirect) { 151 List<String> list = selectStrList.getList(); 152 list.clear(); 153 list.addAll(_dataTableModel.getData()); 154 } 155 156 try { 157 if (_tabbedPane.getSelectedComponent() == _panelDirect) { 158 selectStrList.setAddressing(NamedBeanAddressing.Direct); 159 } else if (_tabbedPane.getSelectedComponent() == _panelLocalVariable) { 160 selectStrList.setAddressing(NamedBeanAddressing.LocalVariable); 161 selectStrList.setLocalVariable(_localVariableTextField.getText()); 162 } else if (_tabbedPane.getSelectedComponent() == _panelFormula) { 163 selectStrList.setAddressing(NamedBeanAddressing.Formula); 164 selectStrList.setFormula(_formulaTextField.getText()); 165 } else { 166 throw new IllegalArgumentException("_tabbedPaneEnum has unknown selection"); 167 } 168 } catch (ParserException e) { 169 throw new RuntimeException("ParserException: "+e.getMessage(), e); 170 } 171 } 172 173 public void dispose() { 174 } 175 176 177 178 179 private static class StringListTableModel extends AbstractTableModel { 180 181 public static final int COLUMN_DATA = 0; 182 public static final int COLUMN_MOVE_UP = 1; 183 public static final int COLUMN_MOVE_DOWN = 2; 184 public static final int COLUMN_REMOVE = 3; 185 186 private final List<String> _data = new ArrayList<>(); 187 188 189 public StringListTableModel(List<String> data) { 190 if (data != null) { 191 this._data.addAll(data); 192 } 193 } 194 195 /** {@inheritDoc} */ 196 @Override 197 public int getRowCount() { 198 return _data.size(); 199 } 200 201 /** {@inheritDoc} */ 202 @Override 203 public int getColumnCount() { 204 return 4; 205 } 206 207 /** {@inheritDoc} */ 208 @Override 209 public String getColumnName(int col) { 210 switch (col) { 211 case COLUMN_DATA: 212 return Bundle.getMessage("LogixNG_SelectStringListSwing_ColumnVariableData"); 213 case COLUMN_MOVE_UP: 214 return Bundle.getMessage("LogixNG_SelectStringListSwing_ColumnVariableMoveUp"); 215 case COLUMN_MOVE_DOWN: 216 return Bundle.getMessage("LogixNG_SelectStringListSwing_ColumnVariableMoveDown"); 217 case COLUMN_REMOVE: 218 return Bundle.getMessage("LogixNG_SelectStringListSwing_ColumnVariableRemove"); 219 default: 220 throw new IllegalArgumentException("Invalid column"); 221 } 222 } 223 224 /** {@inheritDoc} */ 225 @Override 226 public Class<?> getColumnClass(int col) { 227 switch (col) { 228 case COLUMN_DATA: 229 return String.class; 230 case COLUMN_MOVE_UP: 231 case COLUMN_MOVE_DOWN: 232 case COLUMN_REMOVE: 233 return JButton.class; 234 default: 235 throw new IllegalArgumentException("Invalid column"); 236 } 237 } 238 239 /** {@inheritDoc} */ 240 @Override 241 public boolean isCellEditable(int row, int col) { 242 return true; 243 } 244 245 /** {@inheritDoc} */ 246 @Override 247 public void setValueAt(Object value, int rowIndex, int columnIndex) { 248 switch (columnIndex) { 249 case COLUMN_DATA: 250 if (value != null) { 251 _data.set(rowIndex, value.toString()); 252 } else { 253 _data.set(rowIndex, ""); 254 } 255 break; 256 case COLUMN_MOVE_UP: 257 if (rowIndex > 0) { 258 String s = _data.get(rowIndex-1); 259 _data.set(rowIndex-1, _data.get(rowIndex)); 260 _data.set(rowIndex, s); 261 fireTableRowsUpdated(rowIndex-1, rowIndex); 262 } 263 break; 264 case COLUMN_MOVE_DOWN: 265 if (rowIndex < _data.size()-1) { 266 String s = _data.get(rowIndex+1); 267 _data.set(rowIndex+1, _data.get(rowIndex)); 268 _data.set(rowIndex, s); 269 fireTableRowsUpdated(rowIndex, rowIndex+1); 270 } 271 break; 272 case COLUMN_REMOVE: 273 _data.remove(rowIndex); 274 fireTableRowsDeleted(rowIndex, rowIndex); 275 break; 276 default: 277 throw new IllegalArgumentException("Invalid column"); 278 } 279 } 280 281 /** {@inheritDoc} */ 282 @Override 283 public Object getValueAt(int rowIndex, int columnIndex) { 284 if (rowIndex >= _data.size()) throw new IllegalArgumentException("Invalid row"); 285 286 switch (columnIndex) { 287 case COLUMN_DATA: 288 return _data.get(rowIndex); 289 case COLUMN_MOVE_UP: 290 return Bundle.getMessage("LogixNG_SelectStringListSwing_ColumnVariableMoveUp"); 291 case COLUMN_MOVE_DOWN: 292 return Bundle.getMessage("LogixNG_SelectStringListSwing_ColumnVariableMoveDown"); 293 case COLUMN_REMOVE: 294 return Bundle.getMessage("LogixNG_SelectStringListSwing_ColumnVariableRemove"); 295 default: 296 throw new IllegalArgumentException("Invalid column"); 297 } 298 } 299 300 public void add(ActionEvent evt) { 301 int row = _data.size(); 302 _data.add(""); 303 fireTableRowsInserted(row, row); 304 } 305 306 public List<String> getData() { 307 return _data; 308 } 309 310 } 311 312 313// private final static org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(LogixNG_SelectStringListSwing.class); 314}