001package jmri.jmrit.beantable; 002 003import java.awt.*; 004import java.awt.event.ActionEvent; 005import java.awt.event.ActionListener; 006import java.awt.event.ItemEvent; 007import java.awt.event.ItemListener; 008import java.awt.event.KeyEvent; 009import java.io.File; 010import java.io.IOException; 011import java.util.ArrayList; 012import java.util.HashMap; 013import java.util.List; 014import java.util.SortedSet; 015import java.util.TreeSet; 016 017import javax.annotation.Nonnull; 018import javax.swing.BorderFactory; 019import javax.swing.Box; 020import javax.swing.BoxLayout; 021import javax.swing.ButtonGroup; 022import javax.swing.DefaultCellEditor; 023import javax.swing.JButton; 024import javax.swing.JCheckBox; 025import javax.swing.JComboBox; 026import javax.swing.JComponent; 027import javax.swing.JDialog; 028import javax.swing.JFileChooser; 029import javax.swing.JLabel; 030import javax.swing.JMenu; 031import javax.swing.JMenuItem; 032import javax.swing.JPanel; 033import javax.swing.JRadioButtonMenuItem; 034import javax.swing.JScrollPane; 035import javax.swing.JTable; 036import javax.swing.JTextArea; 037import javax.swing.JTextField; 038import javax.swing.table.TableColumn; 039 040import jmri.*; 041import jmri.NamedBean.DisplayOptions; 042import jmri.jmrit.conditional.ConditionalEditBase; 043import jmri.jmrit.conditional.ConditionalListEdit; 044import jmri.jmrit.conditional.ConditionalTreeEdit; 045import jmri.jmrit.conditional.ConditionalListCopy; 046import jmri.jmrit.logixng.tools.ImportLogix; 047import jmri.jmrit.sensorgroup.SensorGroupFrame; 048import jmri.util.FileUtil; 049import jmri.util.JmriJFrame; 050import jmri.util.swing.JmriJOptionPane; 051 052import org.slf4j.Logger; 053import org.slf4j.LoggerFactory; 054 055/** 056 * Swing action to create and register a Logix Table. 057 * <p> 058 * Also contains the panes to create, edit, and delete a Logix. Conditional 059 * editing has been moved to ConditionalListView or CondtionalTreeView. 060 * <p> 061 * Most of the text used in this GUI is in BeanTableBundle.properties, accessed 062 * via Bundle.getMessage(). 063 * 201803 Moved all keys from LogixTableBundle.properties to 064 * BeanTableBundle.properties to simplify i18n. 065 * <p> 066 * Conditionals now have two policies to trigger execution of their action lists: 067 * <ol> 068 * <li>the previous policy - Trigger on change of state only 069 * <li>the new default - Trigger on any enabled state calculation 070 * </ol> 071 * Jan 15, 2011 - Pete Cressman 072 * <p> 073 * Two additional action and variable name selection methods have been added: 074 * <ol> 075 * <li>Single Pick List 076 * <li>Combo Box Selection 077 * </ol> 078 * The traditional tabbed Pick List with text entry is the default method. 079 * The Options menu has been expanded to list the 3 methods. 080 * Mar 27, 2017 - Dave Sand 081 * <p> 082 * Add a Browse Option to the Logix Select Menu This will display a window that 083 * creates a formatted list of the contents of the selected Logix with each 084 * Conditional, Variable and Action. The code is courtesy of Chuck Catania and 085 * is used with his permission. Apr 2, 2017 - Dave Sand 086 * 087 * @author Dave Duchamp Copyright (C) 2007 088 * @author Pete Cressman Copyright (C) 2009, 2010, 2020 089 * @author Matthew Harris copyright (c) 2009 090 * @author Dave Sand copyright (c) 2017 091 */ 092public class LogixTableAction extends AbstractTableAction<Logix> { 093 094 /** 095 * Create a LogixManager instance. 096 * 097 * @param s the Action title, not the title of the resulting frame. Perhaps 098 * this should be changed? 099 */ 100 public LogixTableAction(String s) { 101 super(s); 102 // set up managers - no need to use InstanceManager since both managers are 103 // Default only (internal). We use InstanceManager to get managers for 104 // compatibility with other facilities. 105 _logixManager = InstanceManager.getNullableDefault(jmri.LogixManager.class); 106 _conditionalManager = InstanceManager.getNullableDefault(jmri.ConditionalManager.class); 107 // disable ourself if there is no Logix manager or no Conditional manager available 108 if ((_logixManager == null) || (_conditionalManager == null)) { 109 setEnabled(false); 110 } 111 } 112 113 /** 114 * Create a LogixManager instance with default title. 115 */ 116 public LogixTableAction() { 117 this(Bundle.getMessage("TitleLogixTable")); 118 } 119 120 // ------------ Methods for Logix Table Window ------------ 121 122 /** 123 * Create the JTable DataModel, along with the changes (overrides of 124 * BeanTableDataModel) for the specific case of a Logix table. 125 */ 126 @Override 127 protected void createModel() { 128 m = new BeanTableDataModel<Logix>() { 129 // overlay the state column with the edit column 130 static public final int ENABLECOL = VALUECOL; 131 static public final int EDITCOL = DELETECOL; 132 protected String enabledString = Bundle.getMessage("ColumnHeadEnabled"); // NOI18N 133 134 @Override 135 public String getColumnName(int col) { 136 if (col == EDITCOL) { 137 return ""; // no heading on "Edit" 138 } 139 if (col == ENABLECOL) { 140 return enabledString; 141 } 142 return super.getColumnName(col); 143 } 144 145 @Override 146 public Class<?> getColumnClass(int col) { 147 if (col == EDITCOL) { 148 return String.class; 149 } 150 if (col == ENABLECOL) { 151 return Boolean.class; 152 } 153 return super.getColumnClass(col); 154 } 155 156 @Override 157 public int getPreferredWidth(int col) { 158 // override default value for SystemName and UserName columns 159 if (col == SYSNAMECOL) { 160 return new JTextField(12).getPreferredSize().width; 161 } 162 if (col == USERNAMECOL) { 163 return new JTextField(17).getPreferredSize().width; 164 } 165 if (col == EDITCOL) { 166 return new JTextField(12).getPreferredSize().width; 167 } 168 if (col == ENABLECOL) { 169 return new JTextField(5).getPreferredSize().width; 170 } 171 return super.getPreferredWidth(col); 172 } 173 174 @Override 175 public boolean isCellEditable(int row, int col) { 176 if (col == EDITCOL) { 177 return true; 178 } 179 if (col == ENABLECOL) { 180 return true; 181 } 182 return super.isCellEditable(row, col); 183 } 184 185 @Override 186 public Object getValueAt(int row, int col) { 187 if (col == EDITCOL) { 188 return Bundle.getMessage("ButtonSelect"); // NOI18N 189 } else if (col == ENABLECOL) { 190 Logix logix = (Logix) getValueAt(row, SYSNAMECOL); 191 if (logix == null) { 192 return null; 193 } 194 return Boolean.valueOf(logix.getEnabled()); 195 } else { 196 return super.getValueAt(row, col); 197 } 198 } 199 200 @Override 201 public void setValueAt(Object value, int row, int col) { 202 if (col == EDITCOL) { 203 // set up to edit 204 String sName = ((Logix) getValueAt(row, SYSNAMECOL)).getSystemName(); 205 if (Bundle.getMessage("ButtonEdit").equals(value)) { // NOI18N 206 editPressed(sName); 207 208 } else if (Bundle.getMessage("BrowserButton").equals(value)) { // NOI18N 209 conditionalRowNumber = row; 210 browserPressed(sName); 211 212 } else if (Bundle.getMessage("ButtonCopy").equals(value)) { // NOI18N 213 copyPressed(sName); 214 215 } else if (Bundle.getMessage("ButtonDelete").equals(value)) { // NOI18N 216 deletePressed(sName); 217 } else if (Bundle.getMessage("ButtonExportLogixToLogixNG").equals(value)) { // NOI18N 218 exportToLogixNGPressed(sName); 219 } 220 } else if (col == ENABLECOL) { 221 // alternate 222 Logix x = (Logix) getValueAt(row, SYSNAMECOL); 223 boolean v = x.getEnabled(); 224 x.setEnabled(!v); 225 } else { 226 super.setValueAt(value, row, col); 227 } 228 } 229 230 /** 231 * Delete the bean after all the checking has been done. 232 * <p> 233 * Deactivates the Logix and remove its conditionals. 234 * 235 * @param bean of the Logix to delete 236 */ 237 @Override 238 protected void doDelete(Logix bean) { 239 bean.deActivateLogix(); 240 // delete the Logix and all its Conditionals 241 _logixManager.deleteLogix(bean); 242 } 243 244 @Override 245 protected boolean matchPropertyName(java.beans.PropertyChangeEvent e) { 246 if (e.getPropertyName().equals(enabledString)) { 247 return true; 248 } 249 return super.matchPropertyName(e); 250 } 251 252 @Override 253 public Manager<Logix> getManager() { 254 return InstanceManager.getDefault(jmri.LogixManager.class); 255 } 256 257 @Override 258 public Logix getBySystemName(@Nonnull String name) { 259 return InstanceManager.getDefault(jmri.LogixManager.class).getBySystemName( 260 name); 261 } 262 263 @Override 264 public Logix getByUserName(@Nonnull String name) { 265 return InstanceManager.getDefault(jmri.LogixManager.class).getByUserName( 266 name); 267 } 268 269 @Override 270 protected String getMasterClassName() { 271 return getClassName(); 272 } 273 274 @Override 275 public void configureTable(JTable table) { 276 table.setDefaultRenderer(Boolean.class, new EnablingCheckboxRenderer()); 277 table.setDefaultRenderer(JComboBox.class, new jmri.jmrit.symbolicprog.ValueRenderer()); 278 table.setDefaultEditor(JComboBox.class, new jmri.jmrit.symbolicprog.ValueEditor()); 279 super.configureTable(table); 280 } 281 282 /** 283 * Replace delete button with comboBox to edit/delete/copy/select 284 * Logix. 285 * 286 * @param table name of the Logix JTable holding the column 287 */ 288 @Override 289 protected void configDeleteColumn(JTable table) { 290 JComboBox<String> editCombo = new JComboBox<String>(); 291 editCombo.addItem(Bundle.getMessage("ButtonSelect")); // NOI18N 292 editCombo.addItem(Bundle.getMessage("ButtonEdit")); // NOI18N 293 editCombo.addItem(Bundle.getMessage("BrowserButton")); // NOI18N 294 editCombo.addItem(Bundle.getMessage("ButtonCopy")); // NOI18N 295 editCombo.addItem(Bundle.getMessage("ButtonDelete")); // NOI18N 296 editCombo.addItem(Bundle.getMessage("ButtonExportLogixToLogixNG")); // NOI18N 297 TableColumn col = table.getColumnModel().getColumn(BeanTableDataModel.DELETECOL); 298 col.setCellEditor(new DefaultCellEditor(editCombo)); 299 } 300 301 // Not needed - here for interface compatibility 302 @Override 303 public void clickOn(Logix t) { 304 } 305 306 @Override 307 public String getValue(String s) { 308 return ""; 309 } 310 311 @Override 312 protected String getBeanType() { 313 return Bundle.getMessage("BeanNameLogix"); // NOI18N 314 } 315 }; 316 } 317 318 /** 319 * Set title of Logix table. 320 */ 321 @Override 322 protected void setTitle() { 323 f.setTitle(Bundle.getMessage("TitleLogixTable")); 324 } 325 326 /** 327 * Insert 2 table specific menus. 328 * <p> 329 * Accounts for the Window and Help menus, which are already added to the 330 * menu bar as part of the creation of the JFrame, by adding the new menus 2 331 * places earlier unless the table is part of the ListedTableFrame, which 332 * adds the Help menu later on. 333 * 334 * @param f the JFrame of this table 335 */ 336 @Override 337 public void setMenuBar(BeanTableFrame<Logix> f) { 338 loadSelectionMode(); 339 loadEditorMode(); 340 341 JMenu menu = new JMenu(Bundle.getMessage("MenuOptions")); // NOI18N 342 menu.setMnemonic(KeyEvent.VK_O); 343 javax.swing.JMenuBar menuBar = f.getJMenuBar(); 344 int pos = menuBar.getMenuCount() - 1; // count the number of menus to insert the TableMenus before 'Window' and 'Help' 345 int offset = 1; 346 log.debug("setMenuBar number of menu items = {}", pos); // NOI18N 347 for (int i = 0; i <= pos; i++) { 348 if (menuBar.getComponent(i) instanceof JMenu) { 349 if (((JMenu) menuBar.getComponent(i)).getText().equals(Bundle.getMessage("MenuHelp"))) { // NOI18N 350 offset = -1; // correct for use as part of ListedTableAction where the Help Menu is not yet present 351 } 352 } 353 } 354 355 ButtonGroup enableButtonGroup = new ButtonGroup(); 356 JRadioButtonMenuItem r = new JRadioButtonMenuItem(Bundle.getMessage("EnableAll")); // NOI18N 357 r.addActionListener(new ActionListener() { 358 @Override 359 public void actionPerformed(ActionEvent e) { 360 enableAll(true); 361 } 362 }); 363 enableButtonGroup.add(r); 364 r.setSelected(true); 365 menu.add(r); 366 367 r = new JRadioButtonMenuItem(Bundle.getMessage("DisableAll")); // NOI18N 368 r.addActionListener(new ActionListener() { 369 @Override 370 public void actionPerformed(ActionEvent e) { 371 enableAll(false); 372 } 373 }); 374 enableButtonGroup.add(r); 375 menu.add(r); 376 377 menu.addSeparator(); 378 379 ButtonGroup modeButtonGroup = new ButtonGroup(); 380 r = new JRadioButtonMenuItem(Bundle.getMessage("UseMultiPick")); // NOI18N 381 r.addItemListener(new ItemListener() { 382 @Override 383 public void itemStateChanged(ItemEvent e) { 384 setSelectionMode(SelectionMode.USEMULTI); 385 } 386 }); 387 modeButtonGroup.add(r); 388 menu.add(r); 389 r.setSelected(_selectionMode == SelectionMode.USEMULTI); 390 391 r = new JRadioButtonMenuItem(Bundle.getMessage("UseSinglePick")); // NOI18N 392 r.addItemListener(new ItemListener() { 393 @Override 394 public void itemStateChanged(ItemEvent e) { 395 setSelectionMode(SelectionMode.USESINGLE); 396 } 397 }); 398 modeButtonGroup.add(r); 399 menu.add(r); 400 r.setSelected(_selectionMode == SelectionMode.USESINGLE); 401 402 r = new JRadioButtonMenuItem(Bundle.getMessage("UseComboNameBoxes")); // NOI18N 403 r.addItemListener(new ItemListener() { 404 @Override 405 public void itemStateChanged(ItemEvent e) { 406 setSelectionMode(SelectionMode.USECOMBO); 407 } 408 }); 409 modeButtonGroup.add(r); 410 menu.add(r); 411 r.setSelected(_selectionMode == SelectionMode.USECOMBO); 412 413 menu.addSeparator(); 414 415 ButtonGroup viewButtonGroup = new ButtonGroup(); 416 r = new JRadioButtonMenuItem(Bundle.getMessage("ListEdit")); // NOI18N 417 r.addItemListener(new ItemListener() { 418 @Override 419 public void itemStateChanged(ItemEvent e) { 420 setEditorMode(EditMode.LISTEDIT); 421 } 422 }); 423 viewButtonGroup.add(r); 424 menu.add(r); 425 r.setSelected(_editMode == EditMode.LISTEDIT); 426 427 r = new JRadioButtonMenuItem(Bundle.getMessage("TreeEdit")); // NOI18N 428 r.addItemListener(new ItemListener() { 429 @Override 430 public void itemStateChanged(ItemEvent e) { 431 setEditorMode(EditMode.TREEEDIT); 432 } 433 }); 434 viewButtonGroup.add(r); 435 menu.add(r); 436 r.setSelected(_editMode == EditMode.TREEEDIT); 437 438 menuBar.add(menu, pos + offset); 439 440 menu = new JMenu(Bundle.getMessage("MenuTools")); // NOI18N 441 menu.setMnemonic(KeyEvent.VK_T); 442 443 JMenuItem item = new JMenuItem(Bundle.getMessage("OpenPickListTables")); // NOI18N 444 item.addActionListener(new ActionListener() { 445 @Override 446 public void actionPerformed(ActionEvent e) { 447 openPickListTable(); 448 } 449 }); 450 menu.add(item); 451 452 item = new JMenuItem(Bundle.getMessage("FindOrphans")); // NOI18N 453 item.addActionListener(new ActionListener() { 454 @Override 455 public void actionPerformed(ActionEvent e) { 456 findOrphansPressed(e); 457 } 458 }); 459 menu.add(item); 460 461 item = new JMenuItem(Bundle.getMessage("EmptyConditionals")); // NOI18N 462 item.addActionListener(new ActionListener() { 463 @Override 464 public void actionPerformed(ActionEvent e) { 465 findEmptyPressed(e); 466 } 467 }); 468 menu.add(item); 469 470 item = new JMenuItem(Bundle.getMessage("CrossReference")); // NOI18N 471 item.addActionListener(new ActionListener() { 472 BeanTableFrame<?> parent; 473 474 @Override 475 public void actionPerformed(ActionEvent e) { 476 new RefDialog(parent); 477 } 478 479 ActionListener init(BeanTableFrame<?> f) { 480 parent = f; 481 return this; 482 } 483 }.init(f)); 484 menu.add(item); 485 486 item = new JMenuItem(Bundle.getMessage("DisplayWhereUsed")); // NOI18N 487 item.addActionListener(new ActionListener() { 488 @Override 489 public void actionPerformed(ActionEvent e) { 490 makeWhereUsedWindow(); 491 } 492 }); 493 menu.add(item); 494 495 menuBar.add(menu, pos + offset + 1); // add this menu to the right of the previous 496 } 497 498 /** 499 * Get the saved mode selection, default to the tranditional tabbed pick 500 * list. 501 * <p> 502 * During the menu build process, the corresponding menu item is set to 503 * selected. 504 * 505 * @since 4.7.3 506 */ 507 void loadSelectionMode() { 508 Object modeName = InstanceManager.getDefault(jmri.UserPreferencesManager.class). 509 getProperty(getClassName(), "Selection Mode"); // NOI18N 510 if (modeName == null) { 511 _selectionMode = SelectionMode.USEMULTI; 512 } else { 513 String currentMode = (String) modeName; 514 switch (currentMode) { 515 case "USEMULTI": // NOI18N 516 _selectionMode = SelectionMode.USEMULTI; 517 break; 518 case "USESINGLE": // NOI18N 519 _selectionMode = SelectionMode.USESINGLE; 520 break; 521 case "USECOMBO": // NOI18N 522 _selectionMode = SelectionMode.USECOMBO; 523 break; 524 default: 525 log.warn("Invalid Logix conditional selection mode value, '{}', returned", currentMode); // NOI18N 526 _selectionMode = SelectionMode.USEMULTI; 527 } 528 } 529 } 530 531 /** 532 * Save the mode selection. Called by menu item change events. 533 * 534 * @since 4.7.3 535 * @param newMode The SelectionMode enum constant 536 */ 537 void setSelectionMode(SelectionMode newMode) { 538 _selectionMode = newMode; 539 InstanceManager.getDefault(jmri.UserPreferencesManager.class). 540 setProperty(getClassName(), "Selection Mode", newMode.toString()); // NOI18N 541 } 542 543 /** 544 * Get the saved mode selection, default to the tranditional conditional 545 * list editor. 546 * <p> 547 * During the menu build process, the corresponding menu item is set to 548 * selected. 549 * 550 * @since 4.9.x 551 */ 552 void loadEditorMode() { 553 Object modeName = InstanceManager.getDefault(jmri.UserPreferencesManager.class). 554 getProperty(getClassName(), "Edit Mode"); // NOI18N 555 if (modeName == null) { 556 _editMode = EditMode.LISTEDIT; 557 } else { 558 String currentMode = (String) modeName; 559 switch (currentMode) { 560 case "LISTEDIT": // NOI18N 561 _editMode = EditMode.LISTEDIT; 562 break; 563 case "TREEEDIT": // NOI18N 564 _editMode = EditMode.TREEEDIT; 565 break; 566 default: 567 log.warn("Invalid conditional edit mode value, '{}', returned", currentMode); // NOI18N 568 _editMode = EditMode.LISTEDIT; 569 } 570 } 571 } 572 573 /** 574 * Save the view mode selection. Called by menu item change events. 575 * 576 * @since 4.9.x 577 * @param newMode The ViewMode enum constant 578 */ 579 void setEditorMode(EditMode newMode) { 580 _editMode = newMode; 581 InstanceManager.getDefault(jmri.UserPreferencesManager.class). 582 setProperty(getClassName(), "Edit Mode", newMode.toString()); // NOI18N 583 } 584 585 /** 586 * Open a new Pick List to drag Actions from to form Logix Conditionals. 587 */ 588 void openPickListTable() { 589 if (_pickTables == null) { 590 _pickTables = new jmri.jmrit.picker.PickFrame(Bundle.getMessage("TitlePickList")); // NOI18N 591 } else { 592 _pickTables.setVisible(true); 593 } 594 _pickTables.toFront(); 595 } 596 597 /** 598 * Find empty Conditional entries, called from menu. 599 * 600 * @see Maintenance#findEmptyPressed(java.awt.Frame) 601 * @param e the event heard 602 */ 603 void findEmptyPressed(ActionEvent e) { 604 Maintenance.findEmptyPressed(f); 605 } 606 607 /** 608 * Find orphaned entries, called from menu. 609 * 610 * @see Maintenance#findOrphansPressed(java.awt.Frame) 611 * @param e the event heard 612 */ 613 void findOrphansPressed(ActionEvent e) { 614 Maintenance.findOrphansPressed(f); 615 } 616 617 class RefDialog extends JDialog { 618 619 JTextField _devNameField; 620 java.awt.Frame _parent; 621 622 RefDialog(java.awt.Frame frame) { 623 super(frame, Bundle.getMessage("CrossReference"), true); // NOI18N 624 _parent = frame; 625 JPanel extraPanel = new JPanel(); 626 extraPanel.setLayout(new BoxLayout(extraPanel, BoxLayout.Y_AXIS)); 627 _devNameField = new JTextField(30); 628 JPanel panel = makeEditPanel(_devNameField, "ElementName", "ElementNameHint"); // NOI18N 629 JButton referenceButton = new JButton(Bundle.getMessage("ReferenceButton")); // NOI18N 630 panel.add(referenceButton); 631 referenceButton.addActionListener(new ActionListener() { 632 @Override 633 public void actionPerformed(ActionEvent e) { 634 deviceReportPressed(e); 635 } 636 }); 637 panel.add(referenceButton); 638 extraPanel.add(panel); 639 setContentPane(extraPanel); 640 pack(); 641 // setLocationRelativeTo((java.awt.Component)_pos); 642 setVisible(true); 643 } 644 645 void deviceReportPressed(ActionEvent e) { 646 Maintenance.deviceReportPressed(_devNameField.getText(), _parent); 647 dispose(); 648 } 649 } 650 651 void enableAll(boolean enable) { 652 for (Logix x : _logixManager.getNamedBeanSet()) { 653 x.setEnabled(enable); 654 } 655 } 656 657 @Override 658 protected String helpTarget() { 659 return "package.jmri.jmrit.beantable.LogixTable"; // NOI18N 660 } 661 662 // ------------ variable definitions ------------ 663 664 // Multi use variables 665 ConditionalManager _conditionalManager = null; // set when LogixAction is created 666 LogixManager _logixManager = null; // set when LogixAction is created 667 668 ConditionalEditBase _baseEdit; 669 670 boolean _showReminder = false; 671 private boolean _checkEnabled = jmri.InstanceManager.getDefault(jmri.configurexml.ShutdownPreferences.class).isStoreCheckEnabled(); 672 jmri.jmrit.picker.PickFrame _pickTables; 673 674 // Current focus variables 675 Logix _curLogix = null; 676 int conditionalRowNumber = 0; 677 678 // Add Logix Variables 679 JmriJFrame addLogixFrame = null; 680 JTextField _systemName = new JTextField(20); 681 JTextField _addUserName = new JTextField(20); 682 JComboBox<String> _copyCombo = new JComboBox<>(); 683 684 JCheckBox _autoSystemName = new JCheckBox(Bundle.getMessage("LabelAutoSysName")); // NOI18N 685 JLabel _sysNameLabel = new JLabel(Bundle.getMessage("BeanNameLogix") + " " + Bundle.getMessage("ColumnSystemName") + ":"); // NOI18N 686 JLabel _userNameLabel = new JLabel(Bundle.getMessage("BeanNameLogix") + " " + Bundle.getMessage("ColumnUserName") + ":"); // NOI18N 687 String systemNameAuto = this.getClass().getName() + ".AutoSystemName"; // NOI18N 688 JButton create; 689 690 // Edit Logix Variables 691 private boolean _inEditMode = false; 692 private boolean _inCopyMode = false; 693 private boolean _inAddMode = false; 694 695 /** 696 * Input selection names. 697 * 698 * @since 4.7.3 699 */ 700 public enum SelectionMode { 701 /** 702 * Use the traditional text field, with the tabbed Pick List available 703 * for drag-n-drop 704 */ 705 USEMULTI, 706 /** 707 * Use the traditional text field, but with a single Pick List that 708 * responds with a click 709 */ 710 USESINGLE, 711 /** 712 * Use combo boxes to select names instead of a text field. 713 */ 714 USECOMBO; 715 } 716 SelectionMode _selectionMode; 717 718 /** 719 * Conditional edit view mode 720 * 721 * @since 4.9.x 722 */ 723 public enum EditMode { 724 /** 725 * Use the traditional table list mode for editing conditionals 726 */ 727 LISTEDIT, 728 /** 729 * Use the tree based mode for editing condtiionals 730 */ 731 TREEEDIT; 732 } 733 EditMode _editMode; 734 735 // Save conditional reference target names before updating 736 private TreeSet<String> _saveTargetNames = new TreeSet<String>(); 737 private HashMap<String, ArrayList<String>> _saveTargetList = new HashMap<>(); 738 739 // ------------ Methods for Add Logix Window ------------ 740 741 /** 742 * Respond to the Add button in Logix table Creates and/or initialize the 743 * Add Logix pane. 744 * 745 * @param e The event heard 746 */ 747 @Override 748 protected void addPressed(ActionEvent e) { 749 // possible change 750 if (!checkFlags(null)) { 751 return; 752 } 753 _showReminder = true; 754 // make an Add Logix Frame 755 if (addLogixFrame == null) { 756 JPanel panel5 = makeAddLogixFrame("TitleAddLogix", "AddLogixMessage", 757 "package.jmri.jmrit.beantable.LogixAddEdit"); // NOI18N 758 // Create Logix 759 create = new JButton(Bundle.getMessage("ButtonCreate")); // NOI18N 760 panel5.add(create); 761 create.addActionListener(new ActionListener() { 762 @Override 763 public void actionPerformed(ActionEvent e) { 764 createPressed(e); 765 } 766 }); 767 create.setToolTipText(Bundle.getMessage("LogixCreateButtonHint")); // NOI18N 768 } 769 _inAddMode = true; 770 addLogixFrame.setEscapeKeyClosesWindow(true); 771 addLogixFrame.getRootPane().setDefaultButton(create); 772 addLogixFrame.pack(); 773 addLogixFrame.setVisible(true); 774 _autoSystemName.setSelected(false); 775 addLogixFrame.setLocationRelativeTo(getFrame()); 776 InstanceManager.getOptionalDefault(UserPreferencesManager.class).ifPresent((prefMgr) -> { 777 _autoSystemName.setSelected(prefMgr.getSimplePreferenceState(systemNameAuto)); 778 }); 779 } 780 781 /** 782 * Create or copy Logix frame. 783 * 784 * @param titleId property key to fetch as title of the frame (using Bundle) 785 * @param messageId part 1 of property key to fetch as user instruction on 786 * pane, either 1 or 2 is added to form the whole key 787 * @param helpFile help file name 788 * @return the button JPanel 789 */ 790 JPanel makeAddLogixFrame(String titleId, String messageId, String helpFile) { 791 addLogixFrame = new JmriJFrame(Bundle.getMessage(titleId)); 792 addLogixFrame.addHelpMenu(helpFile, true); // NOI18N 793 addLogixFrame.setLocation(50, 30); 794 Container contentPane = addLogixFrame.getContentPane(); 795 contentPane.setLayout(new BoxLayout(contentPane, BoxLayout.Y_AXIS)); 796 JPanel p; 797 p = new JPanel(); 798 p.setLayout(new FlowLayout()); 799 p.setLayout(new java.awt.GridBagLayout()); 800 java.awt.GridBagConstraints c = new java.awt.GridBagConstraints(); 801 c.gridwidth = 1; 802 c.gridheight = 1; 803 c.gridx = 0; 804 c.gridy = 0; 805 c.anchor = java.awt.GridBagConstraints.EAST; 806 p.add(_sysNameLabel, c); 807 c.gridy = 1; 808 p.add(_userNameLabel, c); 809 c.gridx = 1; 810 c.gridy = 0; 811 c.anchor = java.awt.GridBagConstraints.WEST; 812 c.weightx = 1.0; 813 c.fill = java.awt.GridBagConstraints.HORIZONTAL; // text field will expand 814 if (titleId.equals("TitleCopyLogix")) { 815 p.add(_copyCombo, c); 816 } else { 817 p.add(_systemName, c); 818 } 819 c.gridy = 1; 820 p.add(_addUserName, c); 821 c.gridx = 2; 822 c.gridy = 1; 823 c.anchor = java.awt.GridBagConstraints.WEST; 824 c.weightx = 1.0; 825 c.fill = java.awt.GridBagConstraints.HORIZONTAL; // text field will expand 826 c.gridy = 0; 827 p.add(_autoSystemName, c); 828 _addUserName.setToolTipText(Bundle.getMessage("LogixUserNameHint")); // NOI18N 829 _systemName.setToolTipText(Bundle.getMessage("LogixSystemNameHint")); // NOI18N 830 contentPane.add(p); 831 // set up message 832 JPanel panel3 = new JPanel(); 833 panel3.setLayout(new BoxLayout(panel3, BoxLayout.Y_AXIS)); 834 JPanel panel31 = new JPanel(); 835 panel31.setLayout(new FlowLayout()); 836 JLabel message1 = new JLabel(Bundle.getMessage(messageId + "1")); // NOI18N 837 panel31.add(message1); 838 JPanel panel32 = new JPanel(); 839 JLabel message2 = new JLabel(Bundle.getMessage(messageId + "2")); // NOI18N 840 panel32.add(message2); 841 panel3.add(panel31); 842 panel3.add(panel32); 843 contentPane.add(panel3); 844 845 // set up create and cancel buttons 846 JPanel panel5 = new JPanel(); 847 panel5.setLayout(new FlowLayout()); 848 // Cancel 849 JButton cancel = new JButton(Bundle.getMessage("ButtonCancel")); // NOI18N 850 panel5.add(cancel); 851 cancel.addActionListener(new ActionListener() { 852 @Override 853 public void actionPerformed(ActionEvent e) { 854 cancelAddPressed(e); 855 } 856 }); 857 cancel.setToolTipText(Bundle.getMessage("CancelLogixButtonHint")); // NOI18N 858 859 addLogixFrame.addWindowListener(new java.awt.event.WindowAdapter() { 860 @Override 861 public void windowClosing(java.awt.event.WindowEvent e) { 862 cancelAddPressed(null); 863 } 864 }); 865 contentPane.add(panel5); 866 867 _autoSystemName.addItemListener( 868 new ItemListener() { 869 @Override 870 public void itemStateChanged(ItemEvent e) { 871 autoSystemName(); 872 } 873 }); 874 return panel5; 875 } 876 877 /** 878 * Enable/disable fields for data entry when user selects to have system 879 * name automatically generated. 880 */ 881 void autoSystemName() { 882 if (_autoSystemName.isSelected()) { 883 _systemName.setEnabled(false); 884 _sysNameLabel.setEnabled(false); 885 } else { 886 _systemName.setEnabled(true); 887 _sysNameLabel.setEnabled(true); 888 } 889 } 890 891 /** 892 * Respond to the Cancel button in Add Logix window. 893 * <p> 894 * Note: Also get there if the user closes the Add Logix window. 895 * 896 * @param e The event heard 897 */ 898 void cancelAddPressed(ActionEvent e) { 899 addLogixFrame.setVisible(false); 900 addLogixFrame.dispose(); 901 addLogixFrame = null; 902 _inAddMode = false; 903 _inCopyMode = false; 904 if (f != null) { 905 f.setVisible(true); 906 } 907 } 908 909 /** 910 * Respond to the Copy Logix button in Add Logix window. 911 * <p> 912 * Provides a pane to set new properties of the copy. 913 * 914 * @param sName system name of Logix to be copied 915 */ 916 void copyPressed(String sName) { 917 if (!checkFlags(sName)) { 918 return; 919 } 920 _showReminder = true; 921 922 // Refresh combo box Logix list 923 _copyCombo.removeActionListener(this::copyComboListener); 924 _copyCombo.removeAllItems(); 925 _copyCombo.addItem(""); 926 var logixList = InstanceManager.getDefault(LogixManager.class).getNamedBeanSet(); 927 logixList.forEach((lgx) -> { 928 _copyCombo.addItem(lgx.getSystemName()); 929 }); 930 _copyCombo.setEditable(true); 931 _copyCombo.setSelectedIndex(0); 932 _copyCombo.addActionListener(this::copyComboListener); 933 jmri.util.swing.JComboBoxUtil.setupComboBoxMaxRows(_copyCombo); 934 935 // make an Add Logix Frame 936 if (addLogixFrame == null) { 937 JPanel panel5 = makeAddLogixFrame("TitleCopyLogix", "CopyLogixMessage", 938 "package.jmri.jmrit.conditional.ConditionalCopy"); // NOI18N 939 // Create Logix 940 JButton create = new JButton(Bundle.getMessage("ButtonCopy")); // NOI18N 941 panel5.add(create); 942 create.addActionListener(new CopyAction(sName)); 943 addLogixFrame.pack(); 944 addLogixFrame.setVisible(true); 945 _autoSystemName.setSelected(false); 946 addLogixFrame.setLocationRelativeTo(getFrame()); 947 InstanceManager.getOptionalDefault(UserPreferencesManager.class).ifPresent((prefMgr) -> { 948 _autoSystemName.setSelected(prefMgr.getSimplePreferenceState(systemNameAuto)); 949 }); 950 _inCopyMode = true; 951 } 952 _curLogix = _logixManager.getBySystemName(sName); 953 } 954 955 class CopyAction implements ActionListener { 956 String _lgxName; 957 CopyAction(String lgxName) { 958 _lgxName = lgxName; 959 } 960 @Override 961 public void actionPerformed(ActionEvent e) { 962 copyLogixPressed(_lgxName); 963 } 964 } 965 966 /** 967 * Copy the Logix as configured in the Copy set up pane. 968 * 969 * @param lgxName Logix system name to be copied 970 */ 971 private void copyLogixPressed(String lgxName) { 972 _systemName.setText((String) _copyCombo.getSelectedItem()); 973 String uName = _addUserName.getText(); 974 if (uName.length() == 0) { 975 uName = null; 976 } 977 Logix targetLogix; 978 if (_autoSystemName.isSelected()) { 979 if (!checkLogixUserName(uName)) { 980 return; 981 } 982 targetLogix = _logixManager.createNewLogix(uName); 983 } else { 984 // Validate the system name 985 if (!checkLogixSysName()) { 986 cancelAddPressed(null); 987 return; 988 } 989 var sName = _systemName.getText(); // Use the validated, possibly changed, system name 990 991 targetLogix = _logixManager.getBySystemName(sName); 992 if (targetLogix == null && uName != null) { 993 targetLogix = _logixManager.getByUserName(uName); 994 } 995 if (targetLogix != null) { 996 int result = JmriJOptionPane.showConfirmDialog(f, 997 Bundle.getMessage("ConfirmLogixDuplicate", 998 targetLogix.getDisplayName(DisplayOptions.USERNAME_SYSTEMNAME), lgxName), // NOI18N 999 Bundle.getMessage("QuestionTitle"), JmriJOptionPane.YES_NO_OPTION, // NOI18N 1000 JmriJOptionPane.QUESTION_MESSAGE); 1001 if (JmriJOptionPane.YES_OPTION != result) { 1002 return; 1003 } 1004 } 1005 if (targetLogix == null) { 1006 targetLogix = _logixManager.createNewLogix(sName, uName); 1007 if (targetLogix == null) { 1008 // should never get here unless there is an assignment conflict 1009 log.error("Failure to create Logix with System Name: {}", sName); // NOI18N 1010 return; 1011 } 1012 } else { 1013 targetLogix.setUserName(uName); 1014 } 1015 } 1016 cancelAddPressed(null); 1017 _baseEdit = new ConditionalListCopy(lgxName, targetLogix); 1018 _baseEdit.locateAt(getFrame()); 1019 _inCopyMode = true; 1020 _baseEdit.addLogixEventListener(new ConditionalBaseListener(lgxName)); 1021 } 1022 1023 /** 1024 * Set the user name input field. 1025 * @param e The action event. 1026 */ 1027 private void copyComboListener(ActionEvent e) { 1028 if (!e.getActionCommand().equals("comboBoxChanged")) { 1029 return; 1030 } 1031 1032 var name = ""; 1033 var index = _copyCombo.getSelectedIndex(); 1034 if (index > 0) { 1035 var logix = _logixManager.getLogix(_copyCombo.getItemAt(index)); 1036 if (logix != null) { 1037 var userName = logix.getUserName(); 1038 if (userName != null) { 1039 name = userName; 1040 } 1041 } 1042 } 1043 _addUserName.setText(name); 1044 } 1045 1046 /** 1047 * Check and warn if a string is already in use as the user name of a Logix. 1048 * 1049 * @param uName the suggested name 1050 * @return true if not in use 1051 */ 1052 boolean checkLogixUserName(String uName) { 1053 // check if a Logix with the same user name exists 1054 if (uName != null && uName.trim().length() > 0) { 1055 Logix x = _logixManager.getByUserName(uName); 1056 if (x != null) { 1057 // Logix with this user name already exists 1058 JmriJOptionPane.showMessageDialog(getFrame(), 1059 Bundle.getMessage("LogixError3"), Bundle.getMessage("ErrorTitle"), 1060 JmriJOptionPane.ERROR_MESSAGE); 1061 return false; 1062 } 1063 } 1064 return true; 1065 } 1066 1067 /** 1068 * Check for a valid Logix system name. 1069 * A valid name starts with the Logix prefix consisting of the Internal system prefix (normally I) + X, 1070 * and at least 1 additional character. The prefix will be added if necessary. 1071 * Any makeSystemName errors are logged to the system console and a dialog is displayed. 1072 * @return true if the name is now valid. 1073 */ 1074 boolean checkLogixSysName() { 1075 String sName = _systemName.getText(); 1076 1077 try { 1078 sName = InstanceManager.getDefault(jmri.LogixManager.class).makeSystemName(sName); 1079 } catch (jmri.NamedBean.BadSystemNameException ex) { 1080 JmriJOptionPane.showMessageDialog(getFrame(), 1081 Bundle.getMessage("LogixError8"), Bundle.getMessage("ErrorTitle"), 1082 JmriJOptionPane.ERROR_MESSAGE); 1083 return false; 1084 } 1085 _systemName.setText(sName); 1086 return true; 1087 } 1088 1089 /** 1090 * Check if another Logix editing session is currently open or no system 1091 * name is provided. 1092 * 1093 * @param sName system name of Logix to be copied 1094 * @return true if a new session may be started 1095 */ 1096 boolean checkFlags(String sName) { 1097 if (_inEditMode) { 1098 // Already editing a Logix, ask for completion of that edit 1099 JmriJOptionPane.showMessageDialog(getFrame(), 1100 Bundle.getMessage("LogixError32", _curLogix.getSystemName()), 1101 Bundle.getMessage("ErrorTitle"), 1102 JmriJOptionPane.ERROR_MESSAGE); 1103 _baseEdit.bringToFront(); 1104 return false; 1105 } 1106 1107 if (_inAddMode) { 1108 // Adding a Logix, ask for completion of that edit 1109 JmriJOptionPane.showMessageDialog(getFrame(), 1110 Bundle.getMessage("LogixError33"), 1111 Bundle.getMessage("ErrorTitle"), // NOI18N 1112 JmriJOptionPane.ERROR_MESSAGE); 1113 addLogixFrame.toFront(); 1114 return false; 1115 } 1116 1117 if (_inCopyMode) { 1118 // Already copying a Logix, ask for completion of that edit 1119 JmriJOptionPane.showMessageDialog(getFrame(), 1120 Bundle.getMessage("LogixError31", _curLogix.getSystemName()), 1121 Bundle.getMessage("ErrorTitle"), // NOI18N 1122 JmriJOptionPane.ERROR_MESSAGE); 1123 _baseEdit.bringToFront(); 1124 return false; 1125 } 1126 1127 if (sName != null) { 1128 // check if a Logix with this name exists 1129 Logix x = _logixManager.getBySystemName(sName); 1130 if (x == null) { 1131 // Logix does not exist, so cannot be edited 1132 log.error("No Logix with system name: {}", sName); 1133 JmriJOptionPane.showMessageDialog(getFrame(), 1134 Bundle.getMessage("LogixError5"), 1135 Bundle.getMessage("ErrorTitle"), // NOI18N 1136 JmriJOptionPane.ERROR_MESSAGE); 1137 return false; 1138 } 1139 } 1140 return true; 1141 } 1142 1143 /** 1144 * Respond to the Create Logix button in Add Logix window. 1145 * 1146 * @param e The event heard 1147 */ 1148 void createPressed(ActionEvent e) { 1149 // possible change 1150 _showReminder = true; 1151 String sName = ""; 1152 String uName = _addUserName.getText(); 1153 if (uName.length() == 0) { 1154 uName = null; 1155 } 1156 if (_autoSystemName.isSelected()) { 1157 if (!checkLogixUserName(uName)) { 1158 return; 1159 } 1160 _curLogix = _logixManager.createNewLogix(uName); 1161 sName = _curLogix.getSystemName(); 1162 } else { 1163 if (!checkLogixSysName()) { 1164 return; 1165 } 1166 // Get validated system name 1167 sName = _systemName.getText(); 1168 // check if a Logix with this name already exists 1169 Logix x = null; 1170 try { 1171 x = _logixManager.getBySystemName(sName); 1172 } catch (Exception ex) { 1173 // user input no good 1174 handleCreateException(sName); 1175 return; // without creating 1176 } 1177 if (x != null) { 1178 // Logix already exists 1179 JmriJOptionPane.showMessageDialog(getFrame(), Bundle.getMessage("LogixError1"), 1180 Bundle.getMessage("ErrorTitle"), // NOI18N 1181 JmriJOptionPane.ERROR_MESSAGE); 1182 return; 1183 } 1184 if (!checkLogixUserName(uName)) { 1185 return; 1186 } 1187 // Create the new Logix 1188 _curLogix = _logixManager.createNewLogix(sName, uName); 1189 if (_curLogix == null) { 1190 // should never get here unless there is an assignment conflict 1191 log.error("Failure to create Logix with System Name: {}", sName); // NOI18N 1192 return; 1193 } 1194 } 1195 cancelAddPressed(null); 1196 // create the Edit Logix Window 1197 editPressed(sName); 1198 InstanceManager.getOptionalDefault(UserPreferencesManager.class).ifPresent((prefMgr) -> { 1199 prefMgr.setSimplePreferenceState(systemNameAuto, _autoSystemName.isSelected()); 1200 }); 1201 } 1202 1203 void handleCreateException(String sysName) { 1204 JmriJOptionPane.showMessageDialog(getFrame(), 1205 Bundle.getMessage("ErrorLogixAddFailed", sysName), // NOI18N 1206 Bundle.getMessage("ErrorTitle"), // NOI18N 1207 JmriJOptionPane.ERROR_MESSAGE); 1208 } 1209 1210 // ------------ Methods for Edit Logix Pane ------------ 1211 1212 /** 1213 * Respond to the Edit button pressed in Logix table. 1214 * 1215 * @param sName system name of Logix to be edited 1216 */ 1217 void editPressed(String sName) { 1218 if (!checkFlags(sName)) { 1219 return; 1220 } 1221 1222 if (sName.equals(SensorGroupFrame.logixSysName)) { 1223 // Sensor group message 1224 JmriJOptionPane.showMessageDialog(getFrame(), 1225 Bundle.getMessage("LogixWarn8", SensorGroupFrame.logixUserName, SensorGroupFrame.logixSysName), 1226 Bundle.getMessage("WarningTitle"), // NOI18N 1227 JmriJOptionPane.WARNING_MESSAGE); 1228 return; 1229 } 1230 _curLogix = _logixManager.getBySystemName(sName); 1231 1232 // Create a new conditional edit view, add the listener. 1233 if (_editMode == EditMode.TREEEDIT) { 1234 _baseEdit = new ConditionalTreeEdit(sName); 1235 } else { 1236 _baseEdit = new ConditionalListEdit(sName); 1237 } 1238 _baseEdit.locateAt(getFrame()); 1239 _inEditMode = true; 1240 _baseEdit.addLogixEventListener(new ConditionalBaseListener(sName)); 1241 } 1242 1243 class ConditionalBaseListener implements ConditionalEditBase.LogixEventListener { 1244 String _lgxName; 1245 ConditionalBaseListener(String lgxName) { 1246 _lgxName = lgxName; 1247 } 1248 1249 @Override 1250 public void logixEventOccurred() { 1251 _baseEdit.logixData.forEach((key, value) -> { 1252 if (key.equals("Finish")) { // NOI18N 1253 _baseEdit = null; 1254 _inEditMode = false; 1255 _inCopyMode = false; 1256 Logix x = _logixManager.getBySystemName(value); 1257 if (x == null) { 1258 log.error("Found no logix for name {} when done", value); 1259 return; 1260 } 1261 x.activateLogix(); 1262 f.setVisible(true); 1263 } else if (key.equals("Delete")) { // NOI18N 1264 deletePressed(value); 1265 } else if (key.equals("chgUname")) { // NOI18N 1266 Logix x = _logixManager.getBySystemName(_lgxName); 1267 if (x == null) { 1268 log.error("Found no logix for name {} when changing user name (2)", _lgxName); 1269 return; 1270 } 1271 x.setUserName(value); 1272 m.fireTableDataChanged(); 1273 } 1274 }); 1275 } 1276 } 1277 1278 /** 1279 * Display reminder to save. 1280 */ 1281 void showSaveReminder() { 1282 if (_showReminder && !_checkEnabled) { 1283 if (InstanceManager.getNullableDefault(jmri.UserPreferencesManager.class) != null) { 1284 InstanceManager.getDefault(jmri.UserPreferencesManager.class). 1285 showInfoMessage(Bundle.getMessage("ReminderTitle"), Bundle.getMessage("ReminderSaveString", Bundle.getMessage("MenuItemLogixTable")), // NOI18N 1286 getClassName(), 1287 "remindSaveLogix"); // NOI18N 1288 } 1289 } 1290 } 1291 1292 @Override 1293 public void setMessagePreferencesDetails() { 1294 HashMap<Integer, String> options = new HashMap< Integer, String>(3); 1295 options.put(0x00, Bundle.getMessage("DeleteAsk")); // NOI18N 1296 options.put(0x01, Bundle.getMessage("DeleteNever")); // NOI18N 1297 options.put(0x02, Bundle.getMessage("DeleteAlways")); // NOI18N 1298 jmri.InstanceManager.getDefault(jmri.UserPreferencesManager.class).setMessageItemDetails(getClassName(), "delete", Bundle.getMessage("DeleteLogix"), options, 0x00); // NOI18N 1299 jmri.InstanceManager.getDefault(jmri.UserPreferencesManager.class).setPreferenceItemDetails(getClassName(), "remindSaveLogix", Bundle.getMessage("HideSaveReminder")); // NOI18N 1300 super.setMessagePreferencesDetails(); 1301 } 1302 1303 /** 1304 * Respond to the Delete combo selection Logix window or conditional view 1305 * delete request. 1306 * 1307 * @param sName system name of bean to be deleted 1308 */ 1309 void deletePressed(String sName) { 1310 if (!checkConditionalReferences(sName)) { 1311 return; 1312 } 1313 final Logix x = _logixManager.getBySystemName(sName); 1314 final jmri.UserPreferencesManager p; 1315 p = jmri.InstanceManager.getNullableDefault(jmri.UserPreferencesManager.class); 1316 if (p != null && p.getMultipleChoiceOption(getClassName(), "delete") == 0x02) { // NOI18N 1317 if (x != null) { 1318 _logixManager.deleteLogix(x); 1319 deleteSourceWhereUsed(); 1320 } 1321 } else { 1322 final JDialog dialog = new JDialog(); 1323 String msg; 1324 dialog.setTitle(Bundle.getMessage("QuestionTitle")); // NOI18N 1325 dialog.setLocationRelativeTo(getFrame()); 1326 dialog.setDefaultCloseOperation(javax.swing.JFrame.DISPOSE_ON_CLOSE); 1327 JPanel container = new JPanel(); 1328 container.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10)); 1329 container.setLayout(new BoxLayout(container, BoxLayout.Y_AXIS)); 1330 msg = Bundle.getMessage("ConfirmLogixDelete", sName); // NOI18N 1331 JLabel question = new JLabel(msg); 1332 question.setAlignmentX(Component.CENTER_ALIGNMENT); 1333 container.add(question); 1334 1335 final JCheckBox remember = new JCheckBox(Bundle.getMessage("MessageRememberSetting")); // NOI18N 1336 remember.setFont(remember.getFont().deriveFont(10f)); 1337 remember.setAlignmentX(Component.CENTER_ALIGNMENT); 1338 1339 JButton yesButton = new JButton(Bundle.getMessage("ButtonYes")); // NOI18N 1340 JButton noButton = new JButton(Bundle.getMessage("ButtonNo")); // NOI18N 1341 JPanel button = new JPanel(); 1342 button.setAlignmentX(Component.CENTER_ALIGNMENT); 1343 button.add(yesButton); 1344 button.add(noButton); 1345 container.add(button); 1346 1347 noButton.addActionListener(new ActionListener() { 1348 @Override 1349 public void actionPerformed(ActionEvent e) { 1350 //there is no point in remebering this the user will never be 1351 //able to delete a bean! 1352 /*if(remember.isSelected()){ 1353 setDisplayDeleteMsg(0x01); 1354 }*/ 1355 dialog.dispose(); 1356 } 1357 }); 1358 1359 yesButton.addActionListener(new ActionListener() { 1360 @Override 1361 public void actionPerformed(ActionEvent e) { 1362 if (p != null && remember.isSelected()) { 1363 p.setMultipleChoiceOption(getClassName(), "delete", 0x02); // NOI18N 1364 } 1365 if (x != null) { 1366 _logixManager.deleteLogix(x); 1367 deleteSourceWhereUsed(); 1368 } 1369 dialog.dispose(); 1370 } 1371 }); 1372 container.add(remember); 1373 container.setAlignmentX(Component.CENTER_ALIGNMENT); 1374 container.setAlignmentY(Component.CENTER_ALIGNMENT); 1375 dialog.getContentPane().add(container); 1376 dialog.pack(); 1377 dialog.setModal(true); 1378 dialog.setVisible(true); 1379 } 1380 1381 f.setVisible(true); 1382 } 1383 1384 /** 1385 * Respond to the Export to LogixNG combo selection Logix window request. 1386 * 1387 * @param sName system name of bean to export 1388 */ 1389 void exportToLogixNGPressed(String sName) { 1390 if (!checkConditionalReferences(sName)) { 1391 return; 1392 } 1393 final Logix logix = _logixManager.getBySystemName(sName); 1394 if (logix == null) throw new NullPointerException("logix is null"); 1395 1396 boolean error = false; 1397 StringBuilder errorMessage = new StringBuilder("<html><table border=\"1\" cellspacing=\"0\" cellpadding=\"2\">"); 1398 errorMessage.append("<tr><th>"); 1399 errorMessage.append(Bundle.getMessage("ColumnSystemName")); 1400 errorMessage.append("</th><th>"); 1401 errorMessage.append(Bundle.getMessage("ColumnUserName")); 1402 errorMessage.append("</th><th>"); 1403 errorMessage.append(Bundle.getMessage("ExportLogixColumnError")); 1404 errorMessage.append("</th></tr>"); 1405 1406 try { 1407 ImportLogix importLogix = new ImportLogix(logix, true, true); 1408 importLogix.doImport(); 1409 } catch (JmriException e) { 1410 errorMessage.append("<tr><td>"); 1411 errorMessage.append(logix.getSystemName()); 1412 errorMessage.append("</td><td>"); 1413 errorMessage.append(logix.getUserName() != null ? logix.getUserName() : ""); 1414 errorMessage.append("</td><td>"); 1415 errorMessage.append(e.getMessage()); 1416 errorMessage.append("</td></tr>"); 1417 log.error("Error thrown: {}", e, e); 1418 error = true; 1419 } 1420 1421 if (!error) { 1422 try { 1423 ImportLogix importLogix = new ImportLogix(logix, true, false); 1424 importLogix.doImport(); 1425 JmriJOptionPane.showMessageDialog(f, Bundle.getMessage("LogixIsExported", logix.getDisplayName()), Bundle.getMessage("TitleLogixExportSuccess"), JmriJOptionPane.INFORMATION_MESSAGE); 1426 } catch (JmriException e) { 1427 throw new RuntimeException("Unexpected error: "+e.getMessage(), e); 1428 } 1429 } else { 1430 errorMessage.append("</table></html>"); 1431 JmriJOptionPane.showMessageDialog(f, errorMessage.toString(), Bundle.getMessage("TitleLogixExportError"), JmriJOptionPane.ERROR_MESSAGE); 1432 } 1433 } 1434 1435 /** 1436 * Build a tree set from conditional references. 1437 * 1438 * @since 4.7.4 1439 * @param varList The ConditionalVariable list that might contain 1440 * conditional references 1441 * @param treeSet A tree set to be built from the varList data 1442 */ 1443 void loadReferenceNames(List<ConditionalVariable> varList, TreeSet<String> treeSet) { 1444 treeSet.clear(); 1445 for (ConditionalVariable var : varList) { 1446 if (var.getType() == Conditional.Type.CONDITIONAL_TRUE 1447 || var.getType() == Conditional.Type.CONDITIONAL_FALSE) { 1448 treeSet.add(var.getName()); 1449 } 1450 } 1451 } 1452 1453 boolean checkConditionalUserName(String uName, Logix logix) { 1454 if ((uName != null) && (!(uName.equals("")))) { 1455 Conditional p = _conditionalManager.getByUserName(logix, uName); 1456 if (p != null) { 1457 // Conditional with this user name already exists 1458 log.error("Failure to update Conditional with Duplicate User Name: {}", uName); 1459 JmriJOptionPane.showMessageDialog(getFrame(), 1460 Bundle.getMessage("LogixError10"), // NOI18N 1461 Bundle.getMessage("ErrorTitle"), // NOI18N 1462 JmriJOptionPane.ERROR_MESSAGE); 1463 return false; 1464 } 1465 } 1466 return true; 1467 } 1468 1469 /** 1470 * Check form of Conditional systemName. 1471 * 1472 * @param sName system name of bean to be checked 1473 * @return false if sName is empty string or null 1474 */ 1475 boolean checkConditionalSystemName(String sName) { 1476 if ((sName != null) && (!(sName.equals("")))) { 1477 Conditional p = _conditionalManager.getBySystemName(sName); 1478 if (p != null) { 1479 return false; 1480 } 1481 } else { 1482 return false; 1483 } 1484 return true; 1485 } 1486 1487 /** 1488 * Check for conditional references. 1489 * 1490 * @since 4.7.4 1491 * @param logixName The Logix under consideration 1492 * @return true if no references 1493 */ 1494 boolean checkConditionalReferences(String logixName) { 1495 _saveTargetList.clear(); 1496 Logix x = _logixManager.getLogix(logixName); 1497 int numConditionals = x.getNumConditionals(); 1498 if (numConditionals > 0) { 1499 for (int i = 0; i < numConditionals; i++) { 1500 String csName = x.getConditionalByNumberOrder(i); 1501 1502 // If the conditional is a where used source, retain it for later 1503 ArrayList<String> targetList = InstanceManager.getDefault(jmri.ConditionalManager.class).getTargetList(csName); 1504 if (targetList.size() > 0) { 1505 _saveTargetList.put(csName, targetList); 1506 } 1507 1508 // If the conditional is a where used target, check scope 1509 ArrayList<String> refList = InstanceManager.getDefault(jmri.ConditionalManager.class).getWhereUsed(csName); 1510 if (refList != null) { 1511 for (String refName : refList) { 1512 Logix xRef = _conditionalManager.getParentLogix(refName); 1513 String xsName = xRef.getSystemName(); 1514 if (logixName.equals(xsName)) { 1515 // Member of the same Logix 1516 continue; 1517 } 1518 1519 // External references have to be removed before the Logix can be deleted. 1520 Conditional c = x.getConditional(csName); 1521 Conditional cRef = xRef.getConditional(refName); 1522 JmriJOptionPane.showMessageDialog(getFrame(), 1523 Bundle.getMessage("LogixError11", c.getUserName(), c.getSystemName(), cRef.getUserName(), 1524 cRef.getSystemName(), xRef.getUserName(), xRef.getSystemName()), // NOI18N 1525 Bundle.getMessage("ErrorTitle"), 1526 JmriJOptionPane.ERROR_MESSAGE); // NOI18N 1527 return false; 1528 } 1529 } 1530 } 1531 } 1532 return true; 1533 } 1534 1535 /** 1536 * Remove target/source where used entries after a Logix delete. 1537 * 1538 * @since 4.7.4 1539 */ 1540 void deleteSourceWhereUsed() { 1541 _saveTargetList.forEach((refName, targetList) -> { 1542 for (String targetName : targetList) { 1543 InstanceManager.getDefault(jmri.ConditionalManager.class).removeWhereUsed(targetName, refName); 1544 } 1545 }); 1546 } 1547 1548 /** 1549 * Update the conditional reference where used. 1550 * <p> 1551 * The difference between the saved target names and new target names is 1552 * used to add/remove where used references. 1553 * 1554 * @since 4.7.4 1555 * @param newTargetNames The conditional target names after updating 1556 * @param refName The system name for the referencing conditional 1557 */ 1558 void updateWhereUsed(TreeSet<String> newTargetNames, String refName) { 1559 TreeSet<String> deleteNames = new TreeSet<>(_saveTargetNames); 1560 deleteNames.removeAll(newTargetNames); 1561 for (String deleteName : deleteNames) { 1562 InstanceManager.getDefault(jmri.ConditionalManager.class).removeWhereUsed(deleteName, refName); 1563 } 1564 1565 TreeSet<String> addNames = new TreeSet<>(newTargetNames); 1566 addNames.removeAll(_saveTargetNames); 1567 for (String addName : addNames) { 1568 InstanceManager.getDefault(jmri.ConditionalManager.class).addWhereUsed(addName, refName); 1569 } 1570 } 1571 1572 /** 1573 * Create Variable and Action editing pane center part. 1574 * 1575 * @param comp Field or comboBox to include on sub pane 1576 * @param label property key for label 1577 * @param hint property key for tooltip for this sub pane 1578 * @return JPanel containing interface 1579 */ 1580 JPanel makeEditPanel(JComponent comp, String label, String hint) { 1581 JPanel panel = new JPanel(); 1582 panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS)); 1583 JPanel p = new JPanel(); 1584 p.add(new JLabel(Bundle.getMessage(label))); 1585 panel.add(p); 1586 if (hint != null) { 1587 panel.setToolTipText(Bundle.getMessage(hint)); 1588 } 1589 comp.setMaximumSize(comp.getPreferredSize()); // override for text fields 1590 panel.add(comp); 1591 panel.add(Box.createVerticalGlue()); 1592 return panel; 1593 } 1594 1595 /** 1596 * Format time to hh:mm given integer hour and minute. 1597 * 1598 * @param hour value for time hours 1599 * @param minute value for time minutes 1600 * @return Formatted time string 1601 */ 1602 public static String formatTime(int hour, int minute) { 1603 String s = ""; 1604 String t = Integer.toString(hour); 1605 if (t.length() == 2) { 1606 s = t + ":"; 1607 } else if (t.length() == 1) { 1608 s = "0" + t + ":"; 1609 } 1610 t = Integer.toString(minute); 1611 if (t.length() == 2) { 1612 s = s + t; 1613 } else if (t.length() == 1) { 1614 s = s + "0" + t; 1615 } 1616 if (s.length() != 5) { 1617 // input error 1618 s = "00:00"; 1619 } 1620 return s; 1621 } 1622 1623 @Override 1624 public String getClassDescription() { 1625 return Bundle.getMessage("TitleLogixTable"); // NOI18N 1626 } 1627 1628 @Override 1629 protected String getClassName() { 1630 return LogixTableAction.class.getName(); 1631 } 1632 1633 // ------------ Methods for Conditional References Window ------------ 1634 /** 1635 * Builds the conditional references window when the Conditional Variable 1636 * References menu item is selected. 1637 * <p> 1638 * This is a stand-alone window that can be closed at any time. 1639 * 1640 * @since 4.7.4 1641 */ 1642 void makeWhereUsedWindow() { 1643 1644 JmriJFrame referenceListFrame = new JmriJFrame(Bundle.getMessage("LabelRefTitle"), false, true); // NOI18N 1645 Container contentPane = referenceListFrame.getContentPane(); 1646 contentPane.setLayout(new BoxLayout(contentPane, BoxLayout.Y_AXIS)); 1647 1648 // build header information 1649 JPanel panel1 = new JPanel(); 1650 panel1.setLayout(new FlowLayout(FlowLayout.LEFT, 10, 5)); 1651 panel1.add(new JLabel(Bundle.getMessage("LabelRefTarget"))); // NOI18N 1652 panel1.add(new JLabel(Bundle.getMessage("LabelRefSource"))); // NOI18N 1653 contentPane.add(panel1); 1654 1655 // Build the conditional references listing 1656 JScrollPane scrollPane = null; 1657 JTextArea textContent = buildWhereUsedListing(); 1658 scrollPane = new JScrollPane(textContent); 1659 contentPane.add(scrollPane); 1660 1661 referenceListFrame.pack(); 1662 referenceListFrame.setVisible(true); 1663 } 1664 1665 /** 1666 * Creates a component containing the conditional reference where used list. 1667 * The source is {@link jmri.ConditionalManager#getWhereUsedMap()} 1668 * 1669 * @return a TextArea, empty if reference is not used 1670 * @since 4.7.4 1671 */ 1672 public JTextArea buildWhereUsedListing() { 1673 JTextArea condText = new javax.swing.JTextArea(); 1674 condText.setText(null); 1675 HashMap<String, ArrayList<String>> whereUsed = InstanceManager.getDefault(ConditionalManager.class).getWhereUsedMap(); 1676 SortedSet<String> targets = new TreeSet<>(whereUsed.keySet()); 1677 targets.forEach((target) -> { 1678 condText.append("\n" + target + "\t" + getWhereUsedName(target) + " \n"); 1679 ArrayList<String> refNames = whereUsed.get(target); 1680 refNames.forEach((refName) -> { 1681 condText.append("\t\t" + refName + "\t" + getWhereUsedName(refName) + " \n"); 1682 }); 1683 }); 1684 condText.setCaretPosition(0); 1685 condText.setTabSize(2); 1686 condText.setEditable(false); 1687 return condText; 1688 } 1689 1690 String getWhereUsedName(String cName) { 1691 Conditional cond = _conditionalManager.getBySystemName(cName); 1692 if ( cond!=null){ 1693 return cond.getUserName(); 1694 } 1695 return ""; 1696 } 1697 1698// ------------ Methods for Conditional Browser Window ------------ 1699 /** 1700 * Respond to the Browse button pressed in Logix table. 1701 * 1702 * @param sName The selected Logix system name 1703 */ 1704 void browserPressed(String sName) { 1705 makeBrowserWindow(sName); 1706 } 1707 1708 /** 1709 * Create and initialize the conditionals browser window. 1710 * @param lgxName Logix system name 1711 */ 1712 void makeBrowserWindow(String lgxName) { 1713 Logix logix = _logixManager.getBySystemName(lgxName); 1714 if (logix == null) { 1715 return; 1716 } 1717 // Logix was found, create the window 1718 JmriJFrame condBrowserFrame = new JmriJFrame(Bundle.getMessage("BrowserTitle"), false, true); // NOI18N 1719 condBrowserFrame.addHelpMenu("package.jmri.jmrit.beantable.LogixAddEdit", true); // NOI18N 1720 1721 Container contentPane = condBrowserFrame.getContentPane(); 1722 contentPane.setLayout(new BorderLayout()); 1723 1724 // LOGIX header information 1725 JPanel topPanel = new JPanel(); 1726 String tStr = Bundle.getMessage("BrowserLogix") + " " + logix.getSystemName() + " " // NOI18N 1727 + logix.getUserName() + " " 1728 + (Boolean.valueOf(logix.getEnabled()) 1729 ? Bundle.getMessage("BrowserEnabled") // NOI18N 1730 : Bundle.getMessage("BrowserDisabled")); // NOI18N 1731 topPanel.add(new JLabel(tStr)); 1732 contentPane.add(topPanel, BorderLayout.NORTH); 1733 1734 // Build the conditionals listing 1735 JScrollPane scrollPane = null; 1736 JTextArea textContent = buildConditionalListing(logix); 1737 scrollPane = new JScrollPane(textContent); 1738 contentPane.add(scrollPane); 1739 1740 JPanel bottomPanel = new JPanel(); 1741 bottomPanel.setLayout(new BorderLayout()); 1742 JButton helpBrowse = new JButton(Bundle.getMessage("MenuHelp")); // NOI18N 1743 bottomPanel.add(helpBrowse, BorderLayout.WEST); 1744 helpBrowse.addActionListener(new ActionListener() { 1745 @Override 1746 public void actionPerformed(ActionEvent e) { 1747 JmriJOptionPane.showMessageDialog(condBrowserFrame, 1748 Bundle.getMessage("BrowserHelpText"), // NOI18N 1749 Bundle.getMessage("BrowserHelpTitle"), // NOI18N 1750 JmriJOptionPane.INFORMATION_MESSAGE); 1751 } 1752 }); 1753 JButton saveBrowse = new JButton(Bundle.getMessage("BrowserSaveButton")); // NOI18N 1754 saveBrowse.setToolTipText(Bundle.getMessage("BrowserSaveButtonHint")); // NOI18N 1755 bottomPanel.add(saveBrowse, BorderLayout.EAST); 1756 saveBrowse.addActionListener(new SaveAction(lgxName)); 1757 contentPane.add(bottomPanel, BorderLayout.SOUTH); 1758 1759 condBrowserFrame.pack(); 1760 condBrowserFrame.setVisible(true); 1761 } // makeBrowserWindow 1762 1763 class SaveAction implements ActionListener { 1764 String _lgxName; 1765 SaveAction(String lgxName) { 1766 _lgxName = lgxName; 1767 } 1768 @Override 1769 public void actionPerformed(ActionEvent e) { 1770 saveBrowserPressed(_lgxName); 1771 } 1772 } 1773 1774 /** 1775 * Save the Logix browser window content to a text file. 1776 * @param lgxName Logix system name 1777 */ 1778 void saveBrowserPressed(String lgxName) { 1779 Logix logix = _logixManager.getBySystemName(lgxName); 1780 if (logix == null) { 1781 log.warn("Can't save browsed data, logix {} no longer exits", lgxName); 1782 return; 1783 } 1784 JFileChooser userFileChooser = new jmri.util.swing.JmriJFileChooser(FileUtil.getUserFilesPath()); 1785 userFileChooser.setApproveButtonText(Bundle.getMessage("BrowserSaveDialogApprove")); // NOI18N 1786 userFileChooser.setDialogTitle(Bundle.getMessage("BrowserSaveDialogTitle")); // NOI18N 1787 userFileChooser.rescanCurrentDirectory(); 1788 // Default to logix system name.txt 1789 userFileChooser.setSelectedFile(new File(FileUtil.sanitizeFilename(logix.getSystemName()) + ".txt")); // NOI18N 1790 int retVal = userFileChooser.showSaveDialog(null); 1791 if (retVal != JFileChooser.APPROVE_OPTION) { 1792 log.debug("Save browser content stopped, no file selected"); // NOI18N 1793 return; // give up if no file selected or cancel pressed 1794 } 1795 File file = userFileChooser.getSelectedFile(); 1796 log.debug("Save browser content to '{}'", file); // NOI18N 1797 1798 if (file.exists()) { 1799 Object[] options = {Bundle.getMessage("BrowserSaveDuplicateReplace"), // NOI18N 1800 Bundle.getMessage("BrowserSaveDuplicateAppend"), // NOI18N 1801 Bundle.getMessage("ButtonCancel")}; // NOI18N 1802 int selectedOption = JmriJOptionPane.showOptionDialog(null, 1803 Bundle.getMessage("BrowserSaveDuplicatePrompt", file.getName()), // NOI18N 1804 Bundle.getMessage("BrowserSaveDuplicateTitle"), // NOI18N 1805 JmriJOptionPane.DEFAULT_OPTION, 1806 JmriJOptionPane.WARNING_MESSAGE, 1807 null, options, options[0]); 1808 if (selectedOption == 2 || selectedOption == -1) { 1809 log.debug("Save browser content stopped, file replace/append cancelled"); // NOI18N 1810 return; // Cancel selected or dialog box closed 1811 } 1812 if (selectedOption == 0) { 1813 FileUtil.delete(file); // Replace selected 1814 } 1815 } 1816 1817 // Create the file content 1818 String tStr = Bundle.getMessage("BrowserLogix") + " " + logix.getSystemName() + " " // NOI18N 1819 + logix.getUserName() + " " 1820 + (Boolean.valueOf(logix.getEnabled()) 1821 ? Bundle.getMessage("BrowserEnabled") // NOI18N 1822 : Bundle.getMessage("BrowserDisabled")); // NOI18N 1823 JTextArea textContent = buildConditionalListing(logix); 1824 try { 1825 // ADD Logix Header inforation first 1826 FileUtil.appendTextToFile(file, tStr); 1827 FileUtil.appendTextToFile(file, textContent.getText()); 1828 } catch (IOException e) { 1829 log.error("Unable to write browser content to '{}'", file, e); // NOI18N 1830 } 1831 } 1832 1833 /** 1834 * Builds a Component representing the current conditionals for the selected 1835 * Logix statement. 1836 * 1837 *@param logix browsing Logix 1838 * @return a TextArea listing existing conditionals; will be empty if there 1839 * are none 1840 */ 1841 JTextArea buildConditionalListing(Logix logix) { 1842 String showSystemName, 1843 showCondName, 1844 condName, 1845 operand, 1846 tStr; 1847 1848 List<ConditionalVariable> variableList; 1849 List<ConditionalAction> actionList; 1850 ConditionalVariable variable; 1851 ConditionalAction action; 1852 String _antecedent = null; 1853 1854 JTextArea condText = new javax.swing.JTextArea(); 1855 condText.setFont(new Font(Font.MONOSPACED, Font.PLAIN, 12)); 1856 condText.setText(null); 1857 int numConditionals = logix.getNumConditionals(); 1858 for (int rx = 0; rx < numConditionals; rx++) { 1859 conditionalRowNumber = rx; 1860 Conditional curConditional = _conditionalManager.getBySystemName(logix.getConditionalByNumberOrder(rx)); 1861 if (curConditional==null){ 1862 continue; 1863 } 1864 variableList = curConditional.getCopyOfStateVariables(); 1865 actionList = curConditional.getCopyOfActions(); 1866 1867 showCondName = curConditional.getUserName(); 1868 if (showCondName == null) { 1869 showCondName = ""; 1870 } 1871 showSystemName = curConditional.getSystemName(); 1872 1873 // If no user name for a conditional, create one using C + row number 1874 if (showCondName.equals("")) { 1875 showCondName = "C" + (rx + 1); 1876 } 1877 condText.append("\n " + showSystemName + " " + showCondName + " \n"); 1878 if (curConditional.getLogicType() == Conditional.AntecedentOperator.MIXED) { 1879 _antecedent = curConditional.getAntecedentExpression(); 1880 String antecedent = ConditionalEditBase.translateAntecedent(_antecedent, false); 1881 condText.append(" " + Bundle.getMessage("LogixAntecedent") + " " + antecedent + " \n"); // NOI18N 1882 } 1883 1884 for (int i = 0; i < variableList.size(); i++) { 1885 variable = variableList.get(i); 1886 String varTrigger = (variable.doTriggerActions()) 1887 ? "[x]" // NOI18N 1888 : "[ ]"; 1889 tStr = " " + varTrigger + " "; 1890 tStr = tStr + " R" + (i + 1) + (i > 8 ? " " : " "); // Makes {Rx}bb or {Rxx}b 1891 condText.append(tStr); 1892 1893 operand = variable.getOpernString(); 1894 if (i == 0) { // add the IF to the first conditional 1895 condText.append(Bundle.getMessage("BrowserIF") + " " + operand + " "); // NOI18N 1896 } else { 1897 condText.append(" " + operand + " "); 1898 } 1899 if (variable.isNegated()) { 1900 condText.append(Bundle.getMessage("LogicNOT") + " "); // NOI18N 1901 } 1902 condText.append(variable.toString() + " \n"); 1903 } // for _variableList 1904 1905 if (actionList.size() > 0) { 1906 condText.append(" " + Bundle.getMessage("BrowserTHEN") + " \n"); // NOI18N 1907 boolean triggerType = curConditional.getTriggerOnChange(); 1908 for (int i = 0; i < actionList.size(); i++) { 1909 action = actionList.get(i); 1910 condName = action.description(triggerType); 1911 condText.append(" " + condName + " \n"); 1912 } // for _actionList 1913 } else { 1914 condText.append(" " + Bundle.getMessage("BrowserNoAction") + " \n\n"); // NOI18N 1915 } 1916 } // for numConditionals 1917 1918 condText.setCaretPosition(0); 1919 condText.setTabSize(4); 1920 condText.setEditable(false); 1921 return condText; 1922 } // buildConditionalListing 1923 1924 private final static Logger log = LoggerFactory.getLogger(LogixTableAction.class); 1925 1926}