001package jmri.jmrit.blockboss; 002 003import java.beans.PropertyChangeEvent; 004import java.util.*; 005import javax.annotation.Nonnull; 006 007import jmri.*; 008import jmri.jmrit.automat.Siglet; 009 010/** 011 * Drives the "simple signal" logic for one signal. 012 * <p> 013 * Signals "protect" by telling the engineer about the conditions ahead. The 014 * engineer controls the speed of the train based on what the signals show, and 015 * the signals in turn react to whether the track ahead is occupied, what 016 * signals further down the line show, etc. 017 * <p> 018 * There are four situations that this logic can handle: 019 * <ol> 020 * <li>SINGLEBLOCK - A simple block, without a turnout. 021 * <p> 022 * In this case, there is only a single set of sensors and a single next signal 023 * to protect. 024 * <li>TRAILINGMAIN - This signal is protecting a trailing point turnout, which 025 * can only be passed when the turnout is closed. It can also be used for the 026 * upper head of a two head signal on the facing end of the turnout. 027 * <p> 028 * In this case, the signal is forced red if the specified turnout is THROWN. 029 * When the turnout is CLOSED, there is a single set of sensors and next 030 * signal(s) to protect. 031 * <li>TRAILINGDIVERGING - This signal is protecting a trailing point turnout, 032 * which can only be passed when the turnout is thrown. It can also be used for 033 * the lower head of a two head signal on the facing end of the turnout. 034 * <p> 035 * In this case, the signal is forced red if the specified turnout is CLOSED. 036 * When the turnout is THROWN, there is a single set of sensors and next 037 * signal(s) to protect. 038 * <li>FACING - This single head signal protects a facing point turnout, which 039 * may therefore have two next signals and two sets of next sensors for the 040 * closed and thrown states of the turnout. 041 * <p> 042 * If the turnout is THROWN, one set of sensors and next signal(s) is protected. 043 * If the turnout is CLOSED, another set of sensors and next signal(s) is 044 * protected. 045 * </ol> 046 * <p> 047 * Note that these four possibilities logically require that certain information 048 * be configured consistently; e.g. not specifying a turnout in TRAILINGMAIN 049 * doesn't make any sense. That's not enforced explicitly, but violating it can 050 * result in confusing behavior. 051 * 052 * <p> 053 * The protected sensors should cover the track to the next signal. If any of 054 * the protected sensors show ACTIVE, the signal will be dropped to red. 055 * Normally, the protected sensors cover the occupancy of the track to the next 056 * signal. In this case, the signal will show red to prevent trains from 057 * entering an occupied stretch of track (often called a "block"). But the 058 * actual source of the sensors can be anything useful, for example a 059 * microswitch on a local turnout, etc. 060 * <p> 061 * There are several variants to how a next signal is protected. In the simplest 062 * form, the controlled signal provides a warning to the engineer of what the 063 * signal being protected will show when it becomes visible: 064 * <ul> 065 * <li>If the next signal is red, the engineer needs to be told to slow down; 066 * this signal will be set to yellow. 067 * <li>If the next signal is green, the engineer can proceed at track speed; 068 * this signal will be set to green. 069 * </ul> 070 * If the next signal is yellow, there are two possible variants that can be 071 * configured: 072 * <ul> 073 * <li>For the common "three-aspect" signaling system, an engineer doesn't need 074 * any warning before a yellow signal. In this case, this signal is set to green 075 * when the protected signal is yellow. 076 * <li>For lines where track speed is very fast or braking distances are very 077 * long, it can be useful to give engineers warning that the next signal is 078 * yellow (and the one after that is red) so that slowing the train can start 079 * early. Usually flashing yellow preceeds the yellow signal, and the system is 080 * called "four-aspect" signaling. 081 * </ul> 082 * 083 * <p> 084 * In some cases, you want a signal to show <i>exactly</I> what the next signal 085 * shows, instead of one speed faster. E.g. if the (protected) next signal is 086 * red, this one should be red, instead of yellow. In this case, this signal is 087 * called a "distant signal", as it provides a "distant" view of the protected 088 * signal heads's appearance. Note that when in this mode, this signal still protects 089 * the interveneing track, etc. 090 * <p> 091 * The "hold" unbound parameter can be used to set this logic to show red, 092 * regardless of input. That's intended for use with CTC logic, etc. 093 * <p> 094 * "Approach lit" signaling sets the signal head to dark (off) unless the 095 * specified sensor(s) are ACTIVE. Normally, those sensors are in front of 096 * (before) the signal head. The signal heads then only light when a train is 097 * approaching. This is used to preserve bulbs and batteries (and sometimes to 098 * reduce engineer workload) on prototype railroads, but is uncommon on model 099 * railroads; once the layout owner has gone to the trouble and expense of 100 * installing signals, he usually wants them lit up. 101 * <p> 102 * Two signal heads can be protected. For example, if the next signal has two 103 * heads to control travel onto a main track or siding, then both heads should 104 * be provided here. The <i>faster</i> signal aspect will control the appearance 105 * of this head. For example, if the next signal is showing a green head and a 106 * red head, this signal will be green, because the train will be able to 107 * proceed at track speed when it reaches that next signal (along the track with 108 * the green signal). 109 * 110 * @author Bob Jacobsen Copyright (C) 2003, 2005 111 * @author Dick Bronson 2006 Revisions to add facing point sensors, approach lighting 112 * and check box to limit speed. 113 */ 114public class BlockBossLogic extends Siglet implements java.beans.VetoableChangeListener { 115 116 public static final int SINGLEBLOCK = 1; 117 public static final int TRAILINGMAIN = 2; 118 public static final int TRAILINGDIVERGING = 3; 119 public static final int FACING = 4; 120 private static final String BEAN_X_NOT_FOUND = "BeanXNotFound"; 121 private static final String BEAN_NAME_SIGNAL_HEAD = "BeanNameSignalHead"; 122 private static final String BEAN_NAME_SENSOR = "BeanNameSensor"; 123 124 private int mode = 0; 125 126 /** 127 * Create an object to drive a specific signal head. 128 * 129 * @param name System or user name of the driven signal head, which must exist 130 */ 131 public BlockBossLogic(@Nonnull String name) { 132 super(name + Bundle.getMessage("_BlockBossLogic")); 133 java.util.Objects.requireNonNull(name, "BlockBossLogic name cannot be null"); 134 this.name = name; 135 log.trace("Create BBL {}", name); 136 137 InstanceManager.getDefault(SignalHeadManager.class).addVetoableChangeListener(BlockBossLogic.this); 138 InstanceManager.turnoutManagerInstance().addVetoableChangeListener(BlockBossLogic.this); 139 InstanceManager.sensorManagerInstance().addVetoableChangeListener(BlockBossLogic.this); 140 SignalHead driveHead = InstanceManager.getDefault(SignalHeadManager.class).getSignalHead(name); 141 if (driveHead == null) { 142 logWarn(Bundle.getMessage(BEAN_X_NOT_FOUND, Bundle.getMessage(BEAN_NAME_SIGNAL_HEAD), name)); 143 throw new IllegalArgumentException("SignalHead \"" + name + "\" does not exist"); 144 } 145 driveSignal = nbhm.getNamedBeanHandle(name, driveHead); 146 java.util.Objects.requireNonNull(driveSignal, "driveSignal should not have been null"); 147 } 148 149 @edu.umd.cs.findbugs.annotations.SuppressFBWarnings( value="SLF4J_FORMAT_SHOULD_BE_CONST", 150 justification="I18N Warning strings.") 151 private void logWarn(String stringToLogAsWarning) { 152 log.warn(stringToLogAsWarning); 153 } 154 155 /** 156 * The "driven signal" is controlled by this element. 157 * 158 * @return system name of the driven signal head 159 */ 160 public @Nonnull String getDrivenSignal() { 161 java.util.Objects.requireNonNull(driveSignal, "driveSignal should not have been null"); 162 String retVal = driveSignal.getName(); 163 java.util.Objects.requireNonNull(retVal, "driveSignal system name should not have been null"); 164 return retVal; 165 } 166 167 public @Nonnull NamedBeanHandle<SignalHead> getDrivenSignalNamedBean() { 168 java.util.Objects.requireNonNull(driveSignal, "driveSignal should have been null"); 169 return driveSignal; 170 } 171 172 private final NamedBeanHandleManager nbhm = InstanceManager.getDefault(NamedBeanHandleManager.class); 173 174 public void setSensor1(String name) { 175 if (name == null || name.isEmpty()) { 176 watchSensor1 = null; 177 return; 178 } 179 try { 180 watchSensor1 = nbhm.getNamedBeanHandle(name, InstanceManager.sensorManagerInstance().provideSensor(name)); 181 } catch (IllegalArgumentException ex) { 182 logWarn(Bundle.getMessage(BEAN_X_NOT_FOUND, Bundle.getMessage(BEAN_NAME_SENSOR) + "1", name)); 183 } 184 } 185 186 public void setSensor2(String name) { 187 if (name == null || name.isEmpty()) { 188 watchSensor2 = null; 189 return; 190 } 191 try { 192 watchSensor2 = nbhm.getNamedBeanHandle(name, InstanceManager.sensorManagerInstance().provideSensor(name)); 193 } catch (IllegalArgumentException ex) { 194 logWarn(Bundle.getMessage(BEAN_X_NOT_FOUND, Bundle.getMessage(BEAN_NAME_SENSOR) + "2", name)); 195 } 196 } 197 198 public void setSensor3(String name) { 199 if (name == null || name.isEmpty()) { 200 watchSensor3 = null; 201 return; 202 } 203 try { 204 watchSensor3 = nbhm.getNamedBeanHandle(name, InstanceManager.sensorManagerInstance().provideSensor(name)); 205 } catch (IllegalArgumentException ex) { 206 logWarn(Bundle.getMessage(BEAN_X_NOT_FOUND, Bundle.getMessage(BEAN_NAME_SENSOR) + "3", name)); 207 } 208 } 209 210 public void setSensor4(String name) { 211 if (name == null || name.isEmpty()) { 212 watchSensor4 = null; 213 return; 214 } 215 try { 216 watchSensor4 = nbhm.getNamedBeanHandle(name, InstanceManager.sensorManagerInstance().provideSensor(name)); 217 } catch (IllegalArgumentException ex) { 218 logWarn(Bundle.getMessage(BEAN_X_NOT_FOUND, Bundle.getMessage(BEAN_NAME_SENSOR) + "4", name)); 219 } 220 } 221 222 public void setSensor5(String name) { 223 if (name == null || name.isEmpty()) { 224 watchSensor5 = null; 225 return; 226 } 227 try { 228 watchSensor5 = nbhm.getNamedBeanHandle(name, InstanceManager.sensorManagerInstance().provideSensor(name)); 229 } catch (IllegalArgumentException ex) { 230 logWarn(Bundle.getMessage(BEAN_X_NOT_FOUND, Bundle.getMessage(BEAN_NAME_SENSOR) + "5", name)); 231 } 232 } 233 234 /** 235 * Get the system name of the sensors 1-5 being monitored. 236 * 237 * @return system name; null if no sensor configured 238 */ 239 public String getSensor1() { 240 if (watchSensor1 == null) { 241 return null; 242 } 243 return watchSensor1.getName(); 244 } 245 246 public String getSensor2() { 247 if (watchSensor2 == null) { 248 return null; 249 } 250 return watchSensor2.getName(); 251 } 252 253 public String getSensor3() { 254 if (watchSensor3 == null) { 255 return null; 256 } 257 return watchSensor3.getName(); 258 } 259 260 public String getSensor4() { 261 if (watchSensor4 == null) { 262 return null; 263 } 264 return watchSensor4.getName(); 265 } 266 267 public String getSensor5() { 268 if (watchSensor5 == null) { 269 return null; 270 } 271 return watchSensor5.getName(); 272 } 273 274 public void setTurnout(String name) { 275 if (name == null || name.isEmpty()) { 276 watchTurnout = null; 277 return; 278 } 279 try { 280 watchTurnout = nbhm.getNamedBeanHandle(name, InstanceManager.turnoutManagerInstance().provideTurnout(name)); 281 } catch (IllegalArgumentException ex) { 282 logWarn(Bundle.getMessage(BEAN_X_NOT_FOUND, Bundle.getMessage("BeanNameTurnout"), name)); 283 } 284 } 285 286 /** 287 * Get the system name of the turnout being monitored. 288 * 289 * @return system name; null if no turnout configured 290 */ 291 public String getTurnout() { 292 if (watchTurnout == null) { 293 return null; 294 } 295 return watchTurnout.getName(); 296 } 297 298 public void setMode(int mode) { 299 this.mode = mode; 300 } 301 302 public int getMode() { 303 return mode; 304 } 305 306 private String comment; 307 308 public void setComment(String comment) { 309 this.comment = comment; 310 } 311 312 public String getComment() { 313 return this.comment; 314 } 315 316 public void setWatchedSignal1(String name, boolean useFlash) { 317 if (name == null || name.isEmpty()) { 318 watchedSignal1 = null; 319 return; 320 } 321 SignalHead head = InstanceManager.getDefault(SignalHeadManager.class).getSignalHead(name); 322 if (head != null) { 323 watchedSignal1 = nbhm.getNamedBeanHandle(name, head); 324 } else { 325 logWarn(Bundle.getMessage(BEAN_X_NOT_FOUND, Bundle.getMessage(BEAN_NAME_SIGNAL_HEAD), name)); 326 watchedSignal1 = null; 327 } 328 protectWithFlashing = useFlash; 329 } 330 331 /** 332 * Get the system name of the signal head being monitored for first route. 333 * 334 * @return system name; null if no primary signal head is configured 335 */ 336 public String getWatchedSignal1() { 337 if (watchedSignal1 == null) { 338 return null; 339 } 340 return watchedSignal1.getName(); 341 } 342 343 public void setWatchedSignal1Alt(String name) { 344 if (name == null || name.isEmpty()) { 345 watchedSignal1Alt = null; 346 return; 347 } 348 SignalHead head = InstanceManager.getDefault(SignalHeadManager.class).getSignalHead(name); 349 if (head != null) { 350 watchedSignal1Alt = nbhm.getNamedBeanHandle(name, head); 351 } else { 352 logWarn(Bundle.getMessage(BEAN_X_NOT_FOUND, Bundle.getMessage(BEAN_NAME_SIGNAL_HEAD), name)); 353 watchedSignal1Alt = null; 354 } 355 } 356 357 /** 358 * Get the system name of the alternate signal head being monitored for first 359 * route. 360 * 361 * @return system name; null if no signal head is configured 362 */ 363 public String getWatchedSignal1Alt() { 364 if (watchedSignal1Alt == null) { 365 return null; 366 } 367 return watchedSignal1Alt.getName(); 368 } 369 370 public void setWatchedSignal2(String name) { 371 if (name == null || name.isEmpty()) { 372 watchedSignal2 = null; 373 return; 374 } 375 SignalHead head = InstanceManager.getDefault(SignalHeadManager.class).getSignalHead(name); 376 if (head != null) { 377 watchedSignal2 = nbhm.getNamedBeanHandle(name, head); 378 } else { 379 logWarn(Bundle.getMessage(BEAN_X_NOT_FOUND, Bundle.getMessage(BEAN_NAME_SIGNAL_HEAD), name)); 380 watchedSignal2 = null; 381 } 382 } 383 384 /** 385 * Get the system name of the signal head being monitored for the 2nd route. 386 * 387 * @return system name; null if no signal head is configured 388 */ 389 public String getWatchedSignal2() { 390 if (watchedSignal2 == null) { 391 return null; 392 } 393 return watchedSignal2.getName(); 394 } 395 396 public void setWatchedSignal2Alt(String name) { 397 if (name == null || name.isEmpty()) { 398 watchedSignal2Alt = null; 399 return; 400 } 401 SignalHead head = InstanceManager.getDefault(SignalHeadManager.class).getSignalHead(name); 402 if (head != null) { 403 watchedSignal2Alt = nbhm.getNamedBeanHandle(name, head); 404 } else { 405 logWarn(Bundle.getMessage(BEAN_X_NOT_FOUND, Bundle.getMessage(BEAN_NAME_SIGNAL_HEAD), name)); 406 watchedSignal2Alt = null; 407 } 408 } 409 410 /** 411 * Get the system name of the secondary signal head being monitored for the 412 * 2nd route. 413 * 414 * @return system name; null if no secondary signal head is configured 415 */ 416 public String getWatchedSignal2Alt() { 417 if (watchedSignal2Alt == null) { 418 return null; 419 } 420 return watchedSignal2Alt.getName(); 421 } 422 423 public void setWatchedSensor1(String name) { 424 if (name == null || name.isEmpty()) { 425 watchedSensor1 = null; 426 return; 427 } 428 try { 429 watchedSensor1 = nbhm.getNamedBeanHandle(name, InstanceManager.sensorManagerInstance().provideSensor(name)); 430 } catch (IllegalArgumentException ex) { 431 logWarn(Bundle.getMessage(BEAN_X_NOT_FOUND, Bundle.getMessage(BEAN_NAME_SENSOR) + "1", name)); 432 watchedSensor1 = null; 433 } 434 } 435 436 /** 437 * Get the original name of the sensor1 being monitored. 438 * 439 * @return original name; null if no sensor is configured 440 */ 441 public String getWatchedSensor1() { 442 if (watchedSensor1 == null) { 443 return null; 444 } 445 return watchedSensor1.getName(); 446 } 447 448 public void setWatchedSensor1Alt(String name) { 449 if (name == null || name.isEmpty()) { 450 watchedSensor1Alt = null; 451 return; 452 } 453 try { 454 watchedSensor1Alt = nbhm.getNamedBeanHandle(name, InstanceManager.sensorManagerInstance().provideSensor(name)); 455 } catch (IllegalArgumentException ex) { 456 logWarn(Bundle.getMessage(BEAN_X_NOT_FOUND, Bundle.getMessage(BEAN_NAME_SENSOR) + "1Alt", name)); 457 watchedSensor1Alt = null; 458 } 459 } 460 461 /** 462 * Get the system name of the sensor1Alt being monitored. 463 * 464 * @return system name; null if no sensor is configured 465 */ 466 public String getWatchedSensor1Alt() { 467 if (watchedSensor1Alt == null) { 468 return null; 469 } 470 return watchedSensor1Alt.getName(); 471 } 472 473 public void setWatchedSensor2(String name) { 474 if (name == null || name.isEmpty()) { 475 watchedSensor2 = null; 476 return; 477 } 478 try { 479 watchedSensor2 = nbhm.getNamedBeanHandle(name, InstanceManager.sensorManagerInstance().provideSensor(name)); 480 } catch (IllegalArgumentException ex) { 481 logWarn(Bundle.getMessage(BEAN_X_NOT_FOUND, Bundle.getMessage(BEAN_NAME_SENSOR) + "2", name)); 482 watchedSensor2 = null; 483 } 484 } 485 486 /** 487 * Get the system name of the sensor2 being monitored. 488 * 489 * @return system name; null if no sensor is configured 490 */ 491 public String getWatchedSensor2() { 492 if (watchedSensor2 == null) { 493 return null; 494 } 495 return watchedSensor2.getName(); 496 } 497 498 public void setWatchedSensor2Alt(String name) { 499 if (name == null || name.isEmpty()) { 500 watchedSensor2Alt = null; 501 return; 502 } 503 try { 504 watchedSensor2Alt = nbhm.getNamedBeanHandle(name, InstanceManager.sensorManagerInstance().provideSensor(name)); 505 } catch (IllegalArgumentException ex) { 506 logWarn(Bundle.getMessage(BEAN_X_NOT_FOUND, Bundle.getMessage(BEAN_NAME_SENSOR) + "2Alt", name)); 507 watchedSensor2Alt = null; 508 } 509 } 510 511 /** 512 * Get the system name of the sensor2Alt being monitored. 513 * 514 * @return system name; null if no sensor is configured 515 */ 516 public String getWatchedSensor2Alt() { 517 if (watchedSensor2Alt == null) { 518 return null; 519 } 520 return watchedSensor2Alt.getName(); 521 } 522 523 public void setLimitSpeed1(boolean d) { 524 limitSpeed1 = d; 525 } 526 527 public boolean getLimitSpeed1() { 528 return limitSpeed1; 529 } 530 531 public void setRestrictingSpeed1(boolean d) { 532 restrictingSpeed1 = d; 533 } 534 535 public boolean getRestrictingSpeed1() { 536 return restrictingSpeed1; 537 } 538 539 public void setLimitSpeed2(boolean d) { 540 limitSpeed2 = d; 541 } 542 543 public boolean getLimitSpeed2() { 544 return limitSpeed2; 545 } 546 547 public void setRestrictingSpeed2(boolean d) { 548 restrictingSpeed2 = d; 549 } 550 551 public boolean getRestrictingSpeed2() { 552 return restrictingSpeed2; 553 } 554 555 public boolean getUseFlash() { 556 return protectWithFlashing; 557 } 558 559 public void setDistantSignal(boolean d) { 560 distantSignal = d; 561 } 562 563 public boolean getDistantSignal() { 564 return distantSignal; 565 } 566 567 private boolean mHold = false; 568 569 /** 570 * Provide the current value of the "hold" parameter. 571 * <p> 572 * If true, the output is forced to a RED "stop" appearance. 573 * This allows CTC and other higher-level functions to control 574 * permission to enter this section of track. 575 * 576 * @return true if this Logic currently is Held 577 */ 578 private boolean getHold() { 579 return mHold; 580 } 581 582 /** 583 * Set the current value of the "hold" parameter. 584 * If true, the output is forced to a RED "stop" appearance. 585 * This allows CTC and other higher-level functions to 586 * control permission to enter this section of track. 587 * 588 * @param m true to set Logic to Held 589 */ 590 public void setHold(boolean m) { 591 mHold = m; 592 setOutput(); // to invoke the new state 593 } 594 595 private final String name; 596 597 @Nonnull NamedBeanHandle<SignalHead> driveSignal; 598 599 private NamedBeanHandle<Sensor> watchSensor1 = null; 600 private NamedBeanHandle<Sensor> watchSensor2 = null; 601 private NamedBeanHandle<Sensor> watchSensor3 = null; 602 private NamedBeanHandle<Sensor> watchSensor4 = null; 603 private NamedBeanHandle<Sensor> watchSensor5 = null; 604 private NamedBeanHandle<Turnout> watchTurnout = null; 605 private NamedBeanHandle<SignalHead> watchedSignal1 = null; 606 private NamedBeanHandle<SignalHead> watchedSignal1Alt = null; 607 private NamedBeanHandle<SignalHead> watchedSignal2 = null; 608 private NamedBeanHandle<SignalHead> watchedSignal2Alt = null; 609 private NamedBeanHandle<Sensor> watchedSensor1 = null; 610 private NamedBeanHandle<Sensor> watchedSensor1Alt = null; 611 private NamedBeanHandle<Sensor> watchedSensor2 = null; 612 private NamedBeanHandle<Sensor> watchedSensor2Alt = null; 613 private NamedBeanHandle<Sensor> approachSensor1 = null; 614 615 private boolean limitSpeed1 = false; 616 private boolean restrictingSpeed1 = false; 617 private boolean limitSpeed2 = false; 618 private boolean restrictingSpeed2 = false; 619 private boolean protectWithFlashing = false; 620 private boolean distantSignal = false; 621 622 public void setApproachSensor1(String name) { 623 if (name == null || name.isEmpty()) { 624 approachSensor1 = null; 625 return; 626 } 627 approachSensor1 = nbhm.getNamedBeanHandle(name, InstanceManager.sensorManagerInstance().provideSensor(name)); 628 if (approachSensor1.getBean() == null) { 629 logWarn(Bundle.getMessage(BEAN_X_NOT_FOUND, Bundle.getMessage("Approach_Sensor1_"), name)); 630 } 631 } 632 633 /** 634 * Get the system name of the sensor being monitored. 635 * 636 * @return system name; null if no sensor configured 637 */ 638 public String getApproachSensor1() { 639 if (approachSensor1 == null) { 640 return null; 641 } 642 return approachSensor1.getName(); 643 } 644 645 /** 646 * Define the siglet's input and output. 647 */ 648 @Override 649 public void defineIO() { 650 List<NamedBean> namedBeanList = new ArrayList<>(); 651 652 addBeanToListIfItExists(namedBeanList,watchTurnout); 653 addBeanToListIfItExists(namedBeanList,watchSensor1); 654 addBeanToListIfItExists(namedBeanList,watchSensor2); 655 addBeanToListIfItExists(namedBeanList,watchSensor3); 656 addBeanToListIfItExists(namedBeanList,watchSensor4); 657 addBeanToListIfItExists(namedBeanList,watchSensor5); 658 addBeanToListIfItExists(namedBeanList,watchedSignal1); 659 addBeanToListIfItExists(namedBeanList,watchedSignal1Alt); 660 addBeanToListIfItExists(namedBeanList,watchedSignal2); 661 addBeanToListIfItExists(namedBeanList,watchedSignal2Alt); 662 addBeanToListIfItExists(namedBeanList,watchedSensor1); 663 addBeanToListIfItExists(namedBeanList,watchedSensor1Alt); 664 addBeanToListIfItExists(namedBeanList,watchedSensor2); 665 addBeanToListIfItExists(namedBeanList,watchedSensor2Alt); 666 addBeanToListIfItExists(namedBeanList,approachSensor1); 667 668 // copy temp to definitive inputs 669 inputs = namedBeanList.toArray(new NamedBean[1]); 670 671 outputs = new NamedBean[]{driveSignal.getBean()}; 672 673 // also need to act if the _signal's_ "held" 674 // parameter changes, but we don't want to 675 // act if the signals appearance changes (to 676 // avoid a loop, or avoid somebody changing appearance 677 // manually and having it instantly recomputed & changed back 678 driveSignal.getBean().addPropertyChangeListener(e -> { 679 if (e.getPropertyName().equals(Bundle.getMessage("Held"))) { 680 setOutput(); 681 } 682 }, driveSignal.getName(), "BlockBossLogic:" + name); 683 } 684 685 private void addBeanToListIfItExists(List<NamedBean> namedBeanList, NamedBeanHandle<?> namedBeanHandle) { 686 if (namedBeanHandle != null) { 687 namedBeanList.add(namedBeanHandle.getBean()); 688 } 689 } 690 691 /** 692 * Recompute new output state and apply it. 693 */ 694 @Override 695 public void setOutput() { 696 697 log.trace("setOutput for {}", name); 698 699 // make sure init is complete 700 if ((outputs == null) || (outputs[0] == null)) { 701 return; 702 } 703 704 // if "hold" is true, must show red 705 if (getHold()) { 706 ((SignalHead) outputs[0]).setAppearance(SignalHead.RED); 707 log.debug("setOutput red due to held for {}", name); 708 return; 709 } 710 711 // otherwise, process algorithm 712 switch (mode) { 713 case SINGLEBLOCK: 714 doSingleBlock(); 715 break; 716 case TRAILINGMAIN: 717 doTrailingMain(); 718 break; 719 case TRAILINGDIVERGING: 720 doTrailingDiverging(); 721 break; 722 case FACING: 723 doFacing(); 724 break; 725 default: 726 log.error("{}{}_Signal_{}", Bundle.getMessage("UnexpectedMode"), mode, getDrivenSignal()); 727 } 728 } 729 730 private int fastestColor1() { 731 int result = SignalHead.RED; 732 // special case: GREEN if no next signal 733 if (watchedSignal1 == null && watchedSignal1Alt == null) { 734 result = SignalHead.GREEN; 735 } 736 737 int val = result; 738 if (watchedSignal1 != null) { 739 val = watchedSignal1.getBean().getAppearance(); 740 } 741 if (watchedSignal1 != null && watchedSignal1.getBean().getHeld()) { 742 val = SignalHead.RED; // if Held, act as if Red 743 } 744 int valAlt = result; 745 if (watchedSignal1Alt != null) { 746 valAlt = watchedSignal1Alt.getBean().getAppearance(); 747 } 748 if (watchedSignal1Alt != null && watchedSignal1Alt.getBean().getHeld()) { 749 valAlt = SignalHead.RED; // if Held, act as if Red 750 } 751 return fasterOf(val, valAlt); 752 } 753 754 private int fastestColor2() { 755 int result = SignalHead.RED; 756 // special case: GREEN if no next signal 757 if (watchedSignal2 == null && watchedSignal2Alt == null) { 758 result = SignalHead.GREEN; 759 } 760 761 int val = result; 762 if (watchedSignal2 != null) { 763 val = watchedSignal2.getBean().getAppearance(); 764 } 765 if (watchedSignal2 != null && watchedSignal2.getBean().getHeld()) { 766 val = SignalHead.RED; 767 } 768 769 int valAlt = result; 770 if (watchedSignal2Alt != null) { 771 valAlt = watchedSignal2Alt.getBean().getAppearance(); 772 } 773 if (watchedSignal2Alt != null && watchedSignal2Alt.getBean().getHeld()) { 774 valAlt = SignalHead.RED; 775 } 776 777 return fasterOf(val, valAlt); 778 } 779 780 /** 781 * Given two {@link SignalHead} color constants, return the one 782 * corresponding to the slower speed. 783 * 784 * @param a color constant 1 to compare with 785 * @param b color constant 2 786 * @return the lowest of the two values entered 787 */ 788 private static int slowerOf(int a, int b) { 789 // DARK is smallest, FLASHING GREEN is largest 790 return Math.min(a, b); 791 } 792 793 /** 794 * Given two {@link SignalHead} color constants, return the one 795 * corresponding to the faster speed. 796 * 797 * @param a color constant 1 to compare with 798 * @param b color constant 2 799 * @return the highest of the two values entered 800 */ 801 private static int fasterOf(int a, int b) { 802 // DARK is smallest, FLASHING GREEN is largest 803 return Math.max(a, b); 804 } 805 806 private void doSingleBlock() { 807 int appearance = SignalHead.GREEN; 808 int oldAppearance = ((SignalHead) outputs[0]).getAppearance(); 809 // check for yellow, flashing yellow overriding green 810 if (protectWithFlashing && fastestColor1() == SignalHead.YELLOW) { 811 appearance = SignalHead.FLASHYELLOW; 812 } 813 if (fastestColor1() == SignalHead.RED || fastestColor1() == SignalHead.FLASHRED) { 814 appearance = SignalHead.YELLOW; 815 } 816 817 // if distant signal, show exactly what the home signal does 818 if (distantSignal) { 819 appearance = fastestColor1(); 820 } 821 822 // if limited speed and green, reduce to yellow 823 if (limitSpeed1) { 824 appearance = slowerOf(appearance, SignalHead.YELLOW); 825 } 826 827 // if restricting, limit to flashing red 828 if (restrictingSpeed1) { 829 appearance = slowerOf(appearance, SignalHead.FLASHRED); 830 } 831 832 // check for red overriding yellow or green 833 if (watchSensor1 != null && watchSensor1.getBean().getKnownState() != Sensor.INACTIVE) { 834 appearance = SignalHead.RED; 835 } 836 if (watchSensor2 != null && watchSensor2.getBean().getKnownState() != Sensor.INACTIVE) { 837 appearance = SignalHead.RED; 838 } 839 if (watchSensor3 != null && watchSensor3.getBean().getKnownState() != Sensor.INACTIVE) { 840 appearance = SignalHead.RED; 841 } 842 if (watchSensor4 != null && watchSensor4.getBean().getKnownState() != Sensor.INACTIVE) { 843 appearance = SignalHead.RED; 844 } 845 if (watchSensor5 != null && watchSensor5.getBean().getKnownState() != Sensor.INACTIVE) { 846 appearance = SignalHead.RED; 847 } 848 849 // check if signal if held, forcing a red appearance by this calculation 850 if (((SignalHead) outputs[0]).getHeld()) { 851 appearance = SignalHead.RED; 852 } 853 854 // handle approach lighting 855 doApproach(); 856 857 // show result if changed 858 if (appearance != oldAppearance) { 859 ((SignalHead) outputs[0]).setAppearance(appearance); 860 log.debug("Change appearance of {} to: {}", name, appearance); 861 } 862 } 863 864 private void doTrailingMain() { 865 int appearance = SignalHead.GREEN; 866 int oldAppearance = ((SignalHead) outputs[0]).getAppearance(); 867 // check for yellow, flashing yellow overriding green 868 if (protectWithFlashing && fastestColor1() == SignalHead.YELLOW) { 869 appearance = SignalHead.FLASHYELLOW; 870 } 871 if (fastestColor1() == SignalHead.RED || fastestColor1() == SignalHead.FLASHRED) { 872 appearance = SignalHead.YELLOW; 873 } 874 875 // if distant signal, show exactly what the home signal does 876 if (distantSignal) { 877 appearance = fastestColor1(); 878 } 879 880 // if limited speed and green, reduce to yellow 881 if (limitSpeed1) { 882 appearance = slowerOf(appearance, SignalHead.YELLOW); 883 } 884 // if restricting, limit to flashing red 885 if (restrictingSpeed1) { 886 appearance = slowerOf(appearance, SignalHead.FLASHRED); 887 } 888 889 // check for red overriding yellow or green 890 if (watchSensor1 != null && watchSensor1.getBean().getKnownState() != Sensor.INACTIVE) { 891 appearance = SignalHead.RED; 892 } 893 if (watchSensor2 != null && watchSensor2.getBean().getKnownState() != Sensor.INACTIVE) { 894 appearance = SignalHead.RED; 895 } 896 if (watchSensor3 != null && watchSensor3.getBean().getKnownState() != Sensor.INACTIVE) { 897 appearance = SignalHead.RED; 898 } 899 if (watchSensor4 != null && watchSensor4.getBean().getKnownState() != Sensor.INACTIVE) { 900 appearance = SignalHead.RED; 901 } 902 if (watchSensor5 != null && watchSensor5.getBean().getKnownState() != Sensor.INACTIVE) { 903 appearance = SignalHead.RED; 904 } 905 906 if (watchTurnout != null && watchTurnout.getBean().getKnownState() != Turnout.CLOSED) { 907 appearance = SignalHead.RED; 908 } 909 if (watchTurnout != null && watchTurnout.getBean().getCommandedState() != Turnout.CLOSED) { 910 appearance = SignalHead.RED; 911 } 912 913 // check if signal if held, forcing a red appearance by this calculation 914 if (((SignalHead) outputs[0]).getHeld()) { 915 appearance = SignalHead.RED; 916 } 917 918 // handle approach lighting 919 doApproach(); 920 921 // show result if changed 922 if (appearance != oldAppearance) { 923 ((SignalHead) outputs[0]).setAppearance(appearance); 924 log.debug("Change appearance of {} to:{}", name, appearance); 925 } 926 } 927 928 private void doTrailingDiverging() { 929 int appearance = SignalHead.GREEN; 930 int oldAppearance = ((SignalHead) outputs[0]).getAppearance(); 931 // check for yellow, flashing yellow overriding green 932 if (protectWithFlashing && fastestColor1() == SignalHead.YELLOW) { 933 appearance = SignalHead.FLASHYELLOW; 934 } 935 if (fastestColor1() == SignalHead.RED || fastestColor1() == SignalHead.FLASHRED) { 936 appearance = SignalHead.YELLOW; 937 } 938 939 // if distant signal, show exactly what the home signal does 940 if (distantSignal) { 941 appearance = fastestColor1(); 942 } 943 944 // if limited speed and green, reduce to yellow 945 if (limitSpeed2) { 946 appearance = slowerOf(appearance, SignalHead.YELLOW); 947 } 948 // if restricting, limit to flashing red 949 if (restrictingSpeed2) { 950 appearance = slowerOf(appearance, SignalHead.FLASHRED); 951 } 952 953 // check for red overriding yellow or green 954 if (watchSensor1 != null && watchSensor1.getBean().getKnownState() != Sensor.INACTIVE) { 955 appearance = SignalHead.RED; 956 } 957 if (watchSensor2 != null && watchSensor2.getBean().getKnownState() != Sensor.INACTIVE) { 958 appearance = SignalHead.RED; 959 } 960 if (watchSensor3 != null && watchSensor3.getBean().getKnownState() != Sensor.INACTIVE) { 961 appearance = SignalHead.RED; 962 } 963 if (watchSensor4 != null && watchSensor4.getBean().getKnownState() != Sensor.INACTIVE) { 964 appearance = SignalHead.RED; 965 } 966 if (watchSensor5 != null && watchSensor5.getBean().getKnownState() != Sensor.INACTIVE) { 967 appearance = SignalHead.RED; 968 } 969 970 if (watchTurnout != null && watchTurnout.getBean().getKnownState() != Turnout.THROWN) { 971 appearance = SignalHead.RED; 972 } 973 if (watchTurnout != null && watchTurnout.getBean().getCommandedState() != Turnout.THROWN) { 974 appearance = SignalHead.RED; 975 } 976 977 // check if signal if held, forcing a red appearance by this calculation 978 if (((SignalHead) outputs[0]).getHeld()) { 979 appearance = SignalHead.RED; 980 } 981 982 // handle approach lighting 983 doApproach(); 984 985 // show result if changed 986 if (appearance != oldAppearance) { 987 ((SignalHead) outputs[0]).setAppearance(appearance); 988 if (log.isDebugEnabled()) { 989 log.debug("Change appearance of {} to: {}", name, appearance); 990 } 991 } 992 } 993 994 private void doFacing() { 995 int appearance = SignalHead.GREEN; 996 int oldAppearance = ((SignalHead) outputs[0]).getAppearance(); 997 998 // find downstream appearance, being pessimistic if we're not sure of the state 999 int s = SignalHead.GREEN; 1000 if (watchTurnout != null && watchTurnout.getBean().getKnownState() != Turnout.THROWN) { 1001 s = slowerOf(s, fastestColor1()); 1002 } 1003 if (watchTurnout != null && watchTurnout.getBean().getKnownState() != Turnout.CLOSED) { 1004 s = slowerOf(s, fastestColor2()); 1005 } 1006 1007 // check for yellow, flashing yellow overriding green 1008 if (protectWithFlashing && s == SignalHead.YELLOW) { 1009 appearance = SignalHead.FLASHYELLOW; 1010 } 1011 if (s == SignalHead.RED || s == SignalHead.FLASHRED) { 1012 appearance = SignalHead.YELLOW; 1013 } 1014 // if distant signal, show exactly what the home signal does 1015 if (distantSignal) { 1016 appearance = s; 1017 } 1018 1019 // if limited speed and green or flashing yellow, reduce to yellow 1020 if (watchTurnout != null && limitSpeed1 && watchTurnout.getBean().getKnownState() != Turnout.THROWN) { 1021 appearance = slowerOf(appearance, SignalHead.YELLOW); 1022 } 1023 if (watchTurnout != null && limitSpeed2 && watchTurnout.getBean().getKnownState() != Turnout.CLOSED) { 1024 appearance = slowerOf(appearance, SignalHead.YELLOW); 1025 } 1026 // if restricting, limit to flashing red 1027 if (watchTurnout != null && restrictingSpeed1 && watchTurnout.getBean().getKnownState() != Turnout.THROWN) { 1028 appearance = slowerOf(appearance, SignalHead.FLASHRED); 1029 } 1030 if (watchTurnout != null && restrictingSpeed2 && watchTurnout.getBean().getKnownState() != Turnout.CLOSED) { 1031 appearance = slowerOf(appearance, SignalHead.FLASHRED); 1032 } 1033 1034 // check for red overriding yellow or green 1035 if (watchSensor1 != null && watchSensor1.getBean().getKnownState() != Sensor.INACTIVE) { 1036 appearance = SignalHead.RED; 1037 } 1038 if (watchSensor2 != null && watchSensor2.getBean().getKnownState() != Sensor.INACTIVE) { 1039 appearance = SignalHead.RED; 1040 } 1041 if (watchSensor3 != null && watchSensor3.getBean().getKnownState() != Sensor.INACTIVE) { 1042 appearance = SignalHead.RED; 1043 } 1044 if (watchSensor4 != null && watchSensor4.getBean().getKnownState() != Sensor.INACTIVE) { 1045 appearance = SignalHead.RED; 1046 } 1047 if (watchSensor5 != null && watchSensor5.getBean().getKnownState() != Sensor.INACTIVE) { 1048 appearance = SignalHead.RED; 1049 } 1050 1051 if ((watchTurnout != null && watchTurnout.getBean().getKnownState() == Turnout.CLOSED) 1052 && (watchedSensor1 != null && watchedSensor1.getBean().getKnownState() != Sensor.INACTIVE)) { 1053 appearance = SignalHead.RED; 1054 } 1055 if ((watchTurnout != null && watchTurnout.getBean().getKnownState() == Turnout.CLOSED) && 1056 (watchedSensor1Alt != null && watchedSensor1Alt.getBean().getKnownState() != Sensor.INACTIVE)) { 1057 appearance = SignalHead.RED; 1058 } 1059 if ((watchTurnout != null && watchTurnout.getBean().getKnownState() == Turnout.THROWN) && 1060 (watchedSensor2 != null && watchedSensor2.getBean().getKnownState() != Sensor.INACTIVE)) { 1061 appearance = SignalHead.RED; 1062 } 1063 if ((watchTurnout != null && watchTurnout.getBean().getKnownState() == Turnout.THROWN) && 1064 (watchedSensor2Alt != null && watchedSensor2Alt.getBean().getKnownState() != Sensor.INACTIVE)) { 1065 appearance = SignalHead.RED; 1066 } 1067 1068 // check if turnout in motion, if so force red 1069 if (watchTurnout != null && (watchTurnout.getBean().getKnownState() != watchTurnout.getBean().getCommandedState())) { 1070 appearance = SignalHead.RED; 1071 } 1072 if (watchTurnout != null && (watchTurnout.getBean().getKnownState() != Turnout.THROWN) && (watchTurnout.getBean().getKnownState() != Turnout.CLOSED)) // checking for other states 1073 { 1074 appearance = SignalHead.RED; 1075 } 1076 1077 // check if signal if held, forcing a red appearance by this calculation 1078 if (((SignalHead) outputs[0]).getHeld()) { 1079 appearance = SignalHead.RED; 1080 } 1081 1082 // handle approach lighting 1083 doApproach(); 1084 1085 // show result if changed 1086 if (appearance != oldAppearance) { 1087 ((SignalHead) outputs[0]).setAppearance(appearance); 1088 } 1089 } 1090 1091 /** 1092 * Handle the approach lighting logic for all modes. 1093 */ 1094 private void doApproach() { 1095 if (approachSensor1 != null && approachSensor1.getBean().getKnownState() == Sensor.INACTIVE) { 1096 // should not be lit 1097 if (driveSignal.getBean().getLit()) { 1098 driveSignal.getBean().setLit(false); 1099 } 1100 } else { 1101 // should be lit 1102 if (!driveSignal.getBean().getLit()) { 1103 driveSignal.getBean().setLit(true); 1104 } 1105 } 1106 } 1107 1108 /** 1109 * Get the BlockBossLogic item governing a specific signal head by its name, 1110 * having removed it from use. 1111 * 1112 * @param signal name of the signal head object 1113 * @return never null 1114 */ 1115 @Nonnull 1116 @edu.umd.cs.findbugs.annotations.SuppressFBWarnings(value = "NP_NULL_ON_SOME_PATH_FROM_RETURN_VALUE", 1117 justification="enforced dynamically, too hard to prove statically") 1118 public static BlockBossLogic getStoppedObject(String signal) { 1119 // As a static requirement, the signal head must exist, but 1120 // we can't express that statically. We test it dynamically. 1121 SignalHead sh = InstanceManager.getDefault(SignalHeadManager.class).getSignalHead(signal); 1122 java.util.Objects.requireNonNull(sh, "signal head must exist"); 1123 return getStoppedObject(sh); 1124 } 1125 1126 /** 1127 * Get the BlockBossLogic item governing a specific signal head, having 1128 * removed it from use. 1129 * 1130 * @param sh signal head object 1131 * @return never null 1132 */ 1133 @Nonnull 1134 public static BlockBossLogic getStoppedObject(@Nonnull SignalHead sh) { 1135 BlockBossLogic b = InstanceManager.getDefault(BlockBossLogicProvider.class).provide(sh); 1136 b.stop(); 1137 return b; 1138 } 1139 1140 @Override 1141 public void vetoableChange(java.beans.PropertyChangeEvent evt) throws java.beans.PropertyVetoException { 1142 NamedBean nb = (NamedBean) evt.getOldValue(); 1143 if ("CanDelete".equals(evt.getPropertyName())) { // NOI18N 1144 processCanDelete(evt, nb); 1145 } else if ("DoDelete".equals(evt.getPropertyName())) { // NOI18N 1146 processDoDelete(nb); 1147 } 1148 } 1149 1150 private void processDoDelete(NamedBean nb) { 1151 if (nb instanceof SignalHead) { 1152 deleteSignalHead(nb); 1153 } else if (nb instanceof Turnout) { 1154 deleteTurnout(nb); 1155 } else if (nb instanceof Sensor) { 1156 deleteSensor(nb); 1157 } 1158 } 1159 1160 private void deleteSensor(NamedBean nb) { 1161 if (watchSensor1 != null && watchSensor1.getBean().equals(nb)) { 1162 stop(); 1163 setSensor1(null); 1164 start(); 1165 } 1166 if (watchSensor2 != null && watchSensor2.getBean().equals(nb)) { 1167 stop(); 1168 setSensor2(null); 1169 start(); 1170 } 1171 if (watchSensor3 != null && watchSensor3.getBean().equals(nb)) { 1172 stop(); 1173 setSensor3(null); 1174 start(); 1175 } 1176 if (watchSensor4 != null && watchSensor4.getBean().equals(nb)) { 1177 stop(); 1178 setSensor4(null); 1179 start(); 1180 } 1181 if (watchSensor5 != null && watchSensor5.getBean().equals(nb)) { 1182 stop(); 1183 setSensor5(null); 1184 start(); 1185 } 1186 if (watchedSensor1 != null && watchedSensor1.getBean().equals(nb)) { 1187 stop(); 1188 setWatchedSensor1(null); 1189 start(); 1190 } 1191 if (watchedSensor2 != null && watchedSensor2.getBean().equals(nb)) { 1192 stop(); 1193 setWatchedSensor2(null); 1194 start(); 1195 } 1196 if (watchedSensor1Alt != null && watchedSensor1Alt.getBean().equals(nb)) { 1197 stop(); 1198 setWatchedSensor1Alt(null); 1199 start(); 1200 } 1201 if (watchedSensor2Alt != null && watchedSensor2Alt.getBean().equals(nb)) { 1202 stop(); 1203 setWatchedSensor2Alt(null); 1204 start(); 1205 } 1206 if (approachSensor1 != null && approachSensor1.getBean().equals(nb)) { 1207 stop(); 1208 setApproachSensor1(null); 1209 start(); 1210 } 1211 } 1212 1213 private void deleteTurnout(NamedBean nb) { 1214 if (watchTurnout != null && watchTurnout.getBean().equals(nb)) { 1215 stop(); 1216 setTurnout(null); 1217 start(); 1218 } 1219 } 1220 1221 private void deleteSignalHead(NamedBean nb) { 1222 if (nb.equals(getDrivenSignalNamedBean().getBean())) { 1223 stop(); 1224 1225 InstanceManager.getDefault(BlockBossLogicProvider.class).remove(this); 1226 } 1227 if (watchedSignal1 != null && watchedSignal1.getBean().equals(nb)) { 1228 stop(); 1229 setWatchedSignal1(null, false); 1230 start(); 1231 } 1232 if (watchedSignal1Alt != null && watchedSignal1Alt.getBean().equals(nb)) { 1233 stop(); 1234 setWatchedSignal1Alt(null); 1235 start(); 1236 } 1237 if (watchedSignal2 != null && watchedSignal2.getBean().equals(nb)) { 1238 stop(); 1239 setWatchedSignal2(null); 1240 start(); 1241 } 1242 if (watchedSignal2Alt != null && watchedSignal2Alt.getBean().equals(nb)) { 1243 stop(); 1244 setWatchedSignal2Alt(null); 1245 start(); 1246 } 1247 } 1248 1249 private void processCanDelete(PropertyChangeEvent evt, NamedBean nb) throws java.beans.PropertyVetoException { 1250 log.debug("name: {} got {} from {}", name, evt, evt.getSource()); 1251 1252 StringBuilder message = new StringBuilder(); 1253 message.append(Bundle.getMessage("InUseBlockBossHeader", getDrivenSignal())); 1254 1255 boolean found = false; 1256 1257 if (nb instanceof SignalHead) { 1258 found = canDeleteSignalHead(evt, nb, message, found); 1259 } else if (nb instanceof Turnout) { 1260 found = canDeleteTurnout(nb, message, found); 1261 } else if (nb instanceof Sensor) { 1262 found = canDeleteSensor(nb, message, found); 1263 } 1264 if (found) { 1265 message.append(Bundle.getMessage("InUseBlockBossFooter")); // NOI18N 1266 throw new java.beans.PropertyVetoException(message.toString(), evt); 1267 } 1268 } 1269 1270 private boolean canDeleteSensor(NamedBean nb, StringBuilder message, boolean found) { 1271 message.append("<ul>"); 1272 if ((watchSensor1 != null && watchSensor1.getBean().equals(nb)) 1273 || (watchSensor2 != null && watchSensor2.getBean().equals(nb)) 1274 || (watchSensor3 != null && watchSensor3.getBean().equals(nb)) 1275 || (watchSensor4 != null && watchSensor4.getBean().equals(nb)) 1276 || (watchSensor5 != null && watchSensor5.getBean().equals(nb))) { 1277 addMessageToHtmlList(message, "<li>", "InUseWatchedSensor", "</li>"); 1278 found = true; 1279 } 1280 if ((watchedSensor1 != null && watchedSensor1.getBean().equals(nb)) 1281 || (watchedSensor2 != null && watchedSensor2.getBean().equals(nb)) 1282 || (watchedSensor1Alt != null && watchedSensor1Alt.getBean().equals(nb)) 1283 || (watchedSensor2Alt != null && watchedSensor2Alt.getBean().equals(nb))) { 1284 addMessageToHtmlList(message, "<li>", "InUseWatchedSensor", "</li>"); 1285 found = true; 1286 1287 } 1288 if (approachSensor1 != null && approachSensor1.getBean().equals(nb)) { 1289 found = true; 1290 addMessageToHtmlList(message, "<li>", "InUseApproachSensor", "</li>"); 1291 } 1292 1293 message.append("</ul>"); 1294 return found; 1295 } 1296 1297 private boolean canDeleteTurnout(NamedBean nb, StringBuilder message, boolean found) { 1298 if (watchTurnout != null && watchTurnout.getBean().equals(nb)) { 1299 found = true; 1300 addMessageToHtmlList(message, "<ul>", "InUseWatchedTurnout", "</ul>"); 1301 } 1302 return found; 1303 } 1304 1305 private boolean canDeleteSignalHead(PropertyChangeEvent evt, NamedBean nb, StringBuilder message, boolean found) throws java.beans.PropertyVetoException { 1306 if (nb.equals(getDrivenSignalNamedBean().getBean())) { 1307 message.append("<br><b>").append(Bundle.getMessage("InUseThisSslWillBeDeleted")).append("</b>"); 1308 throw new java.beans.PropertyVetoException(message.toString(), evt); 1309 } 1310 if ((watchedSignal1 != null && watchedSignal1.getBean().equals(nb)) 1311 || (watchedSignal1Alt != null && watchedSignal1Alt.getBean().equals(nb)) 1312 || (watchedSignal2 != null && watchedSignal2.getBean().equals(nb)) 1313 || (watchedSignal2Alt != null && watchedSignal2Alt.getBean().equals(nb))) { 1314 addMessageToHtmlList(message, "<ul>", "InUseWatchedSignal", "</ul>"); 1315 found = true; 1316 } 1317 return found; 1318 } 1319 1320 private void addMessageToHtmlList(StringBuilder message, String s, String inUseWatchedSignal, String s2) { 1321 message.append(s); 1322 message.append(Bundle.getMessage(inUseWatchedSignal)); 1323 message.append(s2); 1324 } 1325 1326 public List<NamedBeanUsageReport> getUsageReport(NamedBean bean) { 1327 List<NamedBeanUsageReport> report = new ArrayList<>(); 1328 SignalHead head = driveSignal.getBean(); 1329 if (bean != null) { 1330 if (watchSensor1 != null && bean.equals(getDrivenSignalNamedBean().getBean())) { 1331 report.add(new NamedBeanUsageReport("SSLSignal", head)); // NOI18N 1332 } 1333 if (watchSensor1 != null && bean.equals(watchSensor1.getBean())) { 1334 report.add(new NamedBeanUsageReport("SSLSensor1", head)); // NOI18N 1335 } 1336 if (watchSensor2 != null && bean.equals(watchSensor2.getBean())) { 1337 report.add(new NamedBeanUsageReport("SSLSensor2", head)); // NOI18N 1338 } 1339 if (watchSensor3 != null && bean.equals(watchSensor3.getBean())) { 1340 report.add(new NamedBeanUsageReport("SSLSensor3", head)); // NOI18N 1341 } 1342 if (watchSensor4 != null && bean.equals(watchSensor4.getBean())) { 1343 report.add(new NamedBeanUsageReport("SSLSensor4", head)); // NOI18N 1344 } 1345 if (watchSensor5 != null && bean.equals(watchSensor5.getBean())) { 1346 report.add(new NamedBeanUsageReport("SSLSensor5", head)); // NOI18N 1347 } 1348 if (watchTurnout != null && bean.equals(watchTurnout.getBean())) { 1349 report.add(new NamedBeanUsageReport("SSLTurnout", head)); // NOI18N 1350 } 1351 if (watchedSignal1 != null && bean.equals(watchedSignal1.getBean())) { 1352 report.add(new NamedBeanUsageReport("SSLSignal1", head)); // NOI18N 1353 } 1354 if (watchedSignal1Alt != null && bean.equals(watchedSignal1Alt.getBean())) { 1355 report.add(new NamedBeanUsageReport("SSLSignal1Alt", head)); // NOI18N 1356 } 1357 if (watchedSignal2 != null && bean.equals(watchedSignal2.getBean())) { 1358 report.add(new NamedBeanUsageReport("SSLSignal2", head)); // NOI18N 1359 } 1360 if (watchedSignal2Alt != null && bean.equals(watchedSignal2Alt.getBean())) { 1361 report.add(new NamedBeanUsageReport("SSLSignal2Alt", head)); // NOI18N 1362 } 1363 if (watchedSensor1 != null && bean.equals(watchedSensor1.getBean())) { 1364 report.add(new NamedBeanUsageReport("SSLSensorWatched1", head)); // NOI18N 1365 } 1366 if (watchedSensor1Alt != null && bean.equals(watchedSensor1Alt.getBean())) { 1367 report.add(new NamedBeanUsageReport("SSLSensorWatched1Alt", head)); // NOI18N 1368 } 1369 if (watchedSensor2 != null && bean.equals(watchedSensor2.getBean())) { 1370 report.add(new NamedBeanUsageReport("SSLSensorWatched2", head)); // NOI18N 1371 } 1372 if (watchedSensor2Alt != null && bean.equals(watchedSensor2Alt.getBean())) { 1373 report.add(new NamedBeanUsageReport("SSLSensorWatched2Alt", head)); // NOI18N 1374 } 1375 if (approachSensor1 != null && bean.equals(approachSensor1.getBean())) { 1376 report.add(new NamedBeanUsageReport("SSLSensorApproach", head)); // NOI18N 1377 } 1378 } 1379 return report; 1380 } 1381 1382 private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(BlockBossLogic.class); 1383 1384}