001package jmri.jmrit.beantable; 002 003import java.awt.event.*; 004import java.util.*; 005import java.util.List; 006 007import javax.annotation.Nonnull; 008import javax.swing.*; 009import javax.swing.table.TableColumn; 010 011import jmri.InstanceManager; 012import jmri.Manager; 013import jmri.NamedBean; 014import jmri.NamedBean.BadSystemNameException; 015import jmri.NamedBean.BadUserNameException; 016import jmri.UserPreferencesManager; 017import jmri.jmrit.logixng.Base; 018import jmri.jmrit.logixng.tools.swing.AbstractLogixNGEditor; 019import jmri.jmrit.logixng.tools.swing.DeleteBean; 020import jmri.jmrit.logixng.tools.swing.LogixNGBrowseWindow; 021import jmri.util.JmriJFrame; 022import jmri.util.swing.JmriJOptionPane; 023 024/** 025 * Swing action to create and register a LogixNG Table. 026 * <p> 027 Also contains the panes to create, edit, and delete a LogixNG. 028 <p> 029 * Most of the text used in this GUI is in BeanTableBundle.properties, accessed 030 * via Bundle.getMessage(). 031 * 032 * @author Dave Duchamp Copyright (C) 2007 (LogixTableAction) 033 * @author Pete Cressman Copyright (C) 2009, 2010, 2011 (LogixTableAction) 034 * @author Matthew Harris copyright (c) 2009 (LogixTableAction) 035 * @author Dave Sand copyright (c) 2017 (LogixTableAction) 036 * @author Daniel Bergqvist copyright (c) 2019 (AbstractLogixNGTableEditor) 037 * @author Dave Sand copyright (c) 2021 (AbstractLogixNGTableEditor) 038 * 039 * @param <E> the type of NamedBean supported by this model 040 */ 041public abstract class AbstractLogixNGTableAction<E extends NamedBean> extends AbstractTableAction<E> { 042 043 044 private static final ResourceBundle rbx = ResourceBundle.getBundle("jmri.jmrit.logixng.LogixNGBundle"); 045 private static final ResourceBundle rbx2 = ResourceBundle.getBundle("jmri.jmrit.logixng.tools.swing.LogixNGSwingBundle"); 046 047 DeleteBean<E> deleteBean = new DeleteBean<>(getManager()); 048 049 /** 050 * Create a AbstractLogixNGTableAction instance. 051 * 052 * @param s the Action title, not the title of the resulting frame. Perhaps 053 * this should be changed? 054 */ 055 public AbstractLogixNGTableAction(String s) { 056 super(s); 057 super.setEnabled(false); 058 } 059 060 protected abstract AbstractLogixNGEditor<E> getEditor(BeanTableDataModel<E> m, String sName); 061 062 protected boolean isEditSupported() { 063 return true; 064 } 065 066 @Nonnull 067 @Override 068 protected abstract Manager<E> getManager(); 069 070 protected abstract void enableAll(boolean enable); 071 072 protected abstract void setEnabled(E bean, boolean enable); 073 074 protected abstract boolean isEnabled(E bean); 075 076 protected abstract E createBean(String userName); 077 078 protected abstract E createBean(String systemName, String userName); 079 080 protected abstract void deleteBean(E bean); 081 082 protected boolean browseMonoSpace() { return false; } 083 084 protected abstract String getBeanText(E bean, Base.PrintTreeSettings printTreeSettings); 085 086 protected abstract String getBrowserTitle(); 087 088 protected abstract String getAddTitleKey(); 089 090 protected abstract String getCreateButtonHintKey(); 091 092 protected abstract void getListenerRefsIncludingChildren(E t, List<String> list); 093 094 protected abstract boolean hasChildren(E t); 095 096 // ------------ Methods for LogixNG Table Window ------------ 097 098 /** 099 * Create the JTable DataModel, along with the changes (overrides of 100 * BeanTableDataModel) for the specific case of a LogixNG table. 101 */ 102 @Override 103 protected void createModel() { 104 m = new TableModel(); 105 } 106 107 /** 108 * Set title of NamedBean table. 109 */ 110 @Override 111 protected void setTitle() { 112 f.setTitle(Bundle.getMessage("TitleLogixNGTable")); 113 } 114 115 /** 116 * Insert 2 table specific menus. 117 * <p> 118 * Accounts for the Window and Help menus, which are already added to the 119 * menu bar as part of the creation of the JFrame, by adding the new menus 2 120 * places earlier unless the table is part of the ListedTableFrame, which 121 * adds the Help menu later on. 122 * 123 * @param f the JFrame of this table 124 */ 125 @Override 126 public void setMenuBar(BeanTableFrame<E> f) { 127 JMenu menu = new JMenu(Bundle.getMessage("MenuOptions")); // NOI18N 128 menu.setMnemonic(KeyEvent.VK_O); 129 JMenuBar menuBar = f.getJMenuBar(); 130 int pos = menuBar.getMenuCount() - 1; // count the number of menus to insert the TableMenus before 'Window' and 'Help' 131 int offset = 1; 132 log.debug("setMenuBar number of menu items = {}", pos); // NOI18N 133 for (int i = 0; i <= pos; i++) { 134 if (menuBar.getComponent(i) instanceof JMenu) { 135 if (((JMenu) menuBar.getComponent(i)).getText().equals(Bundle.getMessage("MenuHelp"))) { // NOI18N 136 offset = -1; // correct for use as part of ListedTableAction where the Help Menu is not yet present 137 } 138 } 139 } 140 141 // Do not include this menu for Module or Table tables 142 if (this instanceof LogixNGTableAction) { 143 JMenuItem r = new JMenuItem(Bundle.getMessage("EnableAllLogixNGs")); // NOI18N 144 r.addActionListener((ActionEvent e) -> { 145 enableAll(true); 146 }); 147 menu.add(r); 148 149 r = new JMenuItem(Bundle.getMessage("DisableAllLogixNGs")); // NOI18N 150 r.addActionListener((ActionEvent e) -> { 151 enableAll(false); 152 }); 153 menu.add(r); 154 155 menuBar.add(menu, pos + offset); 156 offset++; 157 } 158 159 menu = new JMenu(Bundle.getMessage("MenuTools")); // NOI18N 160 menu.setMnemonic(KeyEvent.VK_T); 161 162 JMenuItem item = new JMenuItem(rbx2.getString("MenuOpenClipboard")); // NOI18N 163 item.addActionListener((ActionEvent e) -> { 164 jmri.jmrit.logixng.tools.swing.TreeEditor.openClipboard(); 165 }); 166 menu.add(item); 167 168 item = new JMenuItem(Bundle.getMessage("OpenPickListTables")); // NOI18N 169 item.addActionListener((ActionEvent e) -> { 170 openPickListTable(); 171 }); 172 menu.add(item); 173 174 menuBar.add(menu, pos + offset); // add this menu to the right of the previous 175 } 176 177 /** 178 * Open a new Pick List to drag Actions from to form NamedBean. 179 */ 180 private void openPickListTable() { 181 if (_pickTables == null) { 182 _pickTables = new jmri.jmrit.picker.PickFrame(Bundle.getMessage("TitlePickList")); // NOI18N 183 } else { 184 _pickTables.setVisible(true); 185 } 186 _pickTables.toFront(); 187 } 188 189 @Override 190 protected String helpTarget() { 191 return "package.jmri.jmrit.beantable.LogixNGTable"; // NOI18N 192 } 193 194 // ------------ variable definitions ------------ 195 196 protected AbstractLogixNGEditor<E> _editor = null; 197 198 boolean _showReminder = false; 199 jmri.jmrit.picker.PickFrame _pickTables; 200 201 // Current focus variables 202 protected E _curNamedBean = null; 203 int conditionalRowNumber = 0; 204 205 // Add E Variables 206 JmriJFrame addLogixNGFrame = null; 207 JTextField _systemName = new JTextField(20); 208 JTextField _addUserName = new JTextField(20); 209 JCheckBox _autoSystemName = new JCheckBox(Bundle.getMessage("LabelAutoSysName")); // NOI18N 210 JLabel _sysNameLabel = new JLabel(rbx.getString("BeanNameLogixNG") + " " + Bundle.getMessage("ColumnSystemName") + ":"); // NOI18N 211 JLabel _userNameLabel = new JLabel(rbx.getString("BeanNameLogixNG") + " " + Bundle.getMessage("ColumnUserName") + ":"); // NOI18N 212 String systemNameAuto = this.getClassName() + ".AutoSystemName"; // NOI18N 213 JButton create; 214 215 // Edit E Variables 216 private boolean _inEditMode = false; 217 private boolean _inCopyMode = false; 218 219 // ------------ Methods for Add bean Window ------------ 220 221 /** 222 * Respond to the Add button in bean table Creates and/or initialize 223 * the Add bean pane. 224 * 225 * @param e The event heard 226 */ 227 @Override 228 protected void addPressed(ActionEvent e) { 229 // possible change 230 if (!checkFlags(null)) { 231 return; 232 } 233 _showReminder = true; 234 // make an Add bean Frame 235 if (addLogixNGFrame == null) { 236 String titleKey = getAddTitleKey(); 237 String buttonHintKey = getCreateButtonHintKey(); 238 JPanel panel5 = makeAddFrame(titleKey, "Add"); // NOI18N 239 // Create bean 240 create = new JButton(Bundle.getMessage("ButtonCreate")); // NOI18N 241 panel5.add(create); 242 create.addActionListener(this::createPressed); 243 create.setToolTipText(Bundle.getMessage(buttonHintKey)); // NOI18N 244 } 245 addLogixNGFrame.pack(); 246 addLogixNGFrame.setVisible(true); 247 _autoSystemName.setSelected(false); 248 InstanceManager.getOptionalDefault(UserPreferencesManager.class).ifPresent((prefMgr) -> { 249 _autoSystemName.setSelected(prefMgr.getCheckboxPreferenceState(systemNameAuto, true)); 250 }); 251 } 252 253 protected abstract JPanel makeAddFrame(String titleId, String startMessageId); 254 255 /** 256 * Enable/disable fields for data entry when user selects to have system 257 * name automatically generated. 258 */ 259 void autoSystemName() { 260 if (_autoSystemName.isSelected()) { 261 _systemName.setEnabled(false); 262 _sysNameLabel.setEnabled(false); 263 } else { 264 _systemName.setEnabled(true); 265 _sysNameLabel.setEnabled(true); 266 } 267 } 268 269 /** 270 * Respond to the Cancel button in Add bean window. 271 * <p> 272 * Note: Also get there if the user closes the Add bean window. 273 * 274 * @param e The event heard 275 */ 276 void cancelAddPressed(ActionEvent e) { 277 addLogixNGFrame.setVisible(false); 278 addLogixNGFrame.dispose(); 279 addLogixNGFrame = null; 280 _inCopyMode = false; 281 if (f != null) { 282 f.setVisible(true); 283 } 284 } 285 286 /** 287 * Respond to the Copy bean button in Add bean window. 288 * <p> 289 * Provides a pane to set new properties of the copy. 290 * 291 * @param sName system name of bean to be copied 292 */ 293 void copyPressed(String sName) { 294 if (!checkFlags(sName)) { 295 return; 296 } 297 298 Runnable t = new Runnable() { 299 @Override 300 public void run() { 301// JmriJOptionPane.showMessageDialog(null, "Copy is not implemented yet.", "Error", JmriJOptionPane.ERROR_MESSAGE); 302 303 JPanel panel5 = makeAddFrame("TitleCopyLogixNG", "Copy"); // NOI18N 304 // Create bean 305 JButton create = new JButton(Bundle.getMessage("ButtonCopy")); // NOI18N 306 panel5.add(create); 307 create.addActionListener((ActionEvent e) -> { 308 copyBeanPressed(e); 309 }); 310 addLogixNGFrame.pack(); 311 addLogixNGFrame.setVisible(true); 312 _autoSystemName.setSelected(false); 313 InstanceManager.getOptionalDefault(UserPreferencesManager.class).ifPresent((prefMgr) -> { 314 _autoSystemName.setSelected(prefMgr.getCheckboxPreferenceState(systemNameAuto, true)); 315 }); 316 317 _inCopyMode = false; 318 } 319 }; 320 log.debug("copyPressed started for {}", sName); // NOI18N 321 javax.swing.SwingUtilities.invokeLater(t); 322 _inCopyMode = true; 323 _logixNGSysName = sName; 324 } 325 326 String _logixNGSysName; 327 328 protected void copyBean(@Nonnull E sourceBean, @Nonnull E targetBean) { 329 throw new UnsupportedOperationException("Not implemented"); 330 } 331 332 protected boolean isCopyBeanSupported() { 333 return false; 334 } 335 336 protected boolean isExecuteSupported() { 337 return false; 338 } 339 340 protected void execute(@Nonnull E bean) { 341 throw new UnsupportedOperationException("Not implemented"); 342 } 343 344 /** 345 * Copy the bean as configured in the Copy set up pane. 346 * 347 * @param e the event heard 348 */ 349 private void copyBeanPressed(ActionEvent e) { 350 351 String uName = _addUserName.getText().trim(); 352 if (uName.length() == 0) { 353 uName = null; 354 } 355 E targetBean; 356 if (_autoSystemName.isSelected()) { 357 if (!checkLogixNGUserName(uName)) { 358 return; 359 } 360 targetBean = createBean(uName); 361 } else { 362 if (!checkLogixNGSysName()) { 363 return; 364 } 365 String sName = _systemName.getText().trim(); 366 // check if a bean with this name already exists 367 boolean createLogix = true; 368 targetBean = getManager().getBySystemName(sName); 369 if (targetBean != null) { 370 int result = JmriJOptionPane.showConfirmDialog(f, 371 Bundle.getMessage("ConfirmLogixDuplicate", sName, _logixNGSysName), // NOI18N 372 Bundle.getMessage("QuestionTitle"), JmriJOptionPane.YES_NO_OPTION, // NOI18N 373 JmriJOptionPane.QUESTION_MESSAGE); 374 if (JmriJOptionPane.NO_OPTION == result) { 375 return; 376 } 377 createLogix = false; 378 String userName = targetBean.getUserName(); 379 if (userName != null && userName.length() > 0) { 380 _addUserName.setText(userName); 381 uName = userName; 382 } 383 } else if (!checkLogixNGUserName(uName)) { 384 return; 385 } 386 if (createLogix) { 387 // Create the new LogixNG 388 targetBean = createBean(sName, uName); 389 if (targetBean == null) { 390 // should never get here unless there is an assignment conflict 391 log.error("Failure to create LogixNG with System Name: {}", sName); // NOI18N 392 return; 393 } 394 } else if (targetBean == null) { 395 log.error("Error targetLogix is null!"); // NOI18N 396 return; 397 } else { 398 targetBean.setUserName(uName); 399 } 400 } 401 E sourceBean = getManager().getBySystemName(_logixNGSysName); 402 if (sourceBean != null) copyBean(sourceBean, targetBean); 403 else log.error("Error targetLogix is null!"); // NOI18N 404 cancelAddPressed(null); 405 } 406 407 /** 408 * Check and warn if a string is already in use as the user name of a LogixNG. 409 * 410 * @param uName the suggested name 411 * @return true if not in use 412 */ 413 boolean checkLogixNGUserName(String uName) { 414 // check if a bean with the same user name exists 415 if (uName != null && uName.trim().length() > 0) { 416 E x = getManager().getByUserName(uName); 417 if (x != null) { 418 // A bean with this user name already exists 419 JmriJOptionPane.showMessageDialog(addLogixNGFrame, 420 Bundle.getMessage("LogixNGError3"), Bundle.getMessage("ErrorTitle"), // NOI18N 421 JmriJOptionPane.ERROR_MESSAGE); 422 return false; 423 } 424 } 425 return true; 426 } 427 428 /** 429 * Check validity of various LogixNG system names. 430 * <p> 431 * Fixes name if it doesn't start with the appropriate prefix or the $ for alpha suffixes 432 * 433 * @return false if the name fails the NameValidity check 434 */ 435 boolean checkLogixNGSysName() { 436 if (_autoSystemName.isSelected()) { 437 return true; 438 } 439 440 var sName = _systemName.getText().trim(); 441 var prefix = getManager().getSubSystemNamePrefix(); 442 443 if (!sName.isEmpty() && !sName.startsWith(prefix)) { 444 var isNumber = sName.matches("^\\d+$"); 445 var hasDollar = sName.startsWith("$"); 446 447 var newName = new StringBuilder(prefix); 448 if (!isNumber && !hasDollar) { 449 newName.append("$"); 450 } 451 newName.append(sName); 452 sName = newName.toString(); 453 } 454 455 if (getManager().validSystemNameFormat(sName) != jmri.Manager.NameValidity.VALID) { 456 JmriJOptionPane.showMessageDialog(null, 457 Bundle.getMessage("LogixNGError8", sName), Bundle.getMessage("ErrorTitle"), // NOI18N 458 JmriJOptionPane.ERROR_MESSAGE); 459 return false; 460 } 461 462 _systemName.setText(sName); 463 return true; 464 } 465 466 /** 467 * Check if another bean editing session is currently open or no system 468 * name is provided. 469 * 470 * @param sName system name of bean to be copied 471 * @return true if a new session may be started 472 */ 473 boolean checkFlags(String sName) { 474 if (_inEditMode) { 475 // Already editing a bean, ask for completion of that edit 476 JmriJOptionPane.showMessageDialog(null, 477 Bundle.getMessage("LogixNGError32", _curNamedBean.getSystemName()), 478 Bundle.getMessage("ErrorTitle"), 479 JmriJOptionPane.ERROR_MESSAGE); 480 if (_editor != null) { 481 _editor.bringToFront(); 482 } 483 return false; 484 } 485 486 if (_inCopyMode) { 487 // Already editing a bean, ask for completion of that edit 488 JmriJOptionPane.showMessageDialog(null, 489 Bundle.getMessage("LogixNGError31", _logixNGSysName), 490 Bundle.getMessage("ErrorTitle"), // NOI18N 491 JmriJOptionPane.ERROR_MESSAGE); 492 return false; 493 } 494 495 if (sName != null) { 496 // check if a bean with this name exists 497 E x = getManager().getBySystemName(sName); 498 if (x == null) { 499 // bean does not exist, so cannot be edited 500 log.error("No bean with system name: {}", sName); 501 JmriJOptionPane.showMessageDialog(null, 502 Bundle.getMessage("LogixNGError5"), 503 Bundle.getMessage("ErrorTitle"), // NOI18N 504 JmriJOptionPane.ERROR_MESSAGE); 505 return false; 506 } 507 } 508 return true; 509 } 510 511 /** 512 * Respond to the Create bean button in Add bean window. 513 * 514 * @param e The event heard 515 */ 516 void createPressed(ActionEvent e) { 517 // possible change 518 _showReminder = true; 519 String sName; 520 String uName = _addUserName.getText().trim(); 521 if (uName.length() == 0) { 522 uName = null; 523 } 524 if (_autoSystemName.isSelected()) { 525 if (!checkLogixNGUserName(uName)) { 526 return; 527 } 528 try { 529 _curNamedBean = createBean(uName); 530 } catch (BadSystemNameException | BadUserNameException ex) { 531 JmriJOptionPane.showMessageDialog(addLogixNGFrame, ex.getLocalizedMessage(), 532 Bundle.getMessage("ErrorTitle"), // NOI18N 533 JmriJOptionPane.ERROR_MESSAGE); 534 return; 535 } 536 if (_curNamedBean == null) { 537 log.error("Failure to create bean with System Name: {}", "none"); // NOI18N 538 return; 539 } 540 sName = _curNamedBean.getSystemName(); 541 } else { 542 if (!checkLogixNGSysName()) { 543 return; 544 } 545 // Get validated system name 546 sName = _systemName.getText(); 547 // check if a bean with this name already exists 548 E x; 549 try { 550 x = getManager().getBySystemName(sName); 551 } catch (Exception ex) { 552 // user input no good 553 handleCreateException(sName); 554 return; // without creating 555 } 556 if (x != null) { 557 // bean already exists 558 JmriJOptionPane.showMessageDialog(addLogixNGFrame, Bundle.getMessage("LogixNGError1"), 559 Bundle.getMessage("ErrorTitle"), // NOI18N 560 JmriJOptionPane.ERROR_MESSAGE); 561 return; 562 } 563 if (!checkLogixNGUserName(uName)) { 564 return; 565 } 566 // Create the new bean 567 _curNamedBean = createBean(sName, uName); 568 if (_curNamedBean == null) { 569 // should never get here unless there is an assignment conflict 570 log.error("Failure to create bean with System Name: {}", sName); // NOI18N 571 return; 572 } 573 } 574 cancelAddPressed(null); 575 // create the Edit bean Window 576 editPressed(sName); 577 InstanceManager.getOptionalDefault(UserPreferencesManager.class).ifPresent((prefMgr) -> { 578 prefMgr.setCheckboxPreferenceState(systemNameAuto, _autoSystemName.isSelected()); 579 }); 580 } 581 582 void handleCreateException(String sysName) { 583 JmriJOptionPane.showMessageDialog(addLogixNGFrame, 584 Bundle.getMessage("ErrorLogixAddFailed", sysName), // NOI18N 585 Bundle.getMessage("ErrorTitle"), // NOI18N 586 JmriJOptionPane.ERROR_MESSAGE); 587 } 588 589 // ------------ Methods for Edit bean Pane ------------ 590 591 /** 592 * Respond to the Edit button pressed in LogixNG table. 593 * 594 * @param sName system name of LogixNG to be edited 595 */ 596 void editPressed(String sName) { 597 _curNamedBean = getManager().getBySystemName(sName); 598 if (!checkFlags(sName)) { 599 return; 600 } 601 602 // Create a new bean edit view, add the listener. 603 _editor = getEditor(m, sName); 604 605 if (_editor == null) return; // Editor not implemented yet for LogixNG Tables 606 607 _inEditMode = true; 608 609 _editor.addEditorEventListener((data) -> { 610 String lgxName = sName; 611 data.forEach((key, value) -> { 612 if (key.equals("Finish")) { // NOI18N 613 _editor = null; 614 _inEditMode = false; 615 f.setVisible(true); 616 } else if (key.equals("Delete")) { // NOI18N 617 _inEditMode = false; 618 deletePressed(value); 619 } else if (key.equals("chgUname")) { // NOI18N 620 E x = getManager().getBySystemName(lgxName); 621 if (x == null) { 622 log.error("Found no logixNG for name {} when changing user name (2)", lgxName); 623 return; 624 } 625 x.setUserName(value); 626 m.fireTableDataChanged(); 627 } 628 }); 629 }); 630 } 631 632 /** 633 * Respond to the Delete combo selection bean window delete request. 634 * 635 * @param sName system name of bean to be deleted 636 */ 637 void deletePressed(String sName) { 638 if (!checkFlags(sName)) { 639 return; 640 } 641 642 final E x = getManager().getBySystemName(sName); 643 644 if (x == null) return; // This should never happen 645 646 deleteBean.delete(x, hasChildren(x), (t)->{deleteBean(t);}, 647 (t,list)->{getListenerRefsIncludingChildren(t,list);}, 648 getClassName()); 649 } 650 651 /** 652 * Respond to the Execute combo selection bean window execute request. 653 * 654 * @param sName system name of bean to be deleted 655 */ 656 void executePressed(String sName) { 657 final E x = getManager().getBySystemName(sName); 658 659 if (x == null) return; // This should never happen 660 661 execute(x); 662 } 663 664 @Override 665 protected String getClassName() { 666 // The class that is returned must have a default constructor, 667 // a constructor with no parameters. 668 return jmri.jmrit.logixng.LogixNG_UserPreferences.class.getName(); 669 } 670 671// ------------ Methods for Conditional Browser Window ------------ 672 /** 673 * Respond to the Browse button pressed in bean table. 674 * 675 * @param sName The selected bean system name 676 */ 677 void browserPressed(String sName) { 678 // bean was found, create the window 679 _curNamedBean = getManager().getBySystemName(sName); 680 681 if (_curNamedBean == null) { 682 // This should never happen but SpotBugs complains about it. 683 throw new RuntimeException("_curNamedBean is null"); 684 } 685 686 String title = Bundle.getMessage("BrowserLogixNG") + " " + _curNamedBean.getSystemName() + " " // NOI18N 687 + _curNamedBean.getUserName() + " " 688 + (isEnabled(_curNamedBean) 689 ? Bundle.getMessage("BrowserEnabled") // NOI18N 690 : Bundle.getMessage("BrowserDisabled")); // NOI18N 691 692 LogixNGBrowseWindow browseWindow = 693 new LogixNGBrowseWindow(Bundle.getMessage("LogixNG_Browse_Title")); 694 browseWindow.getPrintTreeSettings(); 695 boolean showSettingsPanel = this instanceof LogixNGTableAction || this instanceof LogixNGModuleTableAction; 696 browseWindow.makeBrowserWindow(browseMonoSpace(), showSettingsPanel, title, _curNamedBean.getSystemName(), 697 (printTreeSettings) -> { 698 return AbstractLogixNGTableAction.this.getBeanText(_curNamedBean, printTreeSettings); 699 }); 700 } 701 702 703 704 protected class TableModel extends BeanTableDataModel<E> { 705 706 // overlay the state column with the edit column 707 static public final int ENABLECOL = VALUECOL; 708 static public final int EDITCOL = DELETECOL; 709 protected String enabledString = Bundle.getMessage("ColumnHeadEnabled"); // NOI18N 710 711 @Override 712 public String getColumnName(int col) { 713 if (col == EDITCOL) { 714 return Bundle.getMessage("ColumnHeadMenu"); // This makes it easier to test the table 715 } 716 if (col == ENABLECOL) { 717 return enabledString; 718 } 719 return super.getColumnName(col); 720 } 721 722 @Override 723 public Class<?> getColumnClass(int col) { 724 if (col == EDITCOL) { 725 return String.class; 726 } 727 if (col == ENABLECOL) { 728 return Boolean.class; 729 } 730 return super.getColumnClass(col); 731 } 732 733 @Override 734 public int getPreferredWidth(int col) { 735 // override default value for SystemName and UserName columns 736 if (col == SYSNAMECOL) { 737 return new JTextField(12).getPreferredSize().width; 738 } 739 if (col == USERNAMECOL) { 740 return new JTextField(17).getPreferredSize().width; 741 } 742 if (col == EDITCOL) { 743 return new JTextField(12).getPreferredSize().width; 744 } 745 if (col == ENABLECOL) { 746 return new JTextField(5).getPreferredSize().width; 747 } 748 return super.getPreferredWidth(col); 749 } 750 751 @Override 752 public boolean isCellEditable(int row, int col) { 753 if (col == EDITCOL) { 754 return true; 755 } 756 if (col == ENABLECOL) { 757 return true; 758 } 759 return super.isCellEditable(row, col); 760 } 761 762 @SuppressWarnings("unchecked") // Unchecked cast from Object to E 763 @Override 764 public Object getValueAt(int row, int col) { 765 if (col == EDITCOL) { 766 return Bundle.getMessage("ButtonSelect"); // NOI18N 767 } else if (col == ENABLECOL) { 768 E x = (E) getValueAt(row, SYSNAMECOL); 769 if (x == null) { 770 return null; 771 } 772 return isEnabled(x); 773 } else { 774 return super.getValueAt(row, col); 775 } 776 } 777 778 @SuppressWarnings("unchecked") // Unchecked cast from Object to E 779 @Override 780 public void setValueAt(Object value, int row, int col) { 781 if (col == EDITCOL) { 782 // set up to edit 783 String sName = ((NamedBean) getValueAt(row, SYSNAMECOL)).getSystemName(); 784 if (Bundle.getMessage("ButtonEdit").equals(value)) { // NOI18N 785 editPressed(sName); 786 787 } else if (Bundle.getMessage("BrowserButton").equals(value)) { // NOI18N 788 conditionalRowNumber = row; 789 browserPressed(sName); 790 791 } else if (Bundle.getMessage("ButtonCopy").equals(value)) { // NOI18N 792 copyPressed(sName); 793 794 } else if (Bundle.getMessage("ButtonDelete").equals(value)) { // NOI18N 795 deletePressed(sName); 796 797 } else if (Bundle.getMessage("LogixNG_ButtonExecute").equals(value)) { // NOI18N 798 executePressed(sName); 799 } 800 } else if (col == ENABLECOL) { 801 // alternate 802 E x = (E) getValueAt(row, SYSNAMECOL); 803 boolean v = isEnabled(x); 804 setEnabled(x, !v); 805 } else { 806 super.setValueAt(value, row, col); 807 } 808 } 809 810 /** 811 * Delete the bean after all the checking has been done. 812 * <p> 813 * Deletes the NamedBean. 814 * 815 * @param bean of the NamedBean to delete 816 */ 817 @Override 818 protected void doDelete(E bean) { 819 // delete the LogixNG 820 AbstractLogixNGTableAction.this.deleteBean(bean); 821 } 822 823 @Override 824 protected boolean matchPropertyName(java.beans.PropertyChangeEvent e) { 825 if (e.getPropertyName().equals(enabledString)) { 826 return true; 827 } 828 return super.matchPropertyName(e); 829 } 830 831 @Override 832 public Manager<E> getManager() { 833 return AbstractLogixNGTableAction.this.getManager(); 834 } 835 836 @Override 837 public E getBySystemName(String name) { 838 return AbstractLogixNGTableAction.this.getManager().getBySystemName(name); 839 } 840 841 @Override 842 public E getByUserName(String name) { 843 return AbstractLogixNGTableAction.this.getManager().getByUserName(name); 844 } 845 846 @Override 847 protected String getMasterClassName() { 848 return getClassName(); 849 } 850 851 @Override 852 public void configureTable(JTable table) { 853 table.setDefaultRenderer(Boolean.class, new EnablingCheckboxRenderer()); 854 table.setDefaultRenderer(JComboBox.class, new jmri.jmrit.symbolicprog.ValueRenderer()); 855 table.setDefaultEditor(JComboBox.class, new jmri.jmrit.symbolicprog.ValueEditor()); 856 if (!(getManager() instanceof jmri.jmrit.logixng.LogixNG_Manager)) { 857 table.getColumnModel().getColumn(2).setMinWidth(0); 858 table.getColumnModel().getColumn(2).setMaxWidth(0); 859 } 860 super.configureTable(table); 861 } 862 863 /** 864 * Replace delete button with comboBox to edit/delete/copy/select NamedBean. 865 * 866 * @param table name of the NamedBean JTable holding the column 867 */ 868 @Override 869 protected void configDeleteColumn(JTable table) { 870 JComboBox<String> editCombo = new JComboBox<>(); 871 editCombo.addItem(Bundle.getMessage("ButtonSelect")); // NOI18N 872 if (isEditSupported()) editCombo.addItem(Bundle.getMessage("ButtonEdit")); // NOI18N 873 editCombo.addItem(Bundle.getMessage("BrowserButton")); // NOI18N 874 if (isCopyBeanSupported()) editCombo.addItem(Bundle.getMessage("ButtonCopy")); // NOI18N 875 editCombo.addItem(Bundle.getMessage("ButtonDelete")); // NOI18N 876 if (isExecuteSupported()) editCombo.addItem(Bundle.getMessage("LogixNG_ButtonExecute")); // NOI18N 877 TableColumn col = table.getColumnModel().getColumn(BeanTableDataModel.DELETECOL); 878 col.setCellEditor(new DefaultCellEditor(editCombo)); 879 } 880 881 // Not needed - here for interface compatibility 882 @Override 883 public void clickOn(NamedBean t) { 884 } 885 886 @Override 887 public String getValue(String s) { 888 return ""; 889 } 890 891 @Override 892 protected String getBeanType() { 893// return Bundle.getMessage("BeanNameLogix"); // NOI18N 894 return rbx.getString("BeanNameLogixNG"); // NOI18N 895 } 896 } 897 898 899 private final static org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(AbstractLogixNGTableAction.class); 900 901}