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