001package jmri.jmrix.nce.consist; 002 003import java.awt.Dimension; 004import java.awt.GridBagConstraints; 005import java.awt.GridBagLayout; 006import java.awt.event.ActionListener; 007import java.text.MessageFormat; 008import java.util.ArrayList; 009import java.util.List; 010import java.util.Objects; 011 012import javax.annotation.Nonnull; 013import javax.swing.*; 014 015import jmri.DccLocoAddress; 016import jmri.InstanceManager; 017import jmri.jmrit.roster.RosterEntry; 018import jmri.jmrit.roster.swing.RosterEntryComboBox; 019import jmri.jmrit.throttle.ThrottleFrameManager; 020import jmri.jmrix.nce.*; 021import jmri.util.swing.JmriJOptionPane; 022 023/** 024 * Pane for user edit of NCE Consists 025 * 026 * NCE Consists are stored in Command Station (CS) memory starting at address 027 * xF500 and ending xFAFF (PH5 0x4E00 - 0x53FF). NCE supports up to 127 consists, numbered 1 to 127. 028 * They track the lead loco, rear loco, and four mid locos in the consist file. 029 * NCE cabs start at consist 127 when building and reviewing consists, so we 030 * also start with 127. Consist lead locos are stored in memory locations xF500 031 * through xF5FF (PH5 0x4E00 - 0x4EFF). Consist rear locos are stored in memory locations xF600 032 * through xF6FF (PH5 0x4F00 - 0x4FFF). Mid consist locos (four max) are stored in memory locations 033 * xF700 through xFAFF (PH5 0x500 - 0x53FF). If a long address is in use, bits 6 and 7 of the high 034 * byte are set. Example: Long address 3 = 0xc0 0x03 Short address 3 = 0x00 0x03 035 * 036 * NCE file format: 037 * 038 * :F500 (con 0 lead loco) (con 1 lead loco) ....... (con 7 lead loco) :F510 039 * (con 8 lead loco) ........ (con 15 lead loco) . . :F5F0 (con 120 lead loco) 040 * ..... (con 127 lead loco) 041 * 042 * :F600 (con 0 rear loco) (con 1 rear loco) ....... (con 7 rear loco) . . :F6F0 043 * (con 120 rear loco) ..... (con 127 rear loco) 044 * 045 * :F700 (con 0 mid loco1) (con 0 mid loco2) (con 0 mid loco3) (con 0 mid loco4) 046 * . . :FAF0 (con 126 mid loco1) .. (con 126 mid loco4)(con 127 mid loco1) .. 047 * (con 127 mid loco4) :0000 048 * 049 * @author Dan Boudreau Copyright (C) 2007 2008 Cloned from NceConsistEditFrame 050 * by 051 * @author kcameron Copyright (C) 2010, 2023 052 */ 053public class NceConsistEditPanel extends jmri.jmrix.nce.swing.NcePanel implements 054 jmri.jmrix.nce.NceListener { 055 056 NceConsistRoster nceConsistRoster = InstanceManager.getDefault(NceConsistRoster.class); 057 058 private int CONSIST_MIN = 1; // NCE doesn't use consist 0 059 private int CONSIST_MAX = 127; 060 private static final int LOC_ADR_MIN = 0; // loco address range 061 private static final int LOC_ADR_MAX = 9999; // max range for NCE 062 private static final int LOC_ADR_REPLACE = 0x3FFF; // dummy loco address 063 064 private int consistNum = 0; // consist being worked 065 private boolean newConsist = true; // new consist is displayed 066 067 private int locoPosition = LEAD; // which loco memory bank, 0 = lead, 1 = rear, 2 = mid 068 private static final int LEAD = 0; 069 private static final int REAR = 1; 070 private static final int MID = 2; 071 072 // Verify that loco isn't already a lead or rear loco 073 private int consistNumVerify; // which consist number we're checking 074 private final int[] locoVerifyList = new int[6]; // list of locos to verify 075 private int verifyType; // type of verification 076 private static final int VERIFY_DONE = 0; 077 private static final int VERIFY_LEAD_REAR = 1; // lead or rear loco 078 private static final int VERIFY_MID_FWD = 2; // mid loco foward 079 private static final int VERIFY_MID_REV = 4; // mid loco reverse 080 private static final int VERIFY_ALL = 8; // verify all locos 081 082 private int replyLen = 0; // expected byte length 083 private int waiting = 0; // to catch responses not intended for this module 084 085 // the 16 byte reply states 086 private boolean consistSearchNext = false; // next search 087 private boolean consistSearchPrevious = false; // previous search 088 private boolean locoSearch = false; // when true searching for lead or rear loco in consist 089 090 private boolean emptyConsistSearch = false; // when true searching for an empty consist 091 private boolean verifyRosterMatch = false; // when true verify that roster matches consist in NCE CS 092 093 private static final int CONSIST_ERROR = -1; 094 private static final int ADDRESS_ERROR = -1; 095 096 private int consistCount = 0; // search count not to exceed CONSIST_MAX 097 098 private boolean refresh = false; // when true, refresh loco info from CS 099 100 private static int DELAY_AFTER_CLEAR = 1000; // number of mSec to wait after sending a del loco 101 102 // member declarations 103 JLabel textConsist = new JLabel(); 104 JLabel textStatus = new JLabel(); 105 JLabel consistStatus = new JLabel(); 106 107 // major buttons 108 JButton previousButton = new JButton(); 109 JButton nextButton = new JButton(); 110 JButton getButton = new JButton(); 111 JButton throttleButton = new JButton(); 112 JButton clearCancelButton = new JButton(); 113 JButton saveLoadButton = new JButton(); 114 JButton deleteButton = new JButton(); 115 JButton backUpButton = new JButton(); 116 JButton restoreButton = new JButton(); 117 118 // check boxes 119 JCheckBox checkBoxEmpty = new JCheckBox(); 120 JCheckBox checkBoxVerify = new JCheckBox(); 121 JCheckBox checkBoxConsist = new JCheckBox(); 122 123 // consist text field 124 JTextField consistTextField = new JTextField(4); 125 126 // labels 127 JLabel textLocomotive = new JLabel(); 128 JLabel textRoster = new JLabel(); 129 JLabel textAddress = new JLabel(); 130 JLabel textAddrType = new JLabel(); 131 JLabel textDirection = new JLabel(); 132 133 JLabel textConRoster = new JLabel(); 134 JLabel textConRoadName = new JLabel(); 135 JLabel textConRoadNumber = new JLabel(); 136 JLabel textConModel = new JLabel(); 137 138 JComboBox<String> conRosterBox = nceConsistRoster.fullRosterComboBox(); 139 140 // for padding out panel 141 JLabel space1 = new JLabel(" "); 142 JLabel space2 = new JLabel(" "); 143 JLabel space3a = new JLabel(" "); 144 JLabel space3b = new JLabel(" "); 145 JLabel space3c = new JLabel(" "); 146 JLabel space3d = new JLabel(" "); 147 148 JLabel space15 = new JLabel(" "); 149 150 // lead loco 151 JLabel textLoco1 = new JLabel(); 152 JTextField locoTextField1 = new JTextField(4); 153 JComboBox<Object> locoRosterBox1 = new RosterEntryComboBox(); 154 JButton adrButton1 = new JButton(); 155 JButton cmdButton1 = new JButton(); 156 JButton dirButton1 = new JButton(); 157 158 // rear loco 159 JLabel textLoco2 = new JLabel(); 160 JTextField locoTextField2 = new JTextField(4); 161 JComboBox<Object> locoRosterBox2 = new RosterEntryComboBox(); 162 JButton adrButton2 = new JButton(); 163 JButton cmdButton2 = new JButton(); 164 JButton dirButton2 = new JButton(); 165 166 // mid loco 167 JLabel textLoco3 = new JLabel(); 168 JTextField locoTextField3 = new JTextField(4); 169 JComboBox<Object> locoRosterBox3 = new RosterEntryComboBox(); 170 JButton adrButton3 = new JButton(); 171 JButton cmdButton3 = new JButton(); 172 JButton dirButton3 = new JButton(); 173 174 // mid loco 175 JLabel textLoco4 = new JLabel(); 176 JTextField locoTextField4 = new JTextField(4); 177 JComboBox<Object> locoRosterBox4 = new RosterEntryComboBox(); 178 JButton adrButton4 = new JButton(); 179 JButton cmdButton4 = new JButton(); 180 JButton dirButton4 = new JButton(); 181 182 // mid loco 183 JLabel textLoco5 = new JLabel(); 184 JTextField locoTextField5 = new JTextField(4); 185 JComboBox<Object> locoRosterBox5 = new RosterEntryComboBox(); 186 JButton adrButton5 = new JButton(); 187 JButton cmdButton5 = new JButton(); 188 JButton dirButton5 = new JButton(); 189 190 // mid loco 191 JLabel textLoco6 = new JLabel(); 192 JTextField locoTextField6 = new JTextField(4); 193 JComboBox<Object> locoRosterBox6 = new RosterEntryComboBox(); 194 JButton adrButton6 = new JButton(); 195 JButton cmdButton6 = new JButton(); 196 JButton dirButton6 = new JButton(); 197 198 private NceTrafficController tc = null; 199 200 public NceConsistEditPanel() { 201 super(); 202 } 203 204 /** 205 * {@inheritDoc} 206 */ 207 @Override 208 public void initContext(Object context) { 209 if (context instanceof NceSystemConnectionMemo) { 210 try { 211 initComponents((NceSystemConnectionMemo) context); 212 } catch (Exception e) { 213 log.error("NceConsistEdit initContext failed"); // NOI18N 214 } 215 } 216 } 217 218 /** 219 * {@inheritDoc} 220 */ 221 @Override 222 public String getHelpTarget() { 223 return "package.jmri.jmrix.nce.consist.NceConsistEditFrame"; 224 } 225 226 /** 227 * {@inheritDoc} 228 */ 229 @Override 230 public String getTitle() { 231 StringBuilder x = new StringBuilder(); 232 if (memo != null) { 233 x.append(memo.getUserName()); 234 } else { 235 x.append("NCE_"); // NOI18N 236 } 237 x.append(": "); 238 x.append(Bundle.getMessage("NceConsistEditTitle")); 239 return x.toString(); 240 } 241 242 /** 243 * {@inheritDoc} 244 */ 245 @Override 246 @Nonnull 247 public List<JMenu> getMenus() { 248 // build menu 249 JMenu toolMenu = new JMenu(Bundle.getMessage("MenuTools")); 250 toolMenu.add(new NceConsistRosterMenu(Bundle.getMessage("RosterTitle"), 251 jmri.jmrit.roster.swing.RosterMenu.MAINMENU, this)); 252 List<JMenu> l = new ArrayList<>(); 253 l.add(toolMenu); 254 return l; 255 } 256 257 /** 258 * {@inheritDoc} 259 */ 260 @Override 261 public void initComponents(NceSystemConnectionMemo m) { 262 this.memo = m; 263 this.tc = m.getNceTrafficController(); 264 CONSIST_MIN = tc.csm.getConsistMin(); 265 CONSIST_MAX = tc.csm.getConsistMax(); 266 // the following code sets the frame's initial state 267 268 textConsist.setText(Bundle.getMessage("L_Consist")); 269 270 textStatus.setText(Bundle.getMessage("L_Status")); 271 272 consistStatus.setText(Bundle.getMessage("EditStateUNKNOWN")); 273 274 previousButton.setText(Bundle.getMessage("KeyPREVIOUS")); 275 previousButton.setToolTipText(Bundle.getMessage("ToolTipPrevious")); 276 277 nextButton.setText(Bundle.getMessage("KeyNEXT")); 278 nextButton.setToolTipText(Bundle.getMessage("ToolTipNext")); 279 280 getButton.setText(Bundle.getMessage("KeyGET")); 281 getButton.setToolTipText(Bundle.getMessage("ToolTipGet")); 282 283 consistTextField.setText(Integer.toString(CONSIST_MAX)); 284 consistTextField.setToolTipText(MessageFormat.format(Bundle.getMessage("ToolTipConsist"), CONSIST_MIN, CONSIST_MAX)); 285 consistTextField.setMaximumSize(new Dimension(consistTextField 286 .getMaximumSize().width, 287 consistTextField.getPreferredSize().height)); 288 289 textLocomotive.setText(Bundle.getMessage("L_Loco")); 290 textRoster.setText(Bundle.getMessage("L_Roster")); 291 textAddress.setText(Bundle.getMessage("L_Address")); 292 textAddrType.setText(Bundle.getMessage("L_Type")); 293 textDirection.setText(Bundle.getMessage("L_Direction")); 294 295 textConRoster.setText(Bundle.getMessage("L_Consist")); 296 textConRoadName.setText(""); 297 textConRoadNumber.setText(""); 298 textConModel.setText(""); 299 300 throttleButton.setText(Bundle.getMessage("L_Throttle")); 301 throttleButton.setEnabled(true); 302 throttleButton.setToolTipText(Bundle.getMessage("ToolTipThrottle")); 303 304 clearCancelButton.setText(Bundle.getMessage("KeyCLEAR")); 305 clearCancelButton.setEnabled(false); 306 clearCancelButton.setToolTipText(Bundle.getMessage("ToolTipClear")); 307 308 saveLoadButton.setText(Bundle.getMessage("KeySAVE")); 309 saveLoadButton.setVisible(false); 310 saveLoadButton.setEnabled(false); 311 saveLoadButton.setToolTipText(Bundle.getMessage("ToolTipSave")); 312 313 deleteButton.setText(Bundle.getMessage("KeyDELETE")); 314 deleteButton.setVisible(false); 315 deleteButton.setEnabled(false); 316 deleteButton.setToolTipText(Bundle.getMessage("ToolTipDelete")); 317 318 backUpButton.setText(Bundle.getMessage("KeyBACKUP")); 319 backUpButton.setToolTipText(Bundle.getMessage("ToolTipBackup")); 320 321 restoreButton.setText(Bundle.getMessage("KeyRESTORE")); 322 restoreButton.setToolTipText(Bundle.getMessage("ToolTipRestore")); 323 324 checkBoxEmpty.setText(Bundle.getMessage("KeyEMPTY")); 325 checkBoxEmpty.setToolTipText(Bundle.getMessage("ToolTipEmpty")); 326 327 checkBoxVerify.setText(Bundle.getMessage("KeyVERIFY")); 328 checkBoxVerify.setSelected(true); 329 checkBoxVerify.setToolTipText(Bundle.getMessage("ToolTipVerify")); 330 331 checkBoxConsist.setText(Bundle.getMessage("KeyCONSIST")); 332 checkBoxConsist.setSelected(true); 333 checkBoxConsist.setToolTipText(Bundle.getMessage("ToolTipConsistCkBox")); 334 335 initLocoFields(); 336 337 setLayout(new GridBagLayout()); 338 339 // Layout the panel by rows 340 // row 0 341 addItem(textConsist, 2, 0); 342 // row 1 343 addItem(previousButton, 1, 1); 344 addItem(consistTextField, 2, 1); 345 addItem(nextButton, 3, 1); 346 addItem(checkBoxEmpty, 5, 1); 347 // row 2 348 addItem(textStatus, 0, 2); 349 addItem(consistStatus, 1, 2); 350 addItem(getButton, 2, 2); 351 addItem(checkBoxVerify, 5, 2); 352 // row 3 353 addItem(space3a, 1, 3); 354 addItem(space3b, 2, 3); 355 addItem(space3c, 3, 3); 356 addItem(space3d, 4, 3); 357 // row 4 358 addItem(textConRoster, 1, 4); 359 // row 5 360 addItem(conRosterBox, 1, 5); 361 addItem(textConRoadName, 2, 5); 362 addItem(textConRoadNumber, 3, 5); 363 addItem(textConModel, 4, 5); 364 addItem(checkBoxConsist, 5, 5); 365 initConsistRoster(conRosterBox); 366 367 // row 6 padding for looks 368 addItem(space1, 1, 6); 369 // row 7 labels 370 addItem(textLocomotive, 0, 7); 371 addItem(textRoster, 1, 7); 372 addItem(textAddress, 2, 7); 373 addItem(textAddrType, 3, 7); 374 addItem(textDirection, 4, 7); 375 376 // row 8 Lead Locomotive 377 addLocoRow(textLoco1, locoRosterBox1, locoTextField1, adrButton1, 378 dirButton1, cmdButton1, 8); 379 // row 9 Rear Locomotive 380 addLocoRow(textLoco2, locoRosterBox2, locoTextField2, adrButton2, 381 dirButton2, cmdButton2, 9); 382 // row 10 Mid Locomotive 383 addLocoRow(textLoco3, locoRosterBox3, locoTextField3, adrButton3, 384 dirButton3, cmdButton3, 10); 385 // row 11 Mid Locomotive 386 addLocoRow(textLoco4, locoRosterBox4, locoTextField4, adrButton4, 387 dirButton4, cmdButton4, 11); 388 // row 12 Mid Locomotive 389 addLocoRow(textLoco5, locoRosterBox5, locoTextField5, adrButton5, 390 dirButton5, cmdButton5, 12); 391 // row 13 Mid Locomotive 392 addLocoRow(textLoco6, locoRosterBox6, locoTextField6, adrButton6, 393 dirButton6, cmdButton6, 13); 394 395 // row 15 padding for looks 396 addItem(space15, 2, 15); 397 // row 16 398 addItem(throttleButton, 0, 16); 399 addItem(clearCancelButton, 1, 16); 400 addItem(saveLoadButton, 2, 16); 401 addItem(deleteButton, 3, 16); 402 addItem(backUpButton, 4, 16); 403 addItem(restoreButton, 5, 16); 404 405 // setup buttons 406 addButtonAction(previousButton); 407 addButtonAction(nextButton); 408 addButtonAction(getButton); 409 addButtonAction(throttleButton); 410 addButtonAction(clearCancelButton); 411 addButtonAction(saveLoadButton); 412 addButtonAction(deleteButton); 413 addButtonAction(backUpButton); 414 addButtonAction(restoreButton); 415 416 // setup checkboxes 417 addCheckBoxAction(checkBoxConsist); 418 checkBoxConsist(); 419 } 420 421 // Previous, Next, Get, Throttle, Clear/Cancel, Save/Load, Delete, Restore & Backup buttons 422 public void buttonActionPerformed(java.awt.event.ActionEvent ae) { 423 // if we're searching ignore user 424 if (consistSearchNext || consistSearchPrevious || locoSearch) { 425 return; 426 } 427 // throttle button 428 if (ae.getSource() == throttleButton) { 429 if (!validConsist()) { 430 return; 431 } 432 int locoAddr = validLocoAdr(locoTextField1.getText()); 433 boolean isLong = (adrButton1.getText().equals(Bundle.getMessage("KeyLONG"))); 434 if (locoAddr < 0) { 435 return; 436 } 437 consistNum = validConsist(consistTextField.getText()); 438 jmri.jmrit.throttle.ThrottleFrame tf 439 = InstanceManager.getDefault(ThrottleFrameManager.class).createThrottleFrame(); 440 tf.getAddressPanel().setAddress(consistNum, false); // use consist address 441 if (JmriJOptionPane.showConfirmDialog(null, 442 Bundle.getMessage("DIALOG_Funct2Lead"), Bundle.getMessage("DIALOG_NceThrottle"), 443 JmriJOptionPane.YES_NO_OPTION) == JmriJOptionPane.YES_OPTION) { 444 tf.getAddressPanel().setAddress(locoAddr, isLong); // use lead loco address 445 } 446 tf.toFront(); 447 return; 448 } 449 // clear or cancel button 450 if (ae.getSource() == clearCancelButton) { 451 // button can be Clear or Cancel 452 if (clearCancelButton.getText().equals(Bundle.getMessage("KeyCLEAR"))) { 453 updateRoster(Bundle.getMessage("CLEARED")); 454 // set refresh flag to update panel 455 refresh = true; 456 killConsist(); 457 458 // must be cancel button 459 } else { 460 changeButtons(false); 461 consistNum = getConsist(); // reload panel 462 } 463 } 464 465 // save or load button 466 if (ae.getSource() == saveLoadButton) { 467 if (!validConsist()) { 468 return; 469 } 470 // check to see if user modified the roster 471 if (canLoad()) { 472 consistStatus.setText(Bundle.getMessage("EditStateOKAY")); 473 } else { 474 consistStatus.setText(Bundle.getMessage("EditStateERROR")); 475 saveLoadButton.setEnabled(false); 476 return; 477 } 478 enableAllLocoRows(false); 479 if (saveLoadButton.getText().equals(Bundle.getMessage("KeyLOAD"))) { 480 loadShift(); // get rid of empty mids! 481 updateRoster(consistTextField.getText()); 482 consistNum = validConsist(consistTextField.getText()); 483 // load right away or verify? 484 if (!verifyAllLocoAddr()) { 485 fullLoad(); 486 } 487 } else if (updateRoster(consistTextField.getText())) { 488 saveLoadButton.setEnabled(false); 489 consistNum = getConsist(); // reload panel 490 } 491 return; 492 } 493 494 // delete button 495 if (ae.getSource() == deleteButton) { 496 if (JmriJOptionPane.showConfirmDialog(null, 497 Bundle.getMessage("DIALOG_ConfirmDelete", Objects.requireNonNull(conRosterBox.getSelectedItem())), 498 Bundle.getMessage("DIALOG_NceDelete"), 499 JmriJOptionPane.OK_CANCEL_OPTION) != JmriJOptionPane.OK_OPTION) { 500 return; 501 } 502 deleteRoster(); 503 changeButtons(false); // yes, clear delete button 504 return; 505 } 506 if (ae.getSource() == previousButton) { 507 consistSearchPrevious = true; 508 consistNum = getConsist(); // check for valid and kick off read 509 } 510 if (ae.getSource() == nextButton) { 511 consistSearchNext = true; 512 consistNum = getConsist(); // check for valid and kick off read 513 } 514 if (ae.getSource() == getButton) { 515 // Get Consist 516 consistNum = getConsist(); 517 } 518 if (ae.getSource() == backUpButton) { 519 Thread mb = new NceConsistBackup(tc); 520 mb.setName("Consist Backup"); 521 mb.start(); 522 } 523 if (ae.getSource() == restoreButton) { 524 Thread mr = new NceConsistRestore(tc); 525 mr.setName("Consist Restore"); 526 mr.start(); 527 } 528 } 529 530 // One of six loco command buttons, add, replace or delete 531 public void buttonActionCmdPerformed(java.awt.event.ActionEvent ae) { 532 // if we're searching ignore user 533 if (consistSearchNext || consistSearchPrevious || locoSearch) { 534 return; 535 } 536 if (consistChanged()) { 537 return; 538 } 539 if (ae.getSource() == cmdButton1) { 540 modifyLocoFields(locoRosterBox1, locoTextField1, adrButton1, 541 dirButton1, cmdButton1); 542 } 543 if (ae.getSource() == cmdButton2) { 544 modifyLocoFields(locoRosterBox2, locoTextField2, adrButton2, 545 dirButton2, cmdButton2); 546 } 547 if (ae.getSource() == cmdButton3) { 548 modifyLocoFields(locoRosterBox3, locoTextField3, adrButton3, 549 dirButton3, cmdButton3); 550 } 551 if (ae.getSource() == cmdButton4) { 552 modifyLocoFields(locoRosterBox4, locoTextField4, adrButton4, 553 dirButton4, cmdButton4); 554 } 555 if (ae.getSource() == cmdButton5) { 556 modifyLocoFields(locoRosterBox5, locoTextField5, adrButton5, 557 dirButton5, cmdButton5); 558 } 559 if (ae.getSource() == cmdButton6) { 560 modifyLocoFields(locoRosterBox6, locoTextField6, adrButton6, 561 dirButton6, cmdButton6); 562 } 563 if (updateRoster(consistTextField.getText())) { 564 saveLoadButton.setEnabled(false); 565 } 566 } 567 568 // one of six loco address type buttons 569 public void buttonActionAdrPerformed(java.awt.event.ActionEvent ae) { 570 // if we're searching ignore user 571 if (consistSearchNext || consistSearchPrevious || locoSearch) { 572 return; 573 } 574 if (consistChanged()) { 575 return; 576 } 577 if (ae.getSource() == adrButton1) { 578 toggleAdrButton(locoTextField1, adrButton1); 579 } 580 if (ae.getSource() == adrButton2) { 581 toggleAdrButton(locoTextField2, adrButton2); 582 } 583 if (ae.getSource() == adrButton3) { 584 toggleAdrButton(locoTextField3, adrButton3); 585 } 586 if (ae.getSource() == adrButton4) { 587 toggleAdrButton(locoTextField4, adrButton4); 588 } 589 if (ae.getSource() == adrButton5) { 590 toggleAdrButton(locoTextField5, adrButton5); 591 } 592 if (ae.getSource() == adrButton6) { 593 toggleAdrButton(locoTextField6, adrButton6); 594 } 595 } 596 597 private void toggleAdrButton(JTextField locoTextField, JButton adrButton) { 598 if (validLocoAdr(locoTextField.getText()) < 0) { 599 return; 600 } 601 if (locoTextField.getText().equals("")) { 602 JmriJOptionPane.showMessageDialog(this, 603 Bundle.getMessage("DIALOG_EnterLocoB4AddrChg"), 604 Bundle.getMessage("DIALOG_NceConsist"), 605 JmriJOptionPane.ERROR_MESSAGE); 606 return; 607 } else { 608 if (adrButton.getText().equals(Bundle.getMessage("KeyLONG"))) { 609 if ((Integer.parseInt(locoTextField.getText()) < 128) 610 && (Integer.parseInt(locoTextField.getText()) > 0)) { 611 adrButton.setText(Bundle.getMessage("KeySHORT")); 612 } 613 } else { 614 adrButton.setText(Bundle.getMessage("KeyLONG")); 615 } 616 } 617 } 618 619 // one of six loco direction buttons 620 public void buttonActionDirPerformed(java.awt.event.ActionEvent ae) { 621 // if we're searching ignore user 622 if (consistSearchNext || consistSearchPrevious || locoSearch) { 623 return; 624 } 625 if (consistChanged()) { 626 return; 627 } 628 if (ae.getSource() == dirButton1) { 629 toggleDirButton(locoTextField1, dirButton1, cmdButton1); 630 } 631 if (ae.getSource() == dirButton2) { 632 toggleDirButton(locoTextField2, dirButton2, cmdButton2); 633 } 634 if (ae.getSource() == dirButton3) { 635 toggleDirButton(locoTextField3, dirButton3, cmdButton3); 636 } 637 if (ae.getSource() == dirButton4) { 638 toggleDirButton(locoTextField4, dirButton4, cmdButton4); 639 } 640 if (ae.getSource() == dirButton5) { 641 toggleDirButton(locoTextField5, dirButton5, cmdButton5); 642 } 643 if (ae.getSource() == dirButton6) { 644 toggleDirButton(locoTextField6, dirButton6, cmdButton6); 645 } 646 saveLoadButton.setEnabled(canLoad()); 647 } 648 649 private void toggleDirButton(JTextField locoTextField, JButton dirButton, 650 JButton cmdButton) { 651 if (validLocoAdr(locoTextField.getText()) < 0) { 652 return; 653 } 654 if (locoTextField.getText().equals("")) { 655 JmriJOptionPane.showMessageDialog(this, 656 Bundle.getMessage("DIALOG_EnterLocoB4DirChg"), 657 Bundle.getMessage("DIALOG_NceConsist"), JmriJOptionPane.ERROR_MESSAGE); 658 return; 659 } 660 cmdButton.setEnabled(true); 661 if (dirButton.getText().equals(Bundle.getMessage("KeyFWD"))) { 662 dirButton.setText(Bundle.getMessage("KeyREV")); 663 } else { 664 dirButton.setText(Bundle.getMessage("KeyFWD")); 665 } 666 } 667 668 // one of six roster select, load loco number and address length 669 public void locoSelected(java.awt.event.ActionEvent ae) { 670 if (ae.getSource() == locoRosterBox1) { 671 rosterBoxSelect(locoRosterBox1, locoTextField1, adrButton1); 672 } 673 if (ae.getSource() == locoRosterBox2) { 674 rosterBoxSelect(locoRosterBox2, locoTextField2, adrButton2); 675 } 676 if (ae.getSource() == locoRosterBox3) { 677 rosterBoxSelect(locoRosterBox3, locoTextField3, adrButton3); 678 } 679 if (ae.getSource() == locoRosterBox4) { 680 rosterBoxSelect(locoRosterBox4, locoTextField4, adrButton4); 681 } 682 if (ae.getSource() == locoRosterBox5) { 683 rosterBoxSelect(locoRosterBox5, locoTextField5, adrButton5); 684 } 685 if (ae.getSource() == locoRosterBox6) { 686 rosterBoxSelect(locoRosterBox6, locoTextField6, adrButton6); 687 } 688 } 689 690 // load a loco from roster 691 private void rosterBoxSelect(JComboBox<Object> locoRosterBox, 692 JTextField locoTextField, JButton adrButton) { 693 RosterEntry entry = null; 694 Object o = locoRosterBox.getSelectedItem(); 695 if (o.getClass().equals(RosterEntry.class)) { 696 entry = (RosterEntry) o; 697 } 698 if (entry != null) { 699 DccLocoAddress a = entry.getDccLocoAddress(); 700 701 locoTextField.setText("" + a.getNumber()); 702 if (a.isLongAddress()) { 703 adrButton.setText(Bundle.getMessage("KeyLONG")); 704 } else { 705 adrButton.setText(Bundle.getMessage("KeySHORT")); 706 } 707 // if lead loco get road number and name 708 if (locoRosterBox == locoRosterBox1) { 709 textConRoadName.setText(entry.getRoadName()); 710 textConRoadNumber.setText(entry.getRoadNumber()); 711 textConModel.setText(entry.getModel()); 712 } 713 } 714 } 715 716 // load a consist from roster 717 public void consistRosterSelected(java.awt.event.ActionEvent ae) { 718 if (consistSearchNext || consistSearchPrevious || locoSearch) { 719 return; 720 } 721 String entry = ""; 722 entry = conRosterBox.getSelectedItem().toString(); 723 log.debug("load consist {} from roster ", entry); 724 if (entry.equals("")) { 725 changeButtons(false); 726 consistNum = getConsist(); // reload panel 727 return; 728 } 729 changeButtons(true); 730 loadRosterEntry(entry); 731 } 732 733 // checkbox modified 734 public void checkBoxActionPerformed(java.awt.event.ActionEvent ae) { 735 if (ae.getSource() == checkBoxConsist) { 736 checkBoxConsist(); 737 } 738 } 739 740 private void checkBoxConsist() { 741 if (checkBoxConsist.isSelected()) { 742 conRosterBox.setEnabled(true); 743 saveLoadButton.setVisible(true); 744 saveLoadButton.setEnabled(canLoad()); 745 deleteButton.setVisible(true); 746 } else { 747 conRosterBox.setEnabled(false); 748 conRosterBox.removeActionListener(consistRosterListener); 749 conRosterBox.setSelectedIndex(0); 750 conRosterBox.addActionListener(consistRosterListener); 751 saveLoadButton.setVisible(false); 752 saveLoadButton.setEnabled(false); 753 deleteButton.setVisible(false); 754 deleteButton.setEnabled(false); 755 } 756 } 757 758 // gets the user supplied consist number and then reads NCE CS memory 759 private int getConsist() { 760 newConsist = true; 761 int consistNumber = validConsist(consistTextField.getText()); 762 if (consistNumber == CONSIST_ERROR) { 763 consistStatus.setText(Bundle.getMessage("EditStateERROR")); 764 consistSearchPrevious = false; 765 consistSearchNext = false; 766 return consistNumber; 767 } 768 if (consistSearchNext || consistSearchPrevious) { 769 consistCount = 0; // used to determine if all 127 consist have been read 770 consistStatus.setText(Bundle.getMessage("EditStateSEARCH")); 771 } else { 772 consistStatus.setText(Bundle.getMessage("EditStateWAIT")); 773 if (consistNumber == consistNum) { 774 newConsist = false; 775 } 776 } 777 778 // if busy don't request 779 if (waiting > 0) { 780 return consistNumber; 781 } 782 783 if (consistSearchNext) { 784 readConsistMemory(consistNumber - 7, LEAD); 785 } else { 786 readConsistMemory(consistNumber, LEAD); // Get or Previous button 787 } 788 return consistNumber; 789 } 790 791 /** 792 * Check for valid consist, popup error message if not 793 * 794 * @return true if valid 795 */ 796 private boolean validConsist() { 797 int consistNumber = validConsist(consistTextField.getText()); 798 if (consistNumber == CONSIST_ERROR) { 799 consistStatus.setText(Bundle.getMessage("EditStateERROR")); 800 JmriJOptionPane.showMessageDialog(this, 801 MessageFormat.format(Bundle.getMessage("ToolTipConsist"), new Object[] {CONSIST_MIN, CONSIST_MAX}), Bundle.getMessage("DIALOG_NceConsist"), 802 JmriJOptionPane.ERROR_MESSAGE); 803 return false; 804 } 805 return true; 806 } 807 808 // Check for valid consist number, return number if valid, -1 or CONSIST_ERROR if not. 809 private int validConsist(String s) { 810 int consistNumber; 811 try { 812 consistNumber = Integer.parseInt(s); 813 } catch (NumberFormatException e) { 814 return CONSIST_ERROR; 815 } 816 if (consistNumber < CONSIST_MIN || consistNumber > CONSIST_MAX) { 817 JmriJOptionPane.showMessageDialog(this, 818 Bundle.getMessage("DIALOG_ConsistOutOfRange", s, CONSIST_MIN, CONSIST_MAX), 819 Bundle.getMessage("DIALOG_NceConsist"), 820 JmriJOptionPane.ERROR_MESSAGE); 821 return CONSIST_ERROR; 822 } else { 823 return consistNumber; 824 } 825 } 826 827 /** 828 * @param s loco address 829 * @return number if valid, -1 or ADDRESS_ERROR if not 830 */ 831 private int validLocoAdr(String s) { 832 int locoAddress; 833 try { 834 locoAddress = Integer.parseInt(s); 835 } catch (NumberFormatException e) { 836 locoAddress = ADDRESS_ERROR; 837 } 838 if (locoAddress < LOC_ADR_MIN || locoAddress > LOC_ADR_MAX) { 839 JmriJOptionPane.showMessageDialog(this, 840 Bundle.getMessage("DIALOG_AddrRange"), Bundle.getMessage("DIALOG_NceConsist"), 841 JmriJOptionPane.ERROR_MESSAGE); 842 return ADDRESS_ERROR; 843 } else { 844 return locoAddress; 845 } 846 } 847 848 // check to see if user modified consist number 849 private boolean consistChanged() { 850 if (consistNum != validConsist(consistTextField.getText())) { 851 JmriJOptionPane.showMessageDialog(this, 852 Bundle.getMessage("DIALOG_PressRead", Bundle.getMessage("KeyGET")), 853 Bundle.getMessage("DIALOG_NceConsist"), 854 JmriJOptionPane.ERROR_MESSAGE); 855 return true; 856 } else { 857 newConsist = false; 858 return false; 859 } 860 } 861 862 /** 863 * Reads 16 bytes of NCE consist memory based on consist number and loco 864 * position in the consist 0=lead 1=rear 2=mid 865 */ 866 private void readConsistMemory(int consistNum, int engPosition) { 867 locoPosition = engPosition; 868 int nceMemAddr = (consistNum * 2) + tc.csm.getConsistHeadAddr(); 869 if (locoPosition == REAR) { 870 nceMemAddr = (consistNum * 2) + tc.csm.getConsistTailAddr(); 871 } 872 if (locoPosition == MID) { 873 nceMemAddr = (consistNum * 8) + tc.csm.getConsistMidAddr(); 874 } 875 log.debug("Read consist ({}) position ({}) NCE memory address ({})", consistNum, engPosition, Integer.toHexString(nceMemAddr)); 876 byte[] bl = NceBinaryCommand.accMemoryRead(nceMemAddr); 877 sendNceMessage(bl, NceMessage.REPLY_16); 878 } 879 880 NceConsistRosterEntry nceConsistRosterEntry; 881 882 private void loadRosterEntry(String entry) { 883 nceConsistRosterEntry = nceConsistRoster.entryFromTitle(entry); 884 consistTextField.setText(nceConsistRosterEntry.getConsistNumber()); 885 int cNum = validConsist(nceConsistRosterEntry.getConsistNumber()); 886 887 if (0 < cNum) { 888 log.debug("verify consist matches roster selection"); 889 verifyRosterMatch = true; 890 consistNum = getConsist(); 891 } else { 892 if (nceConsistRosterEntry.getConsistNumber().equals(Bundle.getMessage("CLEARED")) || nceConsistRosterEntry.getConsistNumber().equals("0")) { 893 log.debug("search for empty consist"); 894 consistTextField.setText(Integer.toString(CONSIST_MAX)); 895 emptyConsistSearch = true; 896 consistSearchNext = true; 897 consistNum = getConsist(); 898 loadFullRoster(nceConsistRosterEntry); 899 saveLoadButton.setEnabled(false); 900 } else { 901 JmriJOptionPane.showMessageDialog(this, 902 Bundle.getMessage("DIALOG_ConsistOutOfRange", CONSIST_MIN, CONSIST_MAX, consistNum), 903 Bundle.getMessage("DIALOG_NceConsist"), 904 JmriJOptionPane.ERROR_MESSAGE); 905 consistStatus.setText(Bundle.getMessage("EditStateERROR")); 906 } 907 } 908 } 909 910 private void loadFullRoster(NceConsistRosterEntry nceConsistRosterEntry) { 911 // get road name, number and model 912 textConRoadName.setText(nceConsistRosterEntry.getRoadName()); 913 textConRoadNumber.setText(nceConsistRosterEntry.getRoadNumber()); 914 textConModel.setText(nceConsistRosterEntry.getModel()); 915 916 // load lead loco 917 locoTextField1.setText(nceConsistRosterEntry.getLoco1DccAddress()); 918 adrButton1.setText(nceConsistRosterEntry.isLoco1LongAddress() ? Bundle.getMessage("KeyLONG") : Bundle.getMessage("KeySHORT")); 919 dirButton1.setText(convertDTD(nceConsistRosterEntry.getLoco1Direction())); 920 locoRosterBox1.setEnabled(true); 921 locoTextField1.setEnabled(true); 922 adrButton1.setEnabled(true); 923 dirButton1.setEnabled(true); 924 925 // load rear loco 926 locoTextField2.setText(nceConsistRosterEntry.getLoco2DccAddress()); 927 adrButton2.setText(nceConsistRosterEntry.isLoco2LongAddress() ? Bundle.getMessage("KeyLONG") : Bundle.getMessage("KeySHORT")); 928 dirButton2.setText(convertDTD(nceConsistRosterEntry.getLoco2Direction())); 929 locoRosterBox2.setEnabled(true); 930 locoTextField2.setEnabled(true); 931 adrButton2.setEnabled(true); 932 dirButton2.setEnabled(true); 933 934 // load Mid1 loco 935 locoTextField3.setText(nceConsistRosterEntry.getLoco3DccAddress()); 936 adrButton3.setText(nceConsistRosterEntry.isLoco3LongAddress() ? Bundle.getMessage("KeyLONG") : Bundle.getMessage("KeySHORT")); 937 dirButton3.setText(convertDTD(nceConsistRosterEntry.getLoco3Direction())); 938 locoRosterBox3.setEnabled(true); 939 locoTextField3.setEnabled(true); 940 adrButton3.setEnabled(true); 941 dirButton3.setEnabled(true); 942 943 // load Mid2 loco 944 locoTextField4.setText(nceConsistRosterEntry.getLoco4DccAddress()); 945 adrButton4.setText(nceConsistRosterEntry.isLoco4LongAddress() ? Bundle.getMessage("KeyLONG") : Bundle.getMessage("KeySHORT")); 946 dirButton4.setText(convertDTD(nceConsistRosterEntry.getLoco4Direction())); 947 locoRosterBox4.setEnabled(true); 948 locoTextField4.setEnabled(true); 949 adrButton4.setEnabled(true); 950 dirButton4.setEnabled(true); 951 952 // load Mid3 loco 953 locoTextField5.setText(nceConsistRosterEntry.getLoco5DccAddress()); 954 adrButton5.setText(nceConsistRosterEntry.isLoco5LongAddress() ? Bundle.getMessage("KeyLONG") : Bundle.getMessage("KeySHORT")); 955 dirButton5.setText(convertDTD(nceConsistRosterEntry.getLoco5Direction())); 956 locoRosterBox5.setEnabled(true); 957 locoTextField5.setEnabled(true); 958 adrButton5.setEnabled(true); 959 dirButton5.setEnabled(true); 960 961 // load Mid4 loco 962 locoTextField6.setText(nceConsistRosterEntry.getLoco6DccAddress()); 963 adrButton6.setText(nceConsistRosterEntry.isLoco6LongAddress() ? Bundle.getMessage("KeyLONG") : Bundle.getMessage("KeySHORT")); 964 dirButton6.setText(convertDTD(nceConsistRosterEntry.getLoco6Direction())); 965 locoRosterBox6.setEnabled(true); 966 locoTextField6.setEnabled(true); 967 adrButton6.setEnabled(true); 968 dirButton6.setEnabled(true); 969 } 970 971 /** 972 * checks to see if all loco addresses in NCE consist match roster updates 973 * road name, road number, and loco direction fields 974 * 975 * @return true if match 976 */ 977 private boolean consistRosterMatch(NceConsistRosterEntry nceConsistRosterEntry) { 978 if (consistTextField.getText().equals(nceConsistRosterEntry.getConsistNumber()) 979 && locoTextField1.getText().equals(nceConsistRosterEntry.getLoco1DccAddress()) 980 && locoTextField2.getText().equals(nceConsistRosterEntry.getLoco2DccAddress()) 981 && locoTextField3.getText().equals(nceConsistRosterEntry.getLoco3DccAddress()) 982 && locoTextField4.getText().equals(nceConsistRosterEntry.getLoco4DccAddress()) 983 && locoTextField5.getText().equals(nceConsistRosterEntry.getLoco5DccAddress()) 984 && locoTextField6.getText().equals(nceConsistRosterEntry.getLoco6DccAddress())) { 985 // match! Only load the elements needed 986 if (newConsist) { 987 textConRoadName.setText(nceConsistRosterEntry.getRoadName()); 988 textConRoadNumber.setText(nceConsistRosterEntry.getRoadNumber()); 989 textConModel.setText(nceConsistRosterEntry.getModel()); 990 dirButton1.setText(convertDTD(nceConsistRosterEntry.getLoco1Direction())); 991 dirButton2.setText(convertDTD(nceConsistRosterEntry.getLoco2Direction())); 992 dirButton3.setText(convertDTD(nceConsistRosterEntry.getLoco3Direction())); 993 dirButton4.setText(convertDTD(nceConsistRosterEntry.getLoco4Direction())); 994 dirButton5.setText(convertDTD(nceConsistRosterEntry.getLoco5Direction())); 995 dirButton6.setText(convertDTD(nceConsistRosterEntry.getLoco6Direction())); 996 } 997 return true; 998 } else { 999 return false; 1000 } 1001 } 1002 1003 private final boolean enablePartialMatch = true; 1004 1005 /** 1006 * checks to see if some loco addresses in NCE consist match roster updates 1007 * road name, road number, and loco direction fields 1008 * 1009 * @return true if there was at least one match 1010 */ 1011 private boolean consistRosterPartialMatch(NceConsistRosterEntry cre) { 1012 if (!enablePartialMatch) { 1013 return false; 1014 } 1015 // does loco1 match? 1016 if (consistTextField.getText().equals(cre.getConsistNumber()) 1017 && locoTextField1.getText().equals(cre.getLoco1DccAddress())) { 1018 dirButton1.setText(convertDTD(cre.getLoco1Direction())); 1019 textConRoadName.setText(cre.getRoadName()); 1020 textConRoadNumber.setText(cre.getRoadNumber()); 1021 textConModel.setText(cre.getModel()); 1022 } else { 1023 consistStatus.setText(Bundle.getMessage("EditStateUNKNOWN")); 1024 return false; 1025 } 1026 if (locoTextField2.getText().equals(cre.getLoco2DccAddress())) { 1027 dirButton2.setText(convertDTD(cre.getLoco2Direction())); 1028 } 1029 if (locoTextField3.getText().equals(cre.getLoco3DccAddress())) { 1030 dirButton3.setText(convertDTD(cre.getLoco3Direction())); 1031 } 1032 if (locoTextField4.getText().equals(cre.getLoco4DccAddress())) { 1033 dirButton4.setText(convertDTD(cre.getLoco4Direction())); 1034 } 1035 if (locoTextField5.getText().equals(cre.getLoco5DccAddress())) { 1036 dirButton5.setText(convertDTD(cre.getLoco5Direction())); 1037 } 1038 if (locoTextField6.getText().equals(cre.getLoco6DccAddress())) { 1039 dirButton6.setText(convertDTD(cre.getLoco6Direction())); 1040 } 1041 consistStatus.setText(Bundle.getMessage("EditStateMODIFIED")); 1042 return true; 1043 } 1044 1045 protected List<NceConsistRosterEntry> consistList = new ArrayList<>(); 1046 1047 /** 1048 * returns true if update successful 1049 */ 1050 private boolean updateRoster(String consistNumber) { 1051 if (!checkBoxConsist.isSelected()) { 1052 return false; 1053 } 1054 String id = locoTextField1.getText(); // lead loco is the consist id 1055 if (id.equals("")) { 1056 log.debug("Attempt to modify consist without valid id"); 1057 return false; 1058 } 1059 // need rear loco to form a consist 1060 if (locoTextField2.getText().equals("")) { 1061 return false; 1062 } 1063 NceConsistRosterEntry nceConsistRosterEntry; 1064 consistList = nceConsistRoster.matchingList(null, null, 1065 null, null, null, null, null, null, null, id); 1066 // if consist doesn't exist in roster ask user if they want to create one 1067 if (consistList.isEmpty()) { 1068 if (JmriJOptionPane.showConfirmDialog(null, Bundle.getMessage("DIALOG_ConfirmAdd", id), 1069 Bundle.getMessage("DIALOG_NceSave"), 1070 JmriJOptionPane.YES_NO_OPTION) != JmriJOptionPane.YES_OPTION) { 1071 return false; 1072 } 1073 nceConsistRosterEntry = new NceConsistRosterEntry(); 1074 nceConsistRoster.addEntry(nceConsistRosterEntry); 1075 // roster entry exists, does it match? 1076 } else { 1077 nceConsistRosterEntry = nceConsistRoster.entryFromTitle(id); 1078 // if all of the loco addresses match, just update without telling user 1079 consistList = nceConsistRoster 1080 .matchingList(null, null, null, locoTextField1.getText(), 1081 locoTextField2.getText(), locoTextField3.getText(), 1082 locoTextField4.getText(), locoTextField5.getText(), 1083 locoTextField6.getText(), id); 1084 // if it doesn't match, do we want to modify it? 1085 if (consistList.isEmpty()) { 1086 if (JmriJOptionPane.showConfirmDialog(null, 1087 Bundle.getMessage("DIALOG_ConfirmUpdate", id, getRosterText(nceConsistRosterEntry)), 1088 Bundle.getMessage("DIALOG_NceUpdate"), 1089 JmriJOptionPane.YES_NO_OPTION) == JmriJOptionPane.NO_OPTION ) { 1090 // update consist if command was to clear 1091 if (consistNumber.equals(Bundle.getMessage("CLEARED"))) { 1092 nceConsistRosterEntry.setConsistNumber(consistNumber); 1093 writeRosterFile(); 1094 } 1095 return false; 1096 } 1097 } 1098 log.debug("Modify consist {}", id); 1099 } 1100 // save all elements of a consist roster 1101 nceConsistRosterEntry.setId(id); 1102 nceConsistRosterEntry.setConsistNumber(consistNumber); 1103 nceConsistRosterEntry.setRoadName(textConRoadName.getText()); 1104 nceConsistRosterEntry.setRoadNumber(textConRoadNumber.getText()); 1105 nceConsistRosterEntry.setModel(textConModel.getText()); 1106 // save lead loco 1107 nceConsistRosterEntry.setLoco1DccAddress(locoTextField1.getText()); 1108 nceConsistRosterEntry.setLoco1LongAddress(adrButton1.getText().equals(Bundle.getMessage("KeyLONG"))); 1109 nceConsistRosterEntry.setLoco1Direction(directionDTD(dirButton1)); 1110 // save rear loco 1111 nceConsistRosterEntry.setLoco2DccAddress(locoTextField2.getText()); 1112 nceConsistRosterEntry.setLoco2LongAddress(adrButton2.getText().equals(Bundle.getMessage("KeyLONG"))); 1113 nceConsistRosterEntry.setLoco2Direction(directionDTD(dirButton2)); 1114 // save Mid1 loco 1115 nceConsistRosterEntry.setLoco3DccAddress(locoTextField3.getText()); 1116 nceConsistRosterEntry.setLoco3LongAddress(adrButton3.getText().equals(Bundle.getMessage("KeyLONG"))); 1117 nceConsistRosterEntry.setLoco3Direction(directionDTD(dirButton3)); 1118 // save Mid2 loco 1119 nceConsistRosterEntry.setLoco4DccAddress(locoTextField4.getText()); 1120 nceConsistRosterEntry.setLoco4LongAddress(adrButton4.getText().equals(Bundle.getMessage("KeyLONG"))); 1121 nceConsistRosterEntry.setLoco4Direction(directionDTD(dirButton4)); 1122 // save Mid3 loco 1123 nceConsistRosterEntry.setLoco5DccAddress(locoTextField5.getText()); 1124 nceConsistRosterEntry.setLoco5LongAddress(adrButton5.getText().equals(Bundle.getMessage("KeyLONG"))); 1125 nceConsistRosterEntry.setLoco5Direction(directionDTD(dirButton5)); 1126 // save Mid4 loco 1127 nceConsistRosterEntry.setLoco6DccAddress(locoTextField6.getText()); 1128 nceConsistRosterEntry.setLoco6LongAddress(adrButton6.getText().equals(Bundle.getMessage("KeyLONG"))); 1129 nceConsistRosterEntry.setLoco6Direction(directionDTD(dirButton6)); 1130 1131 writeRosterFile(); 1132 return true; 1133 } 1134 1135 /** 1136 * @return DTD direction format based on the loco direction button 1137 */ 1138 private String directionDTD(JButton dirButton) { 1139 String formatDTD = Bundle.getMessage("DTD_UNKNOWN"); 1140 if (dirButton.getText().equals(Bundle.getMessage("KeyFWD"))) { 1141 formatDTD = Bundle.getMessage("DTD_FORWARD"); 1142 } 1143 if (dirButton.getText().equals(Bundle.getMessage("KeyREV"))) { 1144 formatDTD = Bundle.getMessage("DTD_REVERSE"); 1145 } 1146 return formatDTD; 1147 } 1148 1149 /** 1150 * @return converts DTD direction to FWD, REV, and ?? 1151 */ 1152 private String convertDTD(String formatDTD) { 1153 String word = Bundle.getMessage("KeyQUESTION"); 1154 if (formatDTD.equals(Bundle.getMessage("DTD_FORWARD"))) { 1155 word = Bundle.getMessage("KeyFWD"); 1156 } 1157 if (formatDTD.equals(Bundle.getMessage("DTD_REVERSE"))) { 1158 word = Bundle.getMessage("KeyREV"); 1159 } 1160 return word; 1161 } 1162 1163 /** 1164 * @return converts DTD direction to FWD, REV, and "" 1165 */ 1166 private String shortHandConvertDTD(String formatDTD) { 1167 String word = ""; 1168 if (formatDTD.equals(Bundle.getMessage("DTD_FORWARD"))) { 1169 word = Bundle.getMessage("KeyFWD"); 1170 } 1171 if (formatDTD.equals(Bundle.getMessage("DTD_REVERSE"))) { 1172 word = Bundle.getMessage("KeyREV"); 1173 } 1174 return word; 1175 } 1176 1177 // remove selected consist from roster 1178 private void deleteRoster() { 1179 String entry = conRosterBox.getSelectedItem().toString(); 1180 log.debug("remove consist {} from roster ", entry); 1181 // delete it from roster 1182 nceConsistRoster.removeEntry(nceConsistRoster.entryFromTitle(entry)); 1183 writeRosterFile(); 1184 } 1185 1186 private void writeRosterFile() { 1187 conRosterBox.removeActionListener(consistRosterListener); 1188 nceConsistRoster.writeRosterFile(); 1189 nceConsistRoster.updateComboBox(conRosterBox); 1190 conRosterBox.insertItemAt("", 0); 1191 conRosterBox.setSelectedIndex(0); 1192 conRosterBox.addActionListener(consistRosterListener); 1193 } 1194 1195 // can the consist be loaded into NCE memory? 1196 private boolean canLoad() { 1197 if (locoTextField1.getText().equals("")) { 1198 return false; 1199 } 1200 if (dirButton1.getText().equals(Bundle.getMessage("KeyQUESTION"))) { 1201 return false; 1202 } 1203 if (locoTextField2.getText().equals("")) { 1204 return false; 1205 } 1206 if (dirButton2.getText().equals(Bundle.getMessage("KeyQUESTION"))) { 1207 return false; 1208 } 1209 if (!locoTextField3.getText().equals("") 1210 && dirButton3.getText().equals(Bundle.getMessage("KeyQUESTION"))) { 1211 return false; 1212 } 1213 if (!locoTextField4.getText().equals("") 1214 && dirButton4.getText().equals(Bundle.getMessage("KeyQUESTION"))) { 1215 return false; 1216 } 1217 if (!locoTextField5.getText().equals("") 1218 && dirButton5.getText().equals(Bundle.getMessage("KeyQUESTION"))) { 1219 return false; 1220 } 1221 if (!locoTextField6.getText().equals("") 1222 && dirButton6.getText().equals(Bundle.getMessage("KeyQUESTION"))) { 1223 return false; 1224 } 1225 // okay to load, clean up empty loco fields 1226 if (locoTextField3.getText().equals("")) { 1227 dirButton3.setText(Bundle.getMessage("KeyQUESTION")); 1228 } 1229 if (locoTextField4.getText().equals("")) { 1230 dirButton4.setText(Bundle.getMessage("KeyQUESTION")); 1231 } 1232 if (locoTextField5.getText().equals("")) { 1233 dirButton5.setText(Bundle.getMessage("KeyQUESTION")); 1234 } 1235 if (locoTextField6.getText().equals("")) { 1236 dirButton6.setText(Bundle.getMessage("KeyQUESTION")); 1237 } 1238 if (saveLoadButton.getText().equals(Bundle.getMessage("KeyLOAD"))) { 1239 return true; 1240 } else if (exactMatch) { 1241 return false; // no need to save, exact match! 1242 } else { 1243 return true; 1244 } 1245 } 1246 1247 // mimic NCE mid loco shift when there's empties 1248 private void loadShift() { 1249 for (int i = 0; i < 3; i++) { 1250 shiftOneLine(locoTextField5, adrButton5, dirButton5, locoTextField6, 1251 adrButton6, dirButton6); 1252 shiftOneLine(locoTextField4, adrButton4, dirButton4, locoTextField5, 1253 adrButton5, dirButton5); 1254 shiftOneLine(locoTextField3, adrButton3, dirButton3, locoTextField4, 1255 adrButton4, dirButton4); 1256 shiftOneLine(locoTextField2, adrButton2, dirButton2, locoTextField3, 1257 adrButton3, dirButton3); 1258 } 1259 } 1260 1261 private void shiftOneLine(JTextField locoTextFieldLow, JButton adrButtonLow, 1262 JButton dirButtonLow, JTextField locoTextFieldHigh, 1263 JButton adrButtonHigh, JButton dirButtonHigh) { 1264 if (locoTextFieldLow.getText().equals("") && !locoTextFieldHigh.getText().equals((""))) { 1265 locoTextFieldLow.setText(locoTextFieldHigh.getText()); 1266 adrButtonLow.setText(adrButtonHigh.getText()); 1267 dirButtonLow.setText(dirButtonHigh.getText()); 1268 dirButtonHigh.setText(Bundle.getMessage("KeyQUESTION")); 1269 locoTextFieldHigh.setText(""); 1270 } else { 1271 return; 1272 } 1273 } 1274 1275 // change button operation during load consist from roster 1276 private void changeButtons(boolean rosterDisplay) { 1277 if (rosterDisplay) { 1278 clearCancelButton.setText(Bundle.getMessage("KeyCANCEL")); 1279 clearCancelButton.setToolTipText(Bundle.getMessage("ToolTipCancel")); 1280 clearCancelButton.setEnabled(true); 1281 saveLoadButton.setText(Bundle.getMessage("KeyLOAD")); 1282 saveLoadButton.setToolTipText(Bundle.getMessage("ToolTipLoad")); 1283 } else { 1284 clearCancelButton.setText(Bundle.getMessage("KeyCLEAR")); 1285 clearCancelButton.setToolTipText(Bundle.getMessage("ToolTipClear")); 1286 saveLoadButton.setText(Bundle.getMessage("KeySAVE")); 1287 saveLoadButton.setToolTipText(Bundle.getMessage("ToolTipSave")); 1288 clearCancelButton.setEnabled(!locoTextField1.getText().equals("")); 1289 } 1290 1291 // toggle (on if we're loading a consist from roster) 1292 deleteButton.setEnabled(rosterDisplay); 1293 1294 // toggle (off if we're loading a consist from roster) 1295 previousButton.setEnabled(!rosterDisplay); 1296 nextButton.setEnabled(!rosterDisplay); 1297 getButton.setEnabled(!rosterDisplay); 1298 backUpButton.setEnabled(!rosterDisplay); 1299 restoreButton.setEnabled(!rosterDisplay); 1300 saveLoadButton.setEnabled(!rosterDisplay); 1301 1302 cmdButton1.setVisible(!rosterDisplay); 1303 cmdButton2.setVisible(!rosterDisplay); 1304 cmdButton3.setVisible(!rosterDisplay); 1305 cmdButton4.setVisible(!rosterDisplay); 1306 cmdButton5.setVisible(!rosterDisplay); 1307 cmdButton6.setVisible(!rosterDisplay); 1308 } 1309 1310 /** 1311 * Kills consist using lead loco address 1312 */ 1313 private void killConsist() { 1314 if (validLocoAdr(locoTextField1.getText()) < 0) // special case where lead or rear loco was being replaced 1315 { 1316 return; 1317 } 1318 int locoAddr = getLocoAddr(locoTextField1, adrButton1); 1319 sendNceBinaryCommand(locoAddr, NceMessage.LOCO_CMD_KILL_CONSIST, 1320 (byte) 0); 1321 } 1322 1323 private void sendNceBinaryCommand(int locoAddr, byte nceLocoCmd, 1324 byte consistNumber) { 1325 byte[] bl = NceBinaryCommand.nceLocoCmd(locoAddr, nceLocoCmd, 1326 consistNumber); 1327 sendNceMessage(bl, NceMessage.REPLY_1); 1328 } 1329 1330 @Override 1331 public void message(NceMessage m) { 1332 } // ignore replies 1333 1334 // NCE CS response from add, delete, save, get, next, previous, etc 1335 // A single byte response is expected from commands 1336 // A 16 byte response is expected when loading a consist or searching 1337 @Override 1338 public void reply(NceReply nceReply) { 1339 if (waiting <= 0) { 1340 log.error("unexpected response"); 1341 return; 1342 } 1343 waiting--; 1344 1345 if (nceReply.getNumDataElements() != replyLen) { 1346 consistStatus.setText(Bundle.getMessage("EditStateERROR")); 1347 log.error("reply length error, expecting: {} got: {}", replyLen, nceReply.getNumDataElements()); 1348 return; 1349 } 1350 1351 // response to commands 1352 if (replyLen == NceMessage.REPLY_1) { 1353 // Looking for proper response 1354 int recChar = nceReply.getElement(0); 1355 log.debug("command reply: {}", recChar); 1356 if (recChar == NceMessage.NCE_OKAY) { 1357 if (locoSearch && waiting == 0) { 1358 readConsistMemory(consistNumVerify, LEAD); 1359 consistStatus.setText(Bundle.getMessage("EditStateVERIFY")); 1360 return; 1361 } 1362 if (refresh && waiting == 0) { 1363 refresh = false; 1364 // update panel 1365 readConsistMemory(consistNum, LEAD); 1366 return; 1367 } 1368 consistStatus.setText(Bundle.getMessage("EditStateOKAY")); 1369 } else { 1370 consistStatus.setText(Bundle.getMessage("EditStateERROR")); 1371 } 1372 return; 1373 } 1374 1375 // Consist memory read 1376 if (replyLen == NceMessage.REPLY_16) { 1377 // are we verifying that loco isn't already part of a consist? 1378 if (locoSearch) { 1379 // search the 16 bytes for a loco match 1380 for (int i = 0; i < NceMessage.REPLY_16;) { 1381 int recChar_High = nceReply.getElement(i++); 1382 recChar_High = (recChar_High << 8) & 0xFF00; 1383 int recChar_Low = nceReply.getElement(i++); 1384 recChar_Low = recChar_Low & 0xFF; 1385 int locoAddress = recChar_High + recChar_Low; 1386 // does it match any of the locos? 1387 for (int j = 0; j < locoVerifyList.length; j++) { 1388 if (locoVerifyList[j] == 0) { 1389 break; // done searching 1390 } 1391 if (locoAddress == locoVerifyList[j]) { 1392 // ignore matching the consist that we're adding the 1393 // loco 1394 if (consistNumVerify != consistNum) { 1395 locoSearch = false; // quit the search 1396 consistStatus.setText(Bundle.getMessage("EditStateERROR")); 1397 locoNumInUse = locoAddress & 0x3FFF; 1398 queueError(ERROR_LOCO_IN_USE); 1399 return; 1400 } 1401 } 1402 } 1403 consistNumVerify++; 1404 } 1405 if (consistNumVerify > CONSIST_MAX) { 1406 if (locoPosition == LEAD) { 1407 // now verify the rear loco consist 1408 locoPosition = REAR; 1409 consistNumVerify = 0; 1410 } else { 1411 // verify complete, loco address is unique 1412 locoSearch = false; 1413 consistStatus.setText(Bundle.getMessage("EditStateOKAY")); 1414 // determine the type of verification 1415 if (verifyType == VERIFY_LEAD_REAR) { 1416 if (refresh && waiting == 0) { 1417 refresh = false; 1418 // update panel 1419 readConsistMemory(consistNum, LEAD); 1420 } 1421 } else if (verifyType == VERIFY_MID_FWD) { 1422 sendNceBinaryCommand(locoVerifyList[0], 1423 NceMessage.LOCO_CMD_FWD_CONSIST_MID, 1424 (byte) consistNum); 1425 } else if (verifyType == VERIFY_MID_REV) { 1426 sendNceBinaryCommand(locoVerifyList[0], 1427 NceMessage.LOCO_CMD_REV_CONSIST_MID, 1428 (byte) consistNum); 1429 } else if (verifyType == VERIFY_ALL) { 1430 fullLoad(); 1431 } else { 1432 log.debug("verifyType out of range"); 1433 } 1434 verifyType = VERIFY_DONE; 1435 return; 1436 } 1437 } 1438 // continue verify 1439 readConsistMemory(consistNumVerify, locoPosition); 1440 return; 1441 } 1442 // are we searching for a consist? 1443 if (consistSearchNext) { 1444 for (int i = NceMessage.REPLY_16 - 1; i > 0;) { 1445 int recChar_Low = nceReply.getElement(i--); 1446 recChar_Low = recChar_Low & 0xFF; 1447 int recChar_High = nceReply.getElement(i--); 1448 recChar_High = (recChar_High << 8) & 0xFF00; 1449 int locoAddress = recChar_High + recChar_Low; 1450 1451 if (emptyConsistSearch) { 1452 if (locoAddress == 0) { 1453 // found an empty consist! 1454 consistSearchNext = false; 1455 emptyConsistSearch = false; 1456 consistStatus.setText(Bundle.getMessage("EditStateOKAY")); 1457 saveLoadButton.setEnabled(canLoad()); 1458 return; 1459 } 1460 } else if (checkBoxEmpty.isSelected()) { 1461 if (locoAddress == 0 && consistCount > 0) { 1462 // found an empty consist! 1463 log.debug("Empty consist ({})", consistNum); 1464 consistSearchNext = false; 1465 // update the panel 1466 readConsistMemory(consistNum, LEAD); 1467 return; 1468 } 1469 } else if (locoAddress != 0 && consistCount > 0) { 1470 // found a consist! 1471 consistSearchNext = false; 1472 readConsistMemory(consistNum, LEAD); 1473 return; 1474 } 1475 if (++consistCount > CONSIST_MAX) { 1476 // could not find a consist 1477 consistSearchNext = false; 1478 consistStatus.setText(Bundle.getMessage("EditStateNONE")); 1479 if (emptyConsistSearch) { 1480 emptyConsistSearch = false; 1481 queueError(ERROR_NO_EMPTY_CONSIST); 1482 } 1483 return; // don't update panel 1484 } 1485 // look for next consist 1486 consistNum--; 1487 if (consistNum < CONSIST_MIN) { 1488 consistNum = CONSIST_MAX; 1489 } 1490 consistTextField.setText(Integer.toString(consistNum)); 1491 if (consistNum == CONSIST_MAX) { 1492 // we need to read NCE memory to continue 1493 break; 1494 } 1495 } 1496 // continue searching 1497 readConsistMemory(consistNum - 7, LEAD); 1498 return; 1499 } 1500 // are we searching? 1501 if (consistSearchPrevious) { 1502 for (int i = 0; i < NceMessage.REPLY_16;) { 1503 int recChar_High = nceReply.getElement(i++); 1504 recChar_High = (recChar_High << 8) & 0xFF00; 1505 int recChar_Low = nceReply.getElement(i++); 1506 recChar_Low = recChar_Low & 0xFF; 1507 int locoAddress = recChar_High + recChar_Low; 1508 1509 if (checkBoxEmpty.isSelected()) { 1510 if (locoAddress == 0 && consistCount > 0) { 1511 consistSearchPrevious = false; 1512 break; 1513 } 1514 } else if (locoAddress != 0 && consistCount > 0) { 1515 consistSearchPrevious = false; 1516 break; 1517 } 1518 if (++consistCount > CONSIST_MAX) { 1519 consistStatus.setText(Bundle.getMessage("EditStateNONE")); 1520 consistSearchPrevious = false; 1521 return; // don't update the panel 1522 } 1523 consistNum++; 1524 if (consistNum > CONSIST_MAX) { 1525 consistNum = CONSIST_MIN; 1526 } 1527 consistTextField.setText(Integer.toString(consistNum)); 1528 // have we wrapped? if yes, need to read NCE memory 1529 if (consistNum == CONSIST_MIN) { 1530 break; 1531 } 1532 } 1533 readConsistMemory(consistNum, LEAD); 1534 return; 1535 } 1536 1537 // Panel update, load lead loco 1538 if (locoPosition == LEAD) { 1539 boolean loco1exists = updateLocoFields(nceReply, 0, locoRosterBox1, 1540 locoTextField1, adrButton1, dirButton1, cmdButton1); 1541 if (clearCancelButton.getText().equals(Bundle.getMessage("KeyCLEAR"))) { 1542 clearCancelButton.setEnabled(loco1exists); 1543 } 1544 1545 // load rear loco 1546 } else if (locoPosition == REAR) { 1547 updateLocoFields(nceReply, 0, locoRosterBox2, locoTextField2, 1548 adrButton2, dirButton2, cmdButton2); 1549 1550 // load mid locos 1551 } else { 1552 updateLocoFields(nceReply, 0, locoRosterBox3, locoTextField3, 1553 adrButton3, dirButton3, cmdButton3); 1554 updateLocoFields(nceReply, 2, locoRosterBox4, locoTextField4, 1555 adrButton4, dirButton4, cmdButton4); 1556 updateLocoFields(nceReply, 4, locoRosterBox5, locoTextField5, 1557 adrButton5, dirButton5, cmdButton5); 1558 updateLocoFields(nceReply, 6, locoRosterBox6, locoTextField6, 1559 adrButton6, dirButton6, cmdButton6); 1560 consistStatus.setText(Bundle.getMessage("EditStateOKAY")); 1561 checkForRosterMatch(); 1562 saveLoadButton.setEnabled(canLoad()); 1563 } 1564 // read the next loco number in the consist 1565 if (locoPosition == LEAD || locoPosition == REAR) { 1566 locoPosition++; 1567 readConsistMemory(consistNum, locoPosition); 1568 } 1569 } 1570 } 1571 1572 private boolean exactMatch = false; 1573 1574 private void checkForRosterMatch() { 1575 exactMatch = false; 1576 if (!verifyRosterMatch) { 1577 nceConsistRosterEntry = nceConsistRoster.entryFromTitle(locoTextField1.getText()); 1578 } 1579 if (nceConsistRosterEntry == null) { 1580 if (checkBoxConsist.isSelected() && !locoTextField1.getText().equals("")) { 1581 consistStatus.setText(Bundle.getMessage("EditStateUNKNOWN")); 1582 } else { 1583 textConRoadName.setText(""); 1584 } 1585 textConRoadNumber.setText(""); 1586 textConModel.setText(""); 1587 return; 1588 } 1589 if (consistRosterMatch(nceConsistRosterEntry)) { 1590 exactMatch = true; 1591 // exact match! 1592 if (verifyRosterMatch) { 1593 queueError(WARN_CONSIST_ALREADY_LOADED); 1594 } 1595 verifyRosterMatch = false; 1596 } else { 1597 // not an exact match! 1598 if (verifyRosterMatch) { 1599 queueError(ERROR_CONSIST_DOESNT_MATCH); 1600 } 1601 verifyRosterMatch = false; 1602 if (!consistRosterPartialMatch(nceConsistRosterEntry)) { 1603 textConRoadName.setText(""); 1604 textConRoadNumber.setText(""); 1605 textConModel.setText(""); 1606 } 1607 } 1608 } 1609 1610 // update loco fields, returns false if loco address is null 1611 private boolean updateLocoFields(NceReply r, int index, 1612 JComboBox<Object> locoRosterBox, JTextField locoTextField, 1613 JButton adrButton, JButton dirButton, JButton cmdButton) { 1614 // index = 0 for lead and rear locos, 0,2,4,6 for mid 1615 String locoAddrText = getLocoAddrText(r, index); 1616 boolean locoType = getLocoAddressType(r, index); // Long or short address? 1617 String locoDirection = getLocoDirection(dirButton); 1618 1619 locoTextField.setText(locoAddrText); 1620 locoRosterBox.setSelectedIndex(0); 1621 1622 if (locoAddrText.equals("") || locoAddrText.equals(Bundle.getMessage("REPLACE_LOCO"))) { 1623 locoRosterBox.setEnabled(true); 1624 locoTextField.setEnabled(true); 1625 cmdButton.setText(Bundle.getMessage("KeyADD")); 1626 cmdButton.setVisible(true); 1627 cmdButton.setEnabled(false); 1628 cmdButton.setToolTipText(Bundle.getMessage("ToolTipAdd")); 1629 dirButton.setText(Bundle.getMessage("KeyQUESTION")); 1630 dirButton.setEnabled(true); 1631 adrButton.setText(Bundle.getMessage("KeyLONG")); 1632 adrButton.setEnabled(true); 1633 return false; 1634 } else { 1635 locoTextField.setText(locoAddrText); 1636 locoRosterBox.setEnabled(false); 1637 locoTextField.setEnabled(false); 1638 cmdButton.setEnabled(true); 1639 dirButton.setText(locoDirection); 1640 dirButton.setEnabled(false); 1641 adrButton.setText((locoType) ? Bundle.getMessage("KeyLONG") : Bundle.getMessage("KeySHORT")); 1642 adrButton.setEnabled(false); 1643 1644 // can not delete lead or rear locos, but can replace 1645 if (locoTextField == locoTextField1 || locoTextField == locoTextField2) { 1646 cmdButton.setText(Bundle.getMessage("KeyREPLACE")); 1647 cmdButton.setToolTipText("Press to delete and replace this loco"); 1648 } else { 1649 cmdButton.setText(Bundle.getMessage("KeyDELETE")); 1650 cmdButton.setToolTipText("Press to delete this loco from consist"); 1651 } 1652 return true; 1653 } 1654 } 1655 1656 // modify loco fields because an Add, Replace, Delete button has been pressed 1657 private void modifyLocoFields(JComboBox<Object> locoRosterBox, 1658 JTextField locoTextField, JButton adrButton, JButton dirButton, 1659 JButton cmdButton) { 1660 if (validLocoAdr(locoTextField.getText()) < 0) { 1661 return; 1662 } 1663 byte consistNumber = (byte) validConsist(consistTextField.getText()); 1664 if (consistNumber < 0) { 1665 return; 1666 } 1667 if (locoTextField.getText().equals("")) { 1668 JmriJOptionPane.showMessageDialog(this, 1669 Bundle.getMessage("DIALOG_EnterLocoB4Add"), 1670 Bundle.getMessage("DIALOG_NceConsist"), 1671 JmriJOptionPane.ERROR_MESSAGE); 1672 return; 1673 } 1674 // set reflesh flag to update panel 1675 refresh = true; 1676 int locoAddr = getLocoAddr(locoTextField, adrButton); 1677 1678 if (cmdButton.getText().equals(Bundle.getMessage("KeyDELETE"))) { 1679 sendNceBinaryCommand(locoAddr, 1680 NceMessage.LOCO_CMD_DELETE_LOCO_CONSIST, (byte) 0); 1681 1682 } else if (cmdButton.getText().equals(Bundle.getMessage("KeyREPLACE"))) { 1683 1684 // Kill refresh flag, no update when replacing loco 1685 refresh = false; 1686 1687 // allow user to add loco to lead or rear consist 1688 locoRosterBox.setEnabled(true); 1689 locoTextField.setText(""); 1690 locoTextField.setEnabled(true); 1691 adrButton.setText(Bundle.getMessage("KeyLONG")); 1692 adrButton.setEnabled(true); 1693 dirButton.setText(Bundle.getMessage("KeyQUESTION")); 1694 dirButton.setEnabled(true); 1695 cmdButton.setText(Bundle.getMessage("KeyADD")); 1696 cmdButton.setToolTipText(Bundle.getMessage("ToolTipAdd")); 1697 1698 // now update CS memory in case user doesn't use the Add button 1699 // this will also allow us to delete the loco from the layout 1700 if (locoTextField == locoTextField1) { 1701 // replace lead loco 1702 sendNceBinaryCommand(LOC_ADR_REPLACE, 1703 NceMessage.LOCO_CMD_FWD_CONSIST_LEAD, consistNumber); 1704 // no lead loco so we can't kill the consist 1705 clearCancelButton.setEnabled(false); 1706 } else { 1707 // replace rear loco 1708 sendNceBinaryCommand(LOC_ADR_REPLACE, 1709 NceMessage.LOCO_CMD_FWD_CONSIST_REAR, consistNumber); 1710 } 1711 // now delete lead or rear loco from layout 1712 sendNceBinaryCommand(locoAddr, 1713 NceMessage.LOCO_CMD_DELETE_LOCO_CONSIST, (byte) 0); 1714 } else { 1715 // ADD button has been pressed 1716 if (dirButton.getText().equals(Bundle.getMessage("KeyQUESTION"))) { 1717 JmriJOptionPane.showMessageDialog(this, 1718 Bundle.getMessage("DIALOG_SetDirB4Consist"), 1719 Bundle.getMessage("DIALOG_NceConsist"), JmriJOptionPane.ERROR_MESSAGE); 1720 1721 // kill refresh flag, no update if Add button is enabled 1722 // and loco direction isn't known (lead, rear, replacement) 1723 refresh = false; 1724 return; 1725 } 1726 // delete loco from any existing consists 1727 sendNceBinaryCommand(locoAddr, 1728 NceMessage.LOCO_CMD_DELETE_LOCO_CONSIST, (byte) 0); 1729 synchronized (this) { 1730 try { 1731 wait(DELAY_AFTER_CLEAR); // needed for booster to reset 1732 } catch (InterruptedException ignored) { 1733 } 1734 } 1735 // check to see if loco is already a lead or rear in another consist 1736 verifyLocoAddr(locoAddr); 1737 1738 // now we need to determine if lead, rear, or mid loco 1739 // lead loco? 1740 if (locoTextField == locoTextField1) { 1741 if (dirButton.getText().equals(Bundle.getMessage("KeyFWD"))) { 1742 sendNceBinaryCommand(locoAddr, 1743 NceMessage.LOCO_CMD_FWD_CONSIST_LEAD, consistNumber); 1744 } 1745 if (dirButton.getText().equals(Bundle.getMessage("KeyREV"))) { 1746 sendNceBinaryCommand(locoAddr, 1747 NceMessage.LOCO_CMD_REV_CONSIST_LEAD, consistNumber); 1748 } 1749 // rear loco? 1750 } else if (locoTextField == locoTextField2) { 1751 if (dirButton.getText().equals(Bundle.getMessage("KeyFWD"))) { 1752 sendNceBinaryCommand(locoAddr, 1753 NceMessage.LOCO_CMD_FWD_CONSIST_REAR, consistNumber); 1754 } 1755 if (dirButton.getText().equals(Bundle.getMessage("KeyREV"))) { 1756 sendNceBinaryCommand(locoAddr, 1757 NceMessage.LOCO_CMD_REV_CONSIST_REAR, consistNumber); 1758 } 1759 // must be mid loco 1760 } else { 1761 // wait for verify to complete before updating mid loco 1762 if (locoSearch) { 1763 if (dirButton.getText().equals(Bundle.getMessage("KeyFWD"))) { 1764 verifyType = VERIFY_MID_FWD; 1765 } else { 1766 verifyType = VERIFY_MID_REV; 1767 } 1768 // no verify, just load and go! 1769 } else { 1770 if (dirButton.getText().equals(Bundle.getMessage("KeyFWD"))) { 1771 sendNceBinaryCommand(locoAddr, 1772 NceMessage.LOCO_CMD_FWD_CONSIST_MID, consistNumber); 1773 } 1774 if (dirButton.getText().equals(Bundle.getMessage("KeyREV"))) { 1775 sendNceBinaryCommand(locoAddr, 1776 NceMessage.LOCO_CMD_REV_CONSIST_MID, consistNumber); 1777 } 1778 } 1779 } 1780 } 1781 } 1782 1783 private void fullLoad() { 1784 refresh = true; 1785 loadOneLine(locoRosterBox1, locoTextField1, adrButton1, 1786 dirButton1, cmdButton1); 1787 loadOneLine(locoRosterBox2, locoTextField2, adrButton2, 1788 dirButton2, cmdButton2); 1789 loadOneLine(locoRosterBox3, locoTextField3, adrButton3, 1790 dirButton3, cmdButton3); 1791 loadOneLine(locoRosterBox4, locoTextField4, adrButton4, 1792 dirButton4, cmdButton4); 1793 loadOneLine(locoRosterBox5, locoTextField5, adrButton5, 1794 dirButton5, cmdButton5); 1795 loadOneLine(locoRosterBox6, locoTextField6, adrButton6, 1796 dirButton6, cmdButton6); 1797 changeButtons(false); 1798 } 1799 1800 /** 1801 * updates NCE CS based on the loco line supplied called by load button 1802 * 1803 */ 1804 private void loadOneLine(JComboBox<Object> locoRosterBox, JTextField locoTextField, 1805 JButton adrButton, JButton dirButton, JButton cmdButton) { 1806 if (locoTextField.getText().equals("")) { 1807 return; 1808 } 1809 if (validLocoAdr(locoTextField.getText()) < 0) { 1810 return; 1811 } 1812 byte cN = (byte) validConsist(consistTextField.getText()); 1813 if (cN < 0) { 1814 return; 1815 } 1816 1817 int locoAddr = getLocoAddr(locoTextField, adrButton); 1818 1819 // ADD loco to consist 1820 if (dirButton.getText().equals(Bundle.getMessage("KeyQUESTION"))) { 1821 JmriJOptionPane.showMessageDialog(this, 1822 Bundle.getMessage("DIALOG_SetDirB4Consist"), Bundle.getMessage("DIALOG_NceConsist"), 1823 JmriJOptionPane.ERROR_MESSAGE); 1824 return; 1825 } 1826 1827 // delete loco from any existing consists 1828 sendNceBinaryCommand(locoAddr, 1829 NceMessage.LOCO_CMD_DELETE_LOCO_CONSIST, (byte) 0); 1830 synchronized (this) { 1831 try { 1832 wait(DELAY_AFTER_CLEAR); // needed for booster to reset 1833 } catch (InterruptedException ignored) { 1834 } 1835 } 1836 // now we need to determine if lead, rear, or mid loco 1837 // lead loco? 1838 if (locoTextField == locoTextField1) { 1839 // kill the consist first to clear NCE CS memory 1840 sendNceBinaryCommand(locoAddr, 1841 NceMessage.LOCO_CMD_FWD_CONSIST_LEAD, cN); 1842 sendNceBinaryCommand(locoAddr, NceMessage.LOCO_CMD_KILL_CONSIST, 1843 (byte) 0); 1844 // now load 1845 if (dirButton.getText().equals(Bundle.getMessage("KeyFWD"))) { 1846 sendNceBinaryCommand(locoAddr, 1847 NceMessage.LOCO_CMD_FWD_CONSIST_LEAD, cN); 1848 } 1849 if (dirButton.getText().equals(Bundle.getMessage("KeyREV"))) { 1850 sendNceBinaryCommand(locoAddr, 1851 NceMessage.LOCO_CMD_REV_CONSIST_LEAD, cN); 1852 } 1853 // rear loco? 1854 } else if (locoTextField == locoTextField2) { 1855 if (dirButton.getText().equals(Bundle.getMessage("KeyFWD"))) { 1856 sendNceBinaryCommand(locoAddr, 1857 NceMessage.LOCO_CMD_FWD_CONSIST_REAR, cN); 1858 } 1859 if (dirButton.getText().equals(Bundle.getMessage("KeyREV"))) { 1860 sendNceBinaryCommand(locoAddr, 1861 NceMessage.LOCO_CMD_REV_CONSIST_REAR, cN); 1862 } 1863 // must be mid loco 1864 } else { 1865 if (dirButton.getText().equals(Bundle.getMessage("KeyFWD"))) { 1866 sendNceBinaryCommand(locoAddr, 1867 NceMessage.LOCO_CMD_FWD_CONSIST_MID, cN); 1868 } 1869 if (dirButton.getText().equals(Bundle.getMessage("KeyREV"))) { 1870 sendNceBinaryCommand(locoAddr, 1871 NceMessage.LOCO_CMD_REV_CONSIST_MID, cN); 1872 } 1873 } 1874 } 1875 1876 private int getLocoAddr(JTextField locoTextField, JButton adrButton) { 1877 int locoAddr = Integer.parseInt(locoTextField.getText()); 1878 if (locoAddr >= 128) { 1879 locoAddr += 0xC000; 1880 } else if (adrButton.getText().equals(Bundle.getMessage("KeyLONG"))) { 1881 locoAddr += 0xC000; 1882 } 1883 return locoAddr; 1884 } 1885 1886 private void sendNceMessage(byte[] b, int replyLength) { 1887 NceMessage m = NceMessage.createBinaryMessage(tc, b, replyLength); 1888 waiting++; 1889 replyLen = replyLength; // Expect n byte response 1890 tc.sendNceMessage(m, this); 1891 } 1892 1893 // get loco address type, returns true if long 1894 private boolean getLocoAddressType(NceReply r, int i) { 1895 int rC = r.getElement(i); 1896 rC = rC & 0xC0; // long address if 2 msb are set 1897 if (rC == 0xC0) { 1898 return true; 1899 } else { 1900 return false; 1901 } 1902 } 1903 1904 private String getLocoAddrText(NceReply r, int i) { 1905 int rC_u = r.getElement(i++); 1906 int rC = (rC_u << 8) & 0x3F00; 1907 int rC_l = r.getElement(i); 1908 rC = rC + (rC_l & 0xFF); 1909 String locoAddrText = ""; 1910 if ((rC_u != 0) || (rC_l != 0)) { 1911 locoAddrText = Integer.toString(rC); 1912 } 1913 if (rC == LOC_ADR_REPLACE) { 1914 locoAddrText = Bundle.getMessage("REPLACE_LOCO"); 1915 } 1916 return locoAddrText; 1917 } 1918 1919 private String getLocoDirection(JButton dirButton) { 1920 if (newConsist) { 1921 return Bundle.getMessage("KeyQUESTION"); 1922 } else { 1923 return dirButton.getText(); 1924 } 1925 } 1926 1927 // check command station memory for lead or rear loco match 1928 private void verifyLocoAddr(int locoAddr) { 1929 verifyType = VERIFY_LEAD_REAR; 1930 if (checkBoxVerify.isSelected()) { 1931 locoVerifyList[0] = locoAddr; 1932 locoVerifyList[1] = 0; // end of list 1933 locoSearch = true; 1934 consistNumVerify = 0; 1935 } 1936 } 1937 1938 // check command station memory for lead or rear loco match 1939 private boolean verifyAllLocoAddr() { 1940 verifyType = VERIFY_ALL; 1941 if (checkBoxVerify.isSelected()) { 1942 int i = 0; 1943 if (!locoTextField1.getText().equals("") && validLocoAdr(locoTextField1.getText()) > 0) { 1944 locoVerifyList[i++] = getLocoAddr(locoTextField1, adrButton1); 1945 } 1946 if (!locoTextField2.getText().equals("") && validLocoAdr(locoTextField2.getText()) > 0) { 1947 locoVerifyList[i++] = getLocoAddr(locoTextField2, adrButton2); 1948 } 1949 if (!locoTextField3.getText().equals("") && validLocoAdr(locoTextField3.getText()) > 0) { 1950 locoVerifyList[i++] = getLocoAddr(locoTextField3, adrButton3); 1951 } 1952 if (!locoTextField4.getText().equals("") && validLocoAdr(locoTextField4.getText()) > 0) { 1953 locoVerifyList[i++] = getLocoAddr(locoTextField4, adrButton4); 1954 } 1955 if (!locoTextField5.getText().equals("") && validLocoAdr(locoTextField5.getText()) > 0) { 1956 locoVerifyList[i++] = getLocoAddr(locoTextField5, adrButton5); 1957 } 1958 if (!locoTextField6.getText().equals("") && validLocoAdr(locoTextField6.getText()) > 0) { 1959 locoVerifyList[i++] = getLocoAddr(locoTextField6, adrButton6); 1960 } else { 1961 locoVerifyList[i] = 0; 1962 } 1963 locoSearch = true; 1964 consistNumVerify = 0; 1965 consistStatus.setText(Bundle.getMessage("EditStateVERIFY")); 1966 readConsistMemory(consistNumVerify, LEAD); 1967 return true; 1968 } 1969 return false; 1970 } 1971 1972 private void addLocoRow(JComponent col1, JComponent col2, JComponent col3, 1973 JComponent col4, JComponent col5, JComponent col6, int row) { 1974 addItem(col1, 0, row); 1975 addItem(col2, 1, row); 1976 addItem(col3, 2, row); 1977 addItem(col4, 3, row); 1978 addItem(col5, 4, row); 1979 addItem(col6, 5, row); 1980 } 1981 1982 private void addItem(JComponent c, int x, int y) { 1983 GridBagConstraints gc = new GridBagConstraints(); 1984 gc.gridx = x; 1985 gc.gridy = y; 1986 gc.weightx = 100.0; 1987 gc.weighty = 100.0; 1988 add(c, gc); 1989 } 1990 1991 private void addButtonAction(JButton b) { 1992 b.addActionListener(new java.awt.event.ActionListener() { 1993 @Override 1994 public void actionPerformed(java.awt.event.ActionEvent e) { 1995 buttonActionPerformed(e); 1996 } 1997 }); 1998 } 1999 2000 private void addCheckBoxAction(JCheckBox cb) { 2001 cb.addActionListener(new java.awt.event.ActionListener() { 2002 @Override 2003 public void actionPerformed(java.awt.event.ActionEvent e) { 2004 checkBoxActionPerformed(e); 2005 } 2006 }); 2007 } 2008 2009 private void enableAllLocoRows(boolean flag) { 2010 enableLocoRow(flag, locoTextField1, locoRosterBox1, 2011 adrButton1, dirButton1, cmdButton1); 2012 enableLocoRow(flag, locoTextField2, locoRosterBox2, 2013 adrButton2, dirButton2, cmdButton2); 2014 enableLocoRow(flag, locoTextField3, locoRosterBox3, 2015 adrButton3, dirButton3, cmdButton3); 2016 enableLocoRow(flag, locoTextField4, locoRosterBox4, 2017 adrButton4, dirButton4, cmdButton4); 2018 enableLocoRow(flag, locoTextField5, locoRosterBox5, 2019 adrButton5, dirButton5, cmdButton5); 2020 enableLocoRow(flag, locoTextField6, locoRosterBox6, 2021 adrButton6, dirButton6, cmdButton6); 2022 } 2023 2024 private void enableLocoRow(boolean flag, JTextField locoTextField, 2025 JComboBox<Object> locoRosterBox, JButton adrButton, JButton dirButton, 2026 JButton cmdButton) { 2027 locoTextField.setEnabled(flag); 2028 locoRosterBox.setEnabled(flag); 2029 adrButton.setEnabled(flag); 2030 dirButton.setEnabled(flag); 2031 cmdButton.setEnabled(flag); 2032 } 2033 2034 // initialize loco fields 2035 private void initLocoFields() { 2036 initLocoRow(1, Bundle.getMessage("LeadLabel"), textLoco1, locoTextField1, locoRosterBox1, 2037 adrButton1, dirButton1, cmdButton1); 2038 initLocoRow(2, Bundle.getMessage("RearLabel"), textLoco2, locoTextField2, locoRosterBox2, 2039 adrButton2, dirButton2, cmdButton2); 2040 initLocoRow(3, Bundle.getMessage("MidLabel", "1"), textLoco3, locoTextField3, locoRosterBox3, 2041 adrButton3, dirButton3, cmdButton3); 2042 initLocoRow(4, Bundle.getMessage("MidLabel", "2"), textLoco4, locoTextField4, locoRosterBox4, 2043 adrButton4, dirButton4, cmdButton4); 2044 initLocoRow(5, Bundle.getMessage("MidLabel", "3"), textLoco5, locoTextField5, locoRosterBox5, 2045 adrButton5, dirButton5, cmdButton5); 2046 initLocoRow(6, Bundle.getMessage("MidLabel", "4"), textLoco6, locoTextField6, locoRosterBox6, 2047 adrButton6, dirButton6, cmdButton6); 2048 } 2049 2050 private void initLocoRow(int row, String s, JLabel textLoco, 2051 JTextField locoTextField, JComboBox<Object> locoRosterBox, 2052 JButton adrButton, JButton dirButton, JButton cmdButton) { 2053 2054 textLoco.setText(s); 2055 textLoco.setVisible(true); 2056 2057 adrButton.setText(Bundle.getMessage("KeyLONG")); 2058 adrButton.setVisible(true); 2059 adrButton.setEnabled(false); 2060 adrButton.setToolTipText(Bundle.getMessage("ToolTipAddressType")); 2061 adrButton.addActionListener(new java.awt.event.ActionListener() { 2062 @Override 2063 public void actionPerformed(java.awt.event.ActionEvent e) { 2064 buttonActionAdrPerformed(e); 2065 } 2066 }); 2067 2068 locoRosterBox.setVisible(true); 2069 locoRosterBox.setEnabled(false); 2070 locoRosterBox.setToolTipText(Bundle.getMessage("ToolTipSelectLoco")); 2071 locoRosterBox.addActionListener(new java.awt.event.ActionListener() { 2072 @Override 2073 public void actionPerformed(java.awt.event.ActionEvent e) { 2074 locoSelected(e); 2075 } 2076 }); 2077 2078 dirButton.setText(Bundle.getMessage("KeyQUESTION")); 2079 dirButton.setVisible(true); 2080 dirButton.setEnabled(false); 2081 dirButton.setToolTipText(Bundle.getMessage("ToolTipDirection")); 2082 dirButton.addActionListener(new java.awt.event.ActionListener() { 2083 @Override 2084 public void actionPerformed(java.awt.event.ActionEvent e) { 2085 buttonActionDirPerformed(e); 2086 } 2087 }); 2088 2089 cmdButton.setText(Bundle.getMessage("KeyADD")); 2090 cmdButton.setVisible(true); 2091 cmdButton.setEnabled(false); 2092 cmdButton.setToolTipText(Bundle.getMessage("ToolTipAdd")); 2093 cmdButton.addActionListener(this::buttonActionCmdPerformed); 2094 2095 locoTextField.setText(""); 2096 locoTextField.setEnabled(false); 2097 locoTextField.setToolTipText(Bundle.getMessage("ToolTipEnterLoco")); 2098 locoTextField.setMaximumSize(new Dimension( 2099 locoTextField.getMaximumSize().width, locoTextField 2100 .getPreferredSize().height)); 2101 } 2102 2103 ActionListener consistRosterListener; 2104 2105 private void initConsistRoster(JComboBox<String> conRosterBox) { 2106 conRosterBox.insertItemAt("", 0); 2107 conRosterBox.setSelectedIndex(0); 2108 conRosterBox.setVisible(true); 2109 conRosterBox.setEnabled(false); 2110 conRosterBox.setToolTipText(Bundle.getMessage("ToolTipSelectConsist")); 2111 conRosterBox.addActionListener(consistRosterListener = this::consistRosterSelected); 2112 } 2113 2114 private static final int ERROR_LOCO_IN_USE = 1; 2115 private static final int ERROR_NO_EMPTY_CONSIST = 2; 2116 private static final int ERROR_CONSIST_DOESNT_MATCH = 3; 2117 private static final int WARN_CONSIST_ALREADY_LOADED = 4; 2118 private int locoNumInUse; // report loco alreay in use 2119 private int errorCode = 0; 2120 2121 private void queueError(int errorCode) { 2122 log.debug("queue warning/error message: {}", errorCode); 2123 if (this.errorCode != 0) { 2124 log.debug("multiple errors reported {}", this.errorCode); 2125 return; 2126 } 2127 this.errorCode = errorCode; 2128 // Bad to stop receive thread with JmriJOptionPane error message 2129 // so start up a new thread to report error 2130 Thread errorThread = new Thread(new Runnable() { 2131 @Override 2132 public void run() { 2133 reportError(); 2134 } 2135 }); 2136 errorThread.setName("Report Error"); // NOI18N 2137 errorThread.start(); 2138 } 2139 2140 public void reportError() { 2141 switch (errorCode) { 2142 2143 case ERROR_LOCO_IN_USE: 2144 JmriJOptionPane.showMessageDialog(this, 2145 Bundle.getMessage("DIALOG_LocoInUse", locoNumInUse, consistNumVerify), 2146 Bundle.getMessage("DIALOG_NceConsist"), 2147 JmriJOptionPane.ERROR_MESSAGE); 2148 break; 2149 2150 case ERROR_NO_EMPTY_CONSIST: 2151 JmriJOptionPane.showMessageDialog(this, 2152 Bundle.getMessage("DIALOG_NoEmptyConsist"), 2153 Bundle.getMessage("DIALOG_NceConsist"), 2154 JmriJOptionPane.ERROR_MESSAGE); 2155 break; 2156 2157 case ERROR_CONSIST_DOESNT_MATCH: 2158 if (JmriJOptionPane.showConfirmDialog(null, 2159 Bundle.getMessage("DIALOG_RosterNotMatch") + " " 2160 + getRosterText(nceConsistRosterEntry), 2161 Bundle.getMessage("DIALOG_NceContinue"), 2162 JmriJOptionPane.YES_NO_OPTION) != JmriJOptionPane.YES_OPTION) { 2163 if (JmriJOptionPane.showConfirmDialog(null, 2164 Bundle.getMessage("DIALOG_RosterNotMatch1", 2165 nceConsistRosterEntry.getId(), nceConsistRosterEntry.getConsistNumber()) 2166 + "\n " + Bundle.getMessage("DIALOG_RosterNotMatch2"), 2167 Bundle.getMessage("DIALOG_NceReset"), 2168 JmriJOptionPane.YES_NO_OPTION) == JmriJOptionPane.YES_OPTION) { 2169 nceConsistRosterEntry.setConsistNumber(Bundle.getMessage("CLEARED")); 2170 } 2171 changeButtons(false); 2172 saveLoadButton.setEnabled(canLoad()); 2173 break; 2174 } 2175 changeButtons(true); 2176 loadFullRoster(nceConsistRosterEntry); 2177 saveLoadButton.setEnabled(canLoad()); 2178 break; 2179 case WARN_CONSIST_ALREADY_LOADED: 2180 JmriJOptionPane.showMessageDialog(this, 2181 Bundle.getMessage("DIALOG_ConsistWasLoaded"), 2182 Bundle.getMessage("DIALOG_NceConsist"), JmriJOptionPane.WARNING_MESSAGE); 2183 break; 2184 default: 2185 JmriJOptionPane.showMessageDialog(this, 2186 Bundle.getMessage("DIALOG_ErrorUnknown", errorCode), 2187 Bundle.getMessage("DIALOG_NceConsist"), 2188 JmriJOptionPane.ERROR_MESSAGE); 2189 log.error("Error code out of range: {}", errorCode); 2190 } 2191 errorCode = 0; 2192 } 2193 2194 private String getRosterText(NceConsistRosterEntry nceConsistRosterEntry) { 2195 return "\n" 2196 + "\n" 2197 + Bundle.getMessage("ROSTER_ConsistNum") 2198 + " " + nceConsistRosterEntry.getConsistNumber() 2199 + "\n" 2200 + Bundle.getMessage("ROSTER_LeadLoco") 2201 + " " + nceConsistRosterEntry.getLoco1DccAddress() 2202 + " " + shortHandConvertDTD(nceConsistRosterEntry.getLoco1Direction()) 2203 + "\n" 2204 + Bundle.getMessage("ROSTER_RearLoco") 2205 + " " + nceConsistRosterEntry.getLoco2DccAddress() 2206 + " " + shortHandConvertDTD(nceConsistRosterEntry.getLoco2Direction()) 2207 + "\n" 2208 + Bundle.getMessage("ROSTER_Mid1Loco") 2209 + " " + nceConsistRosterEntry.getLoco3DccAddress() 2210 + " " + shortHandConvertDTD(nceConsistRosterEntry.getLoco3Direction()) 2211 + "\n" 2212 + Bundle.getMessage("ROSTER_Mid2Loco") 2213 + " " + nceConsistRosterEntry.getLoco4DccAddress() 2214 + " " + shortHandConvertDTD(nceConsistRosterEntry.getLoco4Direction()) 2215 + "\n" 2216 + Bundle.getMessage("ROSTER_Mid3Loco") 2217 + " " + nceConsistRosterEntry.getLoco5DccAddress() 2218 + " " + shortHandConvertDTD(nceConsistRosterEntry.getLoco5Direction()) 2219 + "\n" 2220 + Bundle.getMessage("ROSTER_Mid4Loco") 2221 + " " + nceConsistRosterEntry.getLoco6DccAddress() 2222 + " " + shortHandConvertDTD(nceConsistRosterEntry.getLoco6Direction()); 2223 } 2224 2225 /** 2226 * Nested class to create one of these using old-style defaults 2227 */ 2228 static public class Default extends jmri.jmrix.nce.swing.NceNamedPaneAction { 2229 2230 public Default() { 2231 super("Open NCE Consist Editor", 2232 new jmri.util.swing.sdi.JmriJFrameInterface(), 2233 NceConsistEditPanel.class.getName(), 2234 jmri.InstanceManager.getDefault(NceSystemConnectionMemo.class)); 2235 } 2236 } 2237 2238 private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(NceConsistEditPanel.class); 2239 2240}