001package jmri.jmrit.logixng.util.swing; 002 003import java.awt.event.WindowEvent; 004import java.awt.event.WindowFocusListener; 005import java.util.ArrayList; 006import java.util.List; 007 008import javax.annotation.CheckForNull; 009import javax.annotation.Nonnull; 010import javax.swing.*; 011import javax.swing.event.ChangeEvent; 012import javax.swing.event.ChangeListener; 013 014import jmri.*; 015import jmri.jmrit.logixng.*; 016import jmri.jmrit.logixng.swing.LogixNG_DataDialog; 017import jmri.jmrit.logixng.swing.SwingConfiguratorInterface; 018import jmri.jmrit.logixng.util.LogixNG_SelectTable; 019import jmri.jmrit.logixng.util.parser.ParserException; 020import jmri.util.swing.BeanSelectPanel; 021import jmri.util.swing.JmriJOptionPane; 022 023/** 024 * Swing class for jmri.jmrit.logixng.util.LogixNG_SelectTable. 025 * @author Daniel Bergqvist (C) 2022 026 */ 027public class LogixNG_SelectTableSwing { 028 029 private final JDialog _dialog; 030 private final LogixNG_DataDialog _logixNG_DataDialog; 031 private WindowFocusListener _focusListener; 032 033 private JLabel _tableNameLabel; 034 private JLabel _rowNameLabel; 035 private JLabel _columnNameLabel; 036 037 private JButton _selectTableNameButton; 038 private JButton _selectRowNameButton; 039 private JButton _selectColumnNameButton; 040 041 private NamedBeanAddressing _tableNameAddressing = NamedBeanAddressing.Direct; 042 private BeanSelectPanel<NamedTable> _compareToTableBeanPanel; 043 private JTextField _tableNameReferenceTextField; 044 private JTextField _tableNameLocalVariableTextField; 045 private JTextField _tableNameFormulaTextField; 046 047 private NamedBeanAddressing _tableRowAddressing = NamedBeanAddressing.Direct; 048 private JComboBox<String> _tableRowNameComboBox; 049 private JTextField _tableRowNameTextField; 050 private JTextField _tableRowReferenceTextField; 051 private JTextField _tableRowLocalVariableTextField; 052 private JTextField _tableRowFormulaTextField; 053 054 private NamedBeanAddressing _tableColumnAddressing = NamedBeanAddressing.Direct; 055 private JComboBox<String> _tableColumnNameComboBox; 056 private JTextField _tableColumnNameTextField; 057 private JTextField _tableColumnReferenceTextField; 058 private JTextField _tableColumnLocalVariableTextField; 059 private JTextField _tableColumnFormulaTextField; 060 061 private final List<ChangeListener> _changeListeners = new ArrayList<>(); 062 063 064 public LogixNG_SelectTableSwing( 065 @Nonnull JDialog dialog, @Nonnull SwingConfiguratorInterface swi) { 066 _logixNG_DataDialog = new LogixNG_DataDialog(swi); 067 _dialog = dialog; 068 } 069 070 private String getTableNameDescription() { 071 String namedBean; 072 switch (_tableNameAddressing) { 073 case Direct: 074 String tableName; 075 if (_compareToTableBeanPanel.getNamedBean() != null) { 076 tableName = _compareToTableBeanPanel.getNamedBean().getDisplayName(); 077 } else { 078 tableName = Bundle.getMessage("BeanNotSelected"); // NOI18N 079 } 080 namedBean = Bundle.getMessage("AddressByDirect", tableName); // NOI18N 081 break; 082 083 case Reference: 084 namedBean = Bundle.getMessage("AddressByReference", _tableNameReferenceTextField.getText()); // NOI18N 085 break; 086 087 case LocalVariable: 088 namedBean = Bundle.getMessage("AddressByLocalVariable", _tableNameLocalVariableTextField.getText()); // NOI18N 089 break; 090 091 case Formula: 092 namedBean = Bundle.getMessage("AddressByFormula", _tableNameFormulaTextField.getText()); // NOI18N 093 break; 094 095 default: 096 throw new IllegalArgumentException("invalid _tableNameAddressing: " + _tableNameAddressing.name()); // NOI18N 097 } 098 return Bundle.getMessage("LogixNG_SelectTableSwing_Table", namedBean); // NOI18N 099 } 100 101 private String getTableRowDescription() { 102 String row; 103 switch (_tableRowAddressing) { 104 case Direct: 105 String rowName = 106 _tableNameAddressing == NamedBeanAddressing.Direct 107 ? _tableRowNameComboBox.getItemAt(_tableRowNameComboBox.getSelectedIndex()) 108 : _tableRowNameTextField.getText(); 109 row = Bundle.getMessage("AddressByDirect", rowName); // NOI18N 110 break; 111 112 case Reference: 113 row = Bundle.getMessage("AddressByReference", _tableRowReferenceTextField.getText()); // NOI18N 114 break; 115 116 case LocalVariable: 117 row = Bundle.getMessage("AddressByLocalVariable", _tableRowLocalVariableTextField.getText()); // NOI18N 118 break; 119 120 case Formula: 121 row = Bundle.getMessage("AddressByFormula", _tableRowFormulaTextField.getText()); // NOI18N 122 break; 123 124 default: 125 throw new IllegalArgumentException("invalid _tableRowAddressing: " + _tableRowAddressing.name()); // NOI18N 126 } 127 return Bundle.getMessage("LogixNG_SelectTableSwing_Row", row); // NOI18N 128 } 129 130 private String getTableColumnDescription() { 131 String column; 132 switch (_tableColumnAddressing) { 133 case Direct: 134 String columnName = 135 _tableNameAddressing == NamedBeanAddressing.Direct 136 ? _tableColumnNameComboBox.getItemAt(_tableColumnNameComboBox.getSelectedIndex()) 137 : _tableColumnNameTextField.getText(); 138 column = Bundle.getMessage("AddressByDirect", columnName); // NOI18N 139 break; 140 141 case Reference: 142 column = Bundle.getMessage("AddressByReference", _tableColumnReferenceTextField.getText()); // NOI18N 143 break; 144 145 case LocalVariable: 146 column = Bundle.getMessage("AddressByLocalVariable", _tableColumnLocalVariableTextField.getText()); // NOI18N 147 break; 148 149 case Formula: 150 column = Bundle.getMessage("AddressByFormula", _tableColumnFormulaTextField.getText()); // NOI18N 151 break; 152 153 default: 154 throw new IllegalArgumentException("invalid _tableRowAddressing: " + _tableColumnAddressing.name()); // NOI18N 155 } 156 return Bundle.getMessage("LogixNG_SelectTableSwing_Column", column); // NOI18N 157 } 158 159 private void selectTableNameFinished() { 160 _tableNameAddressing = _logixNG_DataDialog.getAddressing(); 161 _tableNameLabel.setText(getTableNameDescription()); 162 fireChange(); 163 } 164 165 private void selectTableRowFinished() { 166 _tableRowAddressing = _logixNG_DataDialog.getAddressing(); 167 _rowNameLabel.setText(getTableRowDescription()); 168 fireChange(); 169 } 170 171 private void selectTableColumnFinished() { 172 _tableColumnAddressing = _logixNG_DataDialog.getAddressing(); 173 _columnNameLabel.setText(getTableColumnDescription()); 174 fireChange(); 175 } 176 177 private void setupRowOrColumnNameComboBox(@CheckForNull LogixNG_SelectTable selectTable) { 178 String rowName = selectTable != null ? selectTable.getTableRowName() : null; 179 String columnName = selectTable != null ? selectTable.getTableColumnName() : null; 180 181 _tableRowNameComboBox.removeAllItems(); 182 _tableColumnNameComboBox.removeAllItems(); 183 184 NamedTable table = _compareToTableBeanPanel.getNamedBean(); 185 if (table != null) { 186 for (int row=0; row <= table.numRows(); row++) { 187 // If the header is null or empty, treat the row as a comment 188 Object header = table.getCell(row, 0); 189 if ((header != null) && (!header.toString().isEmpty())) { 190 _tableRowNameComboBox.addItem(header.toString()); 191 } 192 } 193 for (int column=0; column <= table.numColumns(); column++) { 194 // If the header is null or empty, treat the row as a comment 195 Object header = table.getCell(0, column); 196 if ((header != null) && (!header.toString().isEmpty())) { 197 _tableColumnNameComboBox.addItem(header.toString()); 198 } 199 } 200 _tableRowNameComboBox.setSelectedItem(rowName); 201 _tableColumnNameComboBox.setSelectedItem(columnName); 202 } 203 } 204 205 206 public void addChangeListener(ChangeListener l) { 207 _changeListeners.add(l); 208 } 209 210 211 public void removeChangeListener(ChangeListener l) { 212 _changeListeners.remove(l); 213 } 214 215 private void fireChange() { 216 for (var l : _changeListeners) { 217 l.stateChanged(new ChangeEvent(this)); 218 } 219 } 220 221 public JPanel createPanel(@CheckForNull LogixNG_SelectTable selectTable) { 222 223 _compareToTableBeanPanel = new BeanSelectPanel<>(InstanceManager.getDefault(NamedTableManager.class), null); 224 225 _tableNameLabel = new JLabel(); 226 _rowNameLabel = new JLabel(); 227 _columnNameLabel = new JLabel(); 228 229 _tableNameAddressing = NamedBeanAddressing.Direct; 230 _compareToTableBeanPanel = new BeanSelectPanel<>(InstanceManager.getDefault(NamedTableManager.class), null); 231 _compareToTableBeanPanel.getBeanCombo().addActionListener((evt) -> { 232 setupRowOrColumnNameComboBox(selectTable); 233 }); 234 235 _tableRowNameComboBox = new JComboBox<>(); 236 _tableRowNameTextField = new JTextField(30); 237 _tableColumnNameComboBox = new JComboBox<>(); 238 _tableColumnNameTextField = new JTextField(30); 239 240 _selectTableNameButton = new JButton(Bundle.getMessage("LogixNG_SelectTableSwing_Select")); // NOI18N 241 _selectRowNameButton = new JButton(Bundle.getMessage("LogixNG_SelectTableSwing_Select")); // NOI18N 242 _selectColumnNameButton = new JButton(Bundle.getMessage("LogixNG_SelectTableSwing_Select")); // NOI18N 243 244 _tableNameReferenceTextField = new JTextField(30); 245 _tableNameLocalVariableTextField = new JTextField(30); 246 _tableNameFormulaTextField = new JTextField(30); 247 248 _tableRowReferenceTextField = new JTextField(30); 249 _tableRowLocalVariableTextField = new JTextField(30); 250 _tableRowFormulaTextField = new JTextField(30); 251 252 _tableColumnReferenceTextField = new JTextField(30); 253 _tableColumnLocalVariableTextField = new JTextField(30); 254 _tableColumnFormulaTextField = new JTextField(30); 255 256 _selectTableNameButton.addActionListener((evt) -> { 257 _logixNG_DataDialog.showDialog( 258 Bundle.getMessage("LogixNG_SelectTableSwing_SelectTable"), 259 _tableNameAddressing, 260 _compareToTableBeanPanel, 261 _tableNameReferenceTextField, 262 _tableNameLocalVariableTextField, 263 _tableNameFormulaTextField, 264 this::selectTableNameFinished); 265 }); 266 _selectRowNameButton.addActionListener((evt) -> { 267 if (_tableNameAddressing == NamedBeanAddressing.Direct) { 268 _logixNG_DataDialog.showDialog( 269 Bundle.getMessage("LogixNG_SelectTableSwing_SelectRow"), 270 _tableRowAddressing, 271 _tableRowNameComboBox, 272 _tableRowReferenceTextField, 273 _tableRowLocalVariableTextField, 274 _tableRowFormulaTextField, 275 this::selectTableRowFinished); 276 } else { 277 _logixNG_DataDialog.showDialog( 278 Bundle.getMessage("LogixNG_SelectTableSwing_SelectRow"), 279 _tableRowAddressing, 280 _tableRowNameTextField, 281 _tableRowReferenceTextField, 282 _tableRowLocalVariableTextField, 283 _tableRowFormulaTextField, 284 this::selectTableRowFinished); 285 } 286 }); 287 _selectColumnNameButton.addActionListener((evt) -> { 288 if (_tableNameAddressing == NamedBeanAddressing.Direct) { 289 _logixNG_DataDialog.showDialog( 290 Bundle.getMessage("LogixNG_SelectTableSwing_SelectColumn"), 291 _tableColumnAddressing, 292 _tableColumnNameComboBox, 293 _tableColumnReferenceTextField, 294 _tableColumnLocalVariableTextField, 295 _tableColumnFormulaTextField, 296 this::selectTableColumnFinished); 297 } else { 298 _logixNG_DataDialog.showDialog( 299 Bundle.getMessage("LogixNG_SelectTableSwing_SelectColumn"), 300 _tableColumnAddressing, 301 _tableColumnNameTextField, 302 _tableColumnReferenceTextField, 303 _tableColumnLocalVariableTextField, 304 _tableColumnFormulaTextField, 305 this::selectTableColumnFinished); 306 } 307 }); 308 309 JPanel panel = new JPanel(); 310 panel.setLayout(new java.awt.GridBagLayout()); 311 312 java.awt.GridBagConstraints constraints = new java.awt.GridBagConstraints(); 313 constraints.gridwidth = 1; 314 constraints.gridheight = 1; 315 constraints.gridx = 0; 316 constraints.gridy = 0; 317 constraints.anchor = java.awt.GridBagConstraints.EAST; 318 panel.add(_selectTableNameButton, constraints); 319 constraints.gridy = 1; 320 panel.add(_selectRowNameButton, constraints); 321 constraints.gridy = 2; 322 panel.add(_selectColumnNameButton, constraints); 323 constraints.gridx = 0; 324 constraints.gridy = 0; 325 constraints.anchor = java.awt.GridBagConstraints.WEST; 326 panel.add(_tableNameLabel, constraints); 327 constraints.gridy = 1; 328 panel.add(_rowNameLabel, constraints); 329 constraints.gridy = 2; 330 panel.add(_columnNameLabel, constraints); 331 constraints.gridx = 1; 332 constraints.gridy = 0; 333 constraints.anchor = java.awt.GridBagConstraints.WEST; 334 panel.add(new JLabel(" "), constraints); 335 constraints.gridx = 2; 336 constraints.gridy = 0; 337 constraints.anchor = java.awt.GridBagConstraints.WEST; 338 panel.add(_selectTableNameButton, constraints); 339 constraints.gridy = 1; 340 panel.add(_selectRowNameButton, constraints); 341 constraints.gridy = 2; 342 panel.add(_selectColumnNameButton, constraints); 343 344 345 if (selectTable != null) { 346 _tableNameAddressing = selectTable.getTableNameAddressing(); 347 348 switch (_tableNameAddressing) { 349 case Direct: 350 if (selectTable.getTable() != null) { 351 _compareToTableBeanPanel.setDefaultNamedBean(selectTable.getTable().getBean()); 352 } 353 break; 354 case Reference: _tableNameReferenceTextField.setText(selectTable.getTableNameReference()); break; 355 case LocalVariable: _tableNameLocalVariableTextField.setText(selectTable.getTableNameLocalVariable()); break; 356 case Formula: _tableNameFormulaTextField.setText(selectTable.getTableNameFormula()); break; 357 default: throw new IllegalArgumentException("invalid _tableNameAddressing: " + _tableNameAddressing.name()); // NOI18N 358 } 359 360 _tableRowAddressing = selectTable.getTableRowAddressing(); 361 switch (_tableRowAddressing) { 362 case Direct: 363 if (_tableNameAddressing == NamedBeanAddressing.Direct) { 364 _tableRowNameComboBox.setSelectedItem(selectTable.getTableRowName()); 365 } else { 366 _tableRowNameTextField.setText(selectTable.getTableRowName()); 367 } 368 break; 369 case Reference: _tableRowReferenceTextField.setText(selectTable.getTableRowReference()); break; 370 case LocalVariable: _tableRowLocalVariableTextField.setText(selectTable.getTableRowLocalVariable()); break; 371 case Formula: _tableRowFormulaTextField.setText(selectTable.getTableRowFormula()); break; 372 default: throw new IllegalArgumentException("invalid _tableRowAddressing: " + _tableRowAddressing.name()); // NOI18N 373 } 374 375 _tableColumnAddressing = selectTable.getTableColumnAddressing(); 376 switch (_tableColumnAddressing) { 377 case Direct: 378 if (_tableNameAddressing == NamedBeanAddressing.Direct) { 379 _tableColumnNameComboBox.setSelectedItem(selectTable.getTableColumnName()); 380 } else { 381 _tableColumnNameTextField.setText(selectTable.getTableColumnName()); 382 } 383 break; 384 case Reference: _tableColumnReferenceTextField.setText(selectTable.getTableColumnReference()); break; 385 case LocalVariable: _tableColumnLocalVariableTextField.setText(selectTable.getTableColumnLocalVariable()); break; 386 case Formula: _tableColumnFormulaTextField.setText(selectTable.getTableColumnFormula()); break; 387 default: throw new IllegalArgumentException("invalid _tableColumnAddressing: " + _tableColumnAddressing.name()); // NOI18N 388 } 389 } 390 391 _tableNameLabel.setText(getTableNameDescription()); 392 _rowNameLabel.setText(getTableRowDescription()); 393 _columnNameLabel.setText(getTableColumnDescription()); 394 395 _focusListener = new WindowFocusListener(){ 396 @Override 397 public void windowGainedFocus(WindowEvent e) { 398 _logixNG_DataDialog.checkOpenDialog(); 399 } 400 401 @Override 402 public void windowLostFocus(WindowEvent e) { 403 // Do nothing 404 } 405 }; 406 _dialog.addWindowFocusListener(_focusListener); 407 408 return panel; 409 } 410 411 public boolean validate(@Nonnull LogixNG_SelectTable selectTable, @Nonnull List<String> errorMessages) { 412 413 try { 414 switch (_tableNameAddressing) { 415 case Direct: 416 NamedTable table = _compareToTableBeanPanel.getNamedBean(); 417 if (table != null) selectTable.setTable(table); 418 else selectTable.removeTable(); 419 break; 420 case Reference: selectTable.setTableNameReference(_tableNameReferenceTextField.getText()); break; 421 case LocalVariable: selectTable.setTableNameLocalVariable(_tableNameLocalVariableTextField.getText()); break; 422 case Formula: selectTable.setTableNameFormula(_tableNameFormulaTextField.getText()); break; 423 default: throw new IllegalArgumentException("invalid _tableNameAddressing: " + _tableNameAddressing.name()); 424 } 425 426 String rowName = 427 _tableNameAddressing == NamedBeanAddressing.Direct 428 ? _tableRowNameComboBox.getItemAt(_tableRowNameComboBox.getSelectedIndex()) 429 : _tableRowNameTextField.getText(); 430 switch (_tableRowAddressing) { 431 case Direct: selectTable.setTableRowName(rowName); break; 432 case Reference: selectTable.setTableRowReference(_tableRowReferenceTextField.getText()); break; 433 case LocalVariable: selectTable.setTableRowLocalVariable(_tableRowLocalVariableTextField.getText()); break; 434 case Formula: selectTable.setTableRowFormula(_tableRowFormulaTextField.getText()); break; 435 default: throw new IllegalArgumentException("invalid _tableRowAddressing: " + _tableRowAddressing.name()); 436 } 437 438 String columnName = 439 _tableNameAddressing == NamedBeanAddressing.Direct 440 ? _tableColumnNameComboBox.getItemAt(_tableColumnNameComboBox.getSelectedIndex()) 441 : _tableColumnNameTextField.getText(); 442 switch (_tableColumnAddressing) { 443 case Direct: selectTable.setTableColumnName(columnName); break; 444 case Reference: selectTable.setTableColumnReference(_tableColumnReferenceTextField.getText()); break; 445 case LocalVariable: selectTable.setTableColumnLocalVariable(_tableColumnLocalVariableTextField.getText()); break; 446 case Formula: selectTable.setTableColumnFormula(_tableColumnFormulaTextField.getText()); break; 447 default: throw new IllegalArgumentException("invalid _tableColumnAddressing: " + _tableColumnAddressing.name()); 448 } 449 } catch (IllegalArgumentException e) { 450 errorMessages.add("Invalid value: " + e.getMessage()); 451 return false; 452 } catch (ParserException e) { 453 errorMessages.add("Cannot parse formula: " + e.getMessage()); 454 return false; 455 } 456 return true; 457 } 458 459 public void updateObject(@Nonnull LogixNG_SelectTable selectTable) { 460 461 try { 462 selectTable.setTableNameAddressing(_tableNameAddressing); 463 switch (_tableNameAddressing) { 464 case Direct: 465 NamedTable table = _compareToTableBeanPanel.getNamedBean(); 466 if (table != null) selectTable.setTable(table); 467 else selectTable.removeTable(); 468 break; 469 case Reference: selectTable.setTableNameReference(_tableNameReferenceTextField.getText()); break; 470 case LocalVariable: selectTable.setTableNameLocalVariable(_tableNameLocalVariableTextField.getText()); break; 471 case Formula: selectTable.setTableNameFormula(_tableNameFormulaTextField.getText()); break; 472 default: throw new IllegalArgumentException("invalid _tableNameAddressing: " + _tableNameAddressing.name()); 473 } 474 475 selectTable.setTableRowAddressing(_tableRowAddressing); 476 String rowName = 477 _tableNameAddressing == NamedBeanAddressing.Direct 478 ? _tableRowNameComboBox.getItemAt(_tableRowNameComboBox.getSelectedIndex()) 479 : _tableRowNameTextField.getText(); 480 switch (_tableRowAddressing) { 481 case Direct: selectTable.setTableRowName(rowName); break; 482 case Reference: selectTable.setTableRowReference(_tableRowReferenceTextField.getText()); break; 483 case LocalVariable: selectTable.setTableRowLocalVariable(_tableRowLocalVariableTextField.getText()); break; 484 case Formula: selectTable.setTableRowFormula(_tableRowFormulaTextField.getText()); break; 485 default: throw new IllegalArgumentException("invalid _tableRowAddressing: " + _tableRowAddressing.name()); 486 } 487 488 selectTable.setTableColumnAddressing(_tableColumnAddressing); 489 String columnName = 490 _tableNameAddressing == NamedBeanAddressing.Direct 491 ? _tableColumnNameComboBox.getItemAt(_tableColumnNameComboBox.getSelectedIndex()) 492 : _tableColumnNameTextField.getText(); 493 switch (_tableColumnAddressing) { 494 case Direct: selectTable.setTableColumnName(columnName); break; 495 case Reference: selectTable.setTableColumnReference(_tableColumnReferenceTextField.getText()); break; 496 case LocalVariable: selectTable.setTableColumnLocalVariable(_tableColumnLocalVariableTextField.getText()); break; 497 case Formula: selectTable.setTableColumnFormula(_tableColumnFormulaTextField.getText()); break; 498 default: throw new IllegalArgumentException("invalid _tableColumnAddressing: " + _tableColumnAddressing.name()); 499 } 500 } catch (ParserException e) { 501 throw new RuntimeException("ParserException: "+e.getMessage(), e); 502 } 503 } 504 505 /** {@inheritDoc} */ 506 @Override 507 public String toString() { 508 return Bundle.getMessage("LocalVariable_Short"); 509 } 510 511 public boolean canClose() { 512 if (_logixNG_DataDialog.checkOpenDialog()) { 513 JmriJOptionPane.showMessageDialog(_dialog, 514 Bundle.getMessage("Error_InSelectMode"), // NOI18N 515 Bundle.getMessage("ErrorTitle"), // NOI18N 516 JmriJOptionPane.ERROR_MESSAGE); 517 return false; 518 } 519 return true; 520 } 521 522 public void setEnabled(boolean enabled) { 523 _selectTableNameButton.setEnabled(enabled); 524 _selectRowNameButton.setEnabled(enabled); 525 _selectColumnNameButton.setEnabled(enabled); 526 } 527 528 public void dispose() { 529 _logixNG_DataDialog.dispose(); 530 _dialog.removeWindowFocusListener(_focusListener); 531 } 532 533}