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 private boolean _checkEnabled = jmri.InstanceManager.getDefault(jmri.configurexml.ShutdownPreferences.class).isStoreCheckEnabled(); 200 jmri.jmrit.picker.PickFrame _pickTables; 201 202 // Current focus variables 203 protected E _curNamedBean = null; 204 int conditionalRowNumber = 0; 205 206 // Add E Variables 207 JmriJFrame addLogixNGFrame = null; 208 JTextField _systemName = new JTextField(20); 209 JTextField _addUserName = new JTextField(20); 210 JCheckBox _autoSystemName = new JCheckBox(Bundle.getMessage("LabelAutoSysName")); // NOI18N 211 JLabel _sysNameLabel = new JLabel(rbx.getString("BeanNameLogixNG") + " " + Bundle.getMessage("ColumnSystemName") + ":"); // NOI18N 212 JLabel _userNameLabel = new JLabel(rbx.getString("BeanNameLogixNG") + " " + Bundle.getMessage("ColumnUserName") + ":"); // NOI18N 213 String systemNameAuto = this.getClassName() + ".AutoSystemName"; // NOI18N 214 JButton create; 215 216 // Edit E Variables 217 private boolean _inEditMode = false; 218 private boolean _inCopyMode = false; 219 220 // ------------ Methods for Add bean Window ------------ 221 222 /** 223 * Respond to the Add button in bean table Creates and/or initialize 224 * the Add bean pane. 225 * 226 * @param e The event heard 227 */ 228 @Override 229 protected void addPressed(ActionEvent e) { 230 // possible change 231 if (!checkFlags(null)) { 232 return; 233 } 234 _showReminder = true; 235 // make an Add bean Frame 236 if (addLogixNGFrame == null) { 237 String titleKey = getAddTitleKey(); 238 String buttonHintKey = getCreateButtonHintKey(); 239 JPanel panel5 = makeAddFrame(titleKey, "Add"); // NOI18N 240 // Create bean 241 create = new JButton(Bundle.getMessage("ButtonCreate")); // NOI18N 242 panel5.add(create); 243 create.addActionListener(this::createPressed); 244 create.setToolTipText(Bundle.getMessage(buttonHintKey)); // NOI18N 245 } 246 addLogixNGFrame.pack(); 247 addLogixNGFrame.setVisible(true); 248 _autoSystemName.setSelected(false); 249 InstanceManager.getOptionalDefault(UserPreferencesManager.class).ifPresent((prefMgr) -> { 250 _autoSystemName.setSelected(prefMgr.getCheckboxPreferenceState(systemNameAuto, true)); 251 }); 252 } 253 254 protected abstract JPanel makeAddFrame(String titleId, String startMessageId); 255 256 /** 257 * Enable/disable fields for data entry when user selects to have system 258 * name automatically generated. 259 */ 260 void autoSystemName() { 261 if (_autoSystemName.isSelected()) { 262 _systemName.setEnabled(false); 263 _sysNameLabel.setEnabled(false); 264 } else { 265 _systemName.setEnabled(true); 266 _sysNameLabel.setEnabled(true); 267 } 268 } 269 270 /** 271 * Respond to the Cancel button in Add bean window. 272 * <p> 273 * Note: Also get there if the user closes the Add bean window. 274 * 275 * @param e The event heard 276 */ 277 void cancelAddPressed(ActionEvent e) { 278 addLogixNGFrame.setVisible(false); 279 addLogixNGFrame.dispose(); 280 addLogixNGFrame = null; 281 _inCopyMode = false; 282 if (f != null) { 283 f.setVisible(true); 284 } 285 } 286 287 /** 288 * Respond to the Copy bean button in Add bean window. 289 * <p> 290 * Provides a pane to set new properties of the copy. 291 * 292 * @param sName system name of bean to be copied 293 */ 294 void copyPressed(String sName) { 295 if (!checkFlags(sName)) { 296 return; 297 } 298 299 Runnable t = new Runnable() { 300 @Override 301 public void run() { 302// JmriJOptionPane.showMessageDialog(null, "Copy is not implemented yet.", "Error", JmriJOptionPane.ERROR_MESSAGE); 303 304 JPanel panel5 = makeAddFrame("TitleCopyLogixNG", "Copy"); // NOI18N 305 // Create bean 306 JButton create = new JButton(Bundle.getMessage("ButtonCopy")); // NOI18N 307 panel5.add(create); 308 create.addActionListener((ActionEvent e) -> { 309 copyBeanPressed(e); 310 }); 311 addLogixNGFrame.pack(); 312 addLogixNGFrame.setVisible(true); 313 _autoSystemName.setSelected(false); 314 InstanceManager.getOptionalDefault(UserPreferencesManager.class).ifPresent((prefMgr) -> { 315 _autoSystemName.setSelected(prefMgr.getCheckboxPreferenceState(systemNameAuto, true)); 316 }); 317 318 _inCopyMode = false; 319 } 320 }; 321 log.debug("copyPressed started for {}", sName); // NOI18N 322 javax.swing.SwingUtilities.invokeLater(t); 323 _inCopyMode = true; 324 _logixNGSysName = sName; 325 } 326 327 String _logixNGSysName; 328 329 protected void copyBean(@Nonnull E sourceBean, @Nonnull E targetBean) { 330 throw new UnsupportedOperationException("Not implemented"); 331 } 332 333 protected boolean isCopyBeanSupported() { 334 return false; 335 } 336 337 protected boolean isExecuteSupported() { 338 return false; 339 } 340 341 protected void execute(@Nonnull E bean) { 342 throw new UnsupportedOperationException("Not implemented"); 343 } 344 345 /** 346 * Copy the bean as configured in the Copy set up pane. 347 * 348 * @param e the event heard 349 */ 350 private void copyBeanPressed(ActionEvent e) { 351 352 String uName = _addUserName.getText().trim(); 353 if (uName.length() == 0) { 354 uName = null; 355 } 356 E targetBean; 357 if (_autoSystemName.isSelected()) { 358 if (!checkLogixNGUserName(uName)) { 359 return; 360 } 361 targetBean = createBean(uName); 362 } else { 363 if (!checkLogixNGSysName()) { 364 return; 365 } 366 String sName = _systemName.getText().trim(); 367 // check if a bean with this name already exists 368 boolean createLogix = true; 369 targetBean = getManager().getBySystemName(sName); 370 if (targetBean != null) { 371 int result = JmriJOptionPane.showConfirmDialog(f, 372 Bundle.getMessage("ConfirmLogixDuplicate", sName, _logixNGSysName), // NOI18N 373 Bundle.getMessage("QuestionTitle"), JmriJOptionPane.YES_NO_OPTION, // NOI18N 374 JmriJOptionPane.QUESTION_MESSAGE); 375 if (JmriJOptionPane.NO_OPTION == result) { 376 return; 377 } 378 createLogix = false; 379 String userName = targetBean.getUserName(); 380 if (userName != null && userName.length() > 0) { 381 _addUserName.setText(userName); 382 uName = userName; 383 } 384 } else if (!checkLogixNGUserName(uName)) { 385 return; 386 } 387 if (createLogix) { 388 // Create the new LogixNG 389 targetBean = createBean(sName, uName); 390 if (targetBean == null) { 391 // should never get here unless there is an assignment conflict 392 log.error("Failure to create LogixNG with System Name: {}", sName); // NOI18N 393 return; 394 } 395 } else if (targetBean == null) { 396 log.error("Error targetLogix is null!"); // NOI18N 397 return; 398 } else { 399 targetBean.setUserName(uName); 400 } 401 } 402 E sourceBean = getManager().getBySystemName(_logixNGSysName); 403 if (sourceBean != null) copyBean(sourceBean, targetBean); 404 else log.error("Error targetLogix is null!"); // NOI18N 405 cancelAddPressed(null); 406 } 407 408 /** 409 * Check and warn if a string is already in use as the user name of a LogixNG. 410 * 411 * @param uName the suggested name 412 * @return true if not in use 413 */ 414 boolean checkLogixNGUserName(String uName) { 415 // check if a bean with the same user name exists 416 if (uName != null && uName.trim().length() > 0) { 417 E x = getManager().getByUserName(uName); 418 if (x != null) { 419 // A bean with this user name already exists 420 JmriJOptionPane.showMessageDialog(addLogixNGFrame, 421 Bundle.getMessage("LogixNGError3"), Bundle.getMessage("ErrorTitle"), // NOI18N 422 JmriJOptionPane.ERROR_MESSAGE); 423 return false; 424 } 425 } 426 return true; 427 } 428 429 /** 430 * Check validity of various LogixNG system names. 431 * <p> 432 * Fixes name if it doesn't start with the appropriate prefix or the $ for alpha suffixes 433 * 434 * @return false if the name fails the NameValidity check 435 */ 436 boolean checkLogixNGSysName() { 437 if (_autoSystemName.isSelected()) { 438 return true; 439 } 440 441 var sName = _systemName.getText().trim(); 442 var prefix = getManager().getSubSystemNamePrefix(); 443 444 if (!sName.isEmpty() && !sName.startsWith(prefix)) { 445 var isNumber = sName.matches("^\\d+$"); 446 var hasDollar = sName.startsWith("$"); 447 448 var newName = new StringBuilder(prefix); 449 if (!isNumber && !hasDollar) { 450 newName.append("$"); 451 } 452 newName.append(sName); 453 sName = newName.toString(); 454 } 455 456 if (getManager().validSystemNameFormat(sName) != jmri.Manager.NameValidity.VALID) { 457 JmriJOptionPane.showMessageDialog(null, 458 Bundle.getMessage("LogixNGError8", sName), Bundle.getMessage("ErrorTitle"), // NOI18N 459 JmriJOptionPane.ERROR_MESSAGE); 460 return false; 461 } 462 463 _systemName.setText(sName); 464 return true; 465 } 466 467 /** 468 * Check if another bean editing session is currently open or no system 469 * name is provided. 470 * 471 * @param sName system name of bean to be copied 472 * @return true if a new session may be started 473 */ 474 boolean checkFlags(String sName) { 475 if (_inEditMode) { 476 // Already editing a bean, ask for completion of that edit 477 JmriJOptionPane.showMessageDialog(null, 478 Bundle.getMessage("LogixNGError32", _curNamedBean.getSystemName()), 479 Bundle.getMessage("ErrorTitle"), 480 JmriJOptionPane.ERROR_MESSAGE); 481 if (_editor != null) { 482 _editor.bringToFront(); 483 } 484 return false; 485 } 486 487 if (_inCopyMode) { 488 // Already editing a bean, ask for completion of that edit 489 JmriJOptionPane.showMessageDialog(null, 490 Bundle.getMessage("LogixNGError31", _logixNGSysName), 491 Bundle.getMessage("ErrorTitle"), // NOI18N 492 JmriJOptionPane.ERROR_MESSAGE); 493 return false; 494 } 495 496 if (sName != null) { 497 // check if a bean with this name exists 498 E x = getManager().getBySystemName(sName); 499 if (x == null) { 500 // bean does not exist, so cannot be edited 501 log.error("No bean with system name: {}", sName); 502 JmriJOptionPane.showMessageDialog(null, 503 Bundle.getMessage("LogixNGError5"), 504 Bundle.getMessage("ErrorTitle"), // NOI18N 505 JmriJOptionPane.ERROR_MESSAGE); 506 return false; 507 } 508 } 509 return true; 510 } 511 512 /** 513 * Respond to the Create bean button in Add bean window. 514 * 515 * @param e The event heard 516 */ 517 void createPressed(ActionEvent e) { 518 // possible change 519 _showReminder = true; 520 String sName; 521 String uName = _addUserName.getText().trim(); 522 if (uName.length() == 0) { 523 uName = null; 524 } 525 if (_autoSystemName.isSelected()) { 526 if (!checkLogixNGUserName(uName)) { 527 return; 528 } 529 try { 530 _curNamedBean = createBean(uName); 531 } catch (BadSystemNameException | BadUserNameException ex) { 532 JmriJOptionPane.showMessageDialog(addLogixNGFrame, ex.getLocalizedMessage(), 533 Bundle.getMessage("ErrorTitle"), // NOI18N 534 JmriJOptionPane.ERROR_MESSAGE); 535 return; 536 } 537 if (_curNamedBean == null) { 538 log.error("Failure to create bean with System Name: {}", "none"); // NOI18N 539 return; 540 } 541 sName = _curNamedBean.getSystemName(); 542 } else { 543 if (!checkLogixNGSysName()) { 544 return; 545 } 546 // Get validated system name 547 sName = _systemName.getText(); 548 // check if a bean with this name already exists 549 E x; 550 try { 551 x = getManager().getBySystemName(sName); 552 } catch (Exception ex) { 553 // user input no good 554 handleCreateException(sName); 555 return; // without creating 556 } 557 if (x != null) { 558 // bean already exists 559 JmriJOptionPane.showMessageDialog(addLogixNGFrame, Bundle.getMessage("LogixNGError1"), 560 Bundle.getMessage("ErrorTitle"), // NOI18N 561 JmriJOptionPane.ERROR_MESSAGE); 562 return; 563 } 564 if (!checkLogixNGUserName(uName)) { 565 return; 566 } 567 // Create the new bean 568 _curNamedBean = createBean(sName, uName); 569 if (_curNamedBean == null) { 570 // should never get here unless there is an assignment conflict 571 log.error("Failure to create bean with System Name: {}", sName); // NOI18N 572 return; 573 } 574 } 575 cancelAddPressed(null); 576 // create the Edit bean Window 577 editPressed(sName); 578 InstanceManager.getOptionalDefault(UserPreferencesManager.class).ifPresent((prefMgr) -> { 579 prefMgr.setCheckboxPreferenceState(systemNameAuto, _autoSystemName.isSelected()); 580 }); 581 } 582 583 void handleCreateException(String sysName) { 584 JmriJOptionPane.showMessageDialog(addLogixNGFrame, 585 Bundle.getMessage("ErrorLogixAddFailed", sysName), // NOI18N 586 Bundle.getMessage("ErrorTitle"), // NOI18N 587 JmriJOptionPane.ERROR_MESSAGE); 588 } 589 590 // ------------ Methods for Edit bean Pane ------------ 591 592 /** 593 * Respond to the Edit button pressed in LogixNG table. 594 * 595 * @param sName system name of LogixNG to be edited 596 */ 597 void editPressed(String sName) { 598 _curNamedBean = getManager().getBySystemName(sName); 599 if (!checkFlags(sName)) { 600 return; 601 } 602 603 // Create a new bean edit view, add the listener. 604 _editor = getEditor(m, sName); 605 606 if (_editor == null) return; // Editor not implemented yet for LogixNG Tables 607 608 _inEditMode = true; 609 610 _editor.addEditorEventListener((data) -> { 611 String lgxName = sName; 612 data.forEach((key, value) -> { 613 if (key.equals("Finish")) { // NOI18N 614 _editor = null; 615 _inEditMode = false; 616 f.setVisible(true); 617 } else if (key.equals("Delete")) { // NOI18N 618 _inEditMode = false; 619 deletePressed(value); 620 } else if (key.equals("chgUname")) { // NOI18N 621 E x = getManager().getBySystemName(lgxName); 622 if (x == null) { 623 log.error("Found no logixNG for name {} when changing user name (2)", lgxName); 624 return; 625 } 626 x.setUserName(value); 627 m.fireTableDataChanged(); 628 } 629 }); 630 }); 631 } 632 633 /** 634 * Display reminder to save. 635 */ 636 void showSaveReminder() { 637 if (_showReminder && !_checkEnabled) { 638 if (InstanceManager.getNullableDefault(jmri.UserPreferencesManager.class) != null) { 639 InstanceManager.getDefault(jmri.UserPreferencesManager.class). 640 showInfoMessage(Bundle.getMessage("ReminderTitle"), Bundle.getMessage("ReminderSaveString", Bundle.getMessage("MenuItemLogixNGTable")), // NOI18N 641 getClassName(), 642 "remindSaveLogix"); // NOI18N 643 } 644 } 645 } 646 647 @Override 648 public void setMessagePreferencesDetails() { 649 HashMap<Integer, String> options = new HashMap<>(3); 650 options.put(0x00, Bundle.getMessage("DeleteAsk")); // NOI18N 651 options.put(0x01, Bundle.getMessage("DeleteNever")); // NOI18N 652 options.put(0x02, Bundle.getMessage("DeleteAlways")); // NOI18N 653 jmri.InstanceManager.getDefault(jmri.UserPreferencesManager.class).setMessageItemDetails(getClassName(), "delete", Bundle.getMessage("DeleteLogixNG"), options, 0x00); // NOI18N 654 jmri.InstanceManager.getDefault(jmri.UserPreferencesManager.class).setPreferenceItemDetails(getClassName(), "remindSaveLogixNG", Bundle.getMessage("HideSaveReminder")); // NOI18N 655 super.setMessagePreferencesDetails(); 656 } 657 658 /** 659 * Respond to the Delete combo selection bean window delete request. 660 * 661 * @param sName system name of bean to be deleted 662 */ 663 void deletePressed(String sName) { 664 if (!checkFlags(sName)) { 665 return; 666 } 667 668 final E x = getManager().getBySystemName(sName); 669 670 if (x == null) return; // This should never happen 671 672 deleteBean.delete(x, hasChildren(x), (t)->{deleteBean(t);}, 673 (t,list)->{getListenerRefsIncludingChildren(t,list);}, 674 getClassName()); 675 } 676 677 /** 678 * Respond to the Execute combo selection bean window execute request. 679 * 680 * @param sName system name of bean to be deleted 681 */ 682 void executePressed(String sName) { 683 final E x = getManager().getBySystemName(sName); 684 685 if (x == null) return; // This should never happen 686 687 execute(x); 688 } 689 690 @Override 691 public String getClassDescription() { 692 return Bundle.getMessage("TitleLogixNGTable"); // NOI18N 693 } 694 695 @Override 696 protected String getClassName() { 697 // The class that is returned must have a default constructor, 698 // a constructor with no parameters. 699 return jmri.jmrit.logixng.LogixNG_UserPreferences.class.getName(); 700 } 701 702// ------------ Methods for Conditional Browser Window ------------ 703 /** 704 * Respond to the Browse button pressed in bean table. 705 * 706 * @param sName The selected bean system name 707 */ 708 void browserPressed(String sName) { 709 // bean was found, create the window 710 _curNamedBean = getManager().getBySystemName(sName); 711 712 if (_curNamedBean == null) { 713 // This should never happen but SpotBugs complains about it. 714 throw new RuntimeException("_curNamedBean is null"); 715 } 716 717 String title = Bundle.getMessage("BrowserLogixNG") + " " + _curNamedBean.getSystemName() + " " // NOI18N 718 + _curNamedBean.getUserName() + " " 719 + (isEnabled(_curNamedBean) 720 ? Bundle.getMessage("BrowserEnabled") // NOI18N 721 : Bundle.getMessage("BrowserDisabled")); // NOI18N 722 723 LogixNGBrowseWindow browseWindow = 724 new LogixNGBrowseWindow(Bundle.getMessage("LogixNG_Browse_Title")); 725 browseWindow.getPrintTreeSettings(); 726 boolean showSettingsPanel = this instanceof LogixNGTableAction || this instanceof LogixNGModuleTableAction; 727 browseWindow.makeBrowserWindow(browseMonoSpace(), showSettingsPanel, title, _curNamedBean.getSystemName(), 728 (printTreeSettings) -> { 729 return AbstractLogixNGTableAction.this.getBeanText(_curNamedBean, printTreeSettings); 730 }); 731 } 732 733 734 735 protected class TableModel extends BeanTableDataModel<E> { 736 737 // overlay the state column with the edit column 738 static public final int ENABLECOL = VALUECOL; 739 static public final int EDITCOL = DELETECOL; 740 protected String enabledString = Bundle.getMessage("ColumnHeadEnabled"); // NOI18N 741 742 @Override 743 public String getColumnName(int col) { 744 if (col == EDITCOL) { 745 return Bundle.getMessage("ColumnHeadMenu"); // This makes it easier to test the table 746 } 747 if (col == ENABLECOL) { 748 return enabledString; 749 } 750 return super.getColumnName(col); 751 } 752 753 @Override 754 public Class<?> getColumnClass(int col) { 755 if (col == EDITCOL) { 756 return String.class; 757 } 758 if (col == ENABLECOL) { 759 return Boolean.class; 760 } 761 return super.getColumnClass(col); 762 } 763 764 @Override 765 public int getPreferredWidth(int col) { 766 // override default value for SystemName and UserName columns 767 if (col == SYSNAMECOL) { 768 return new JTextField(12).getPreferredSize().width; 769 } 770 if (col == USERNAMECOL) { 771 return new JTextField(17).getPreferredSize().width; 772 } 773 if (col == EDITCOL) { 774 return new JTextField(12).getPreferredSize().width; 775 } 776 if (col == ENABLECOL) { 777 return new JTextField(5).getPreferredSize().width; 778 } 779 return super.getPreferredWidth(col); 780 } 781 782 @Override 783 public boolean isCellEditable(int row, int col) { 784 if (col == EDITCOL) { 785 return true; 786 } 787 if (col == ENABLECOL) { 788 return true; 789 } 790 return super.isCellEditable(row, col); 791 } 792 793 @SuppressWarnings("unchecked") // Unchecked cast from Object to E 794 @Override 795 public Object getValueAt(int row, int col) { 796 if (col == EDITCOL) { 797 return Bundle.getMessage("ButtonSelect"); // NOI18N 798 } else if (col == ENABLECOL) { 799 E x = (E) getValueAt(row, SYSNAMECOL); 800 if (x == null) { 801 return null; 802 } 803 return isEnabled(x); 804 } else { 805 return super.getValueAt(row, col); 806 } 807 } 808 809 @SuppressWarnings("unchecked") // Unchecked cast from Object to E 810 @Override 811 public void setValueAt(Object value, int row, int col) { 812 if (col == EDITCOL) { 813 // set up to edit 814 String sName = ((NamedBean) getValueAt(row, SYSNAMECOL)).getSystemName(); 815 if (Bundle.getMessage("ButtonEdit").equals(value)) { // NOI18N 816 editPressed(sName); 817 818 } else if (Bundle.getMessage("BrowserButton").equals(value)) { // NOI18N 819 conditionalRowNumber = row; 820 browserPressed(sName); 821 822 } else if (Bundle.getMessage("ButtonCopy").equals(value)) { // NOI18N 823 copyPressed(sName); 824 825 } else if (Bundle.getMessage("ButtonDelete").equals(value)) { // NOI18N 826 deletePressed(sName); 827 828 } else if (Bundle.getMessage("LogixNG_ButtonExecute").equals(value)) { // NOI18N 829 executePressed(sName); 830 } 831 } else if (col == ENABLECOL) { 832 // alternate 833 E x = (E) getValueAt(row, SYSNAMECOL); 834 boolean v = isEnabled(x); 835 setEnabled(x, !v); 836 } else { 837 super.setValueAt(value, row, col); 838 } 839 } 840 841 /** 842 * Delete the bean after all the checking has been done. 843 * <p> 844 * Deletes the NamedBean. 845 * 846 * @param bean of the NamedBean to delete 847 */ 848 @Override 849 protected void doDelete(E bean) { 850 // delete the LogixNG 851 AbstractLogixNGTableAction.this.deleteBean(bean); 852 } 853 854 @Override 855 protected boolean matchPropertyName(java.beans.PropertyChangeEvent e) { 856 if (e.getPropertyName().equals(enabledString)) { 857 return true; 858 } 859 return super.matchPropertyName(e); 860 } 861 862 @Override 863 public Manager<E> getManager() { 864 return AbstractLogixNGTableAction.this.getManager(); 865 } 866 867 @Override 868 public E getBySystemName(String name) { 869 return AbstractLogixNGTableAction.this.getManager().getBySystemName(name); 870 } 871 872 @Override 873 public E getByUserName(String name) { 874 return AbstractLogixNGTableAction.this.getManager().getByUserName(name); 875 } 876 877 @Override 878 protected String getMasterClassName() { 879 return getClassName(); 880 } 881 882 @Override 883 public void configureTable(JTable table) { 884 table.setDefaultRenderer(Boolean.class, new EnablingCheckboxRenderer()); 885 table.setDefaultRenderer(JComboBox.class, new jmri.jmrit.symbolicprog.ValueRenderer()); 886 table.setDefaultEditor(JComboBox.class, new jmri.jmrit.symbolicprog.ValueEditor()); 887 if (!(getManager() instanceof jmri.jmrit.logixng.LogixNG_Manager)) { 888 table.getColumnModel().getColumn(2).setMinWidth(0); 889 table.getColumnModel().getColumn(2).setMaxWidth(0); 890 } 891 super.configureTable(table); 892 } 893 894 /** 895 * Replace delete button with comboBox to edit/delete/copy/select NamedBean. 896 * 897 * @param table name of the NamedBean JTable holding the column 898 */ 899 @Override 900 protected void configDeleteColumn(JTable table) { 901 JComboBox<String> editCombo = new JComboBox<>(); 902 editCombo.addItem(Bundle.getMessage("ButtonSelect")); // NOI18N 903 if (isEditSupported()) editCombo.addItem(Bundle.getMessage("ButtonEdit")); // NOI18N 904 editCombo.addItem(Bundle.getMessage("BrowserButton")); // NOI18N 905 if (isCopyBeanSupported()) editCombo.addItem(Bundle.getMessage("ButtonCopy")); // NOI18N 906 editCombo.addItem(Bundle.getMessage("ButtonDelete")); // NOI18N 907 if (isExecuteSupported()) editCombo.addItem(Bundle.getMessage("LogixNG_ButtonExecute")); // NOI18N 908 TableColumn col = table.getColumnModel().getColumn(BeanTableDataModel.DELETECOL); 909 col.setCellEditor(new DefaultCellEditor(editCombo)); 910 } 911 912 // Not needed - here for interface compatibility 913 @Override 914 public void clickOn(NamedBean t) { 915 } 916 917 @Override 918 public String getValue(String s) { 919 return ""; 920 } 921 922 @Override 923 protected String getBeanType() { 924// return Bundle.getMessage("BeanNameLogix"); // NOI18N 925 return rbx.getString("BeanNameLogixNG"); // NOI18N 926 } 927 } 928 929 930 private final static org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(AbstractLogixNGTableAction.class); 931 932}