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