001package jmri.implementation; 002 003import java.beans.PropertyChangeEvent; 004import java.beans.PropertyChangeListener; 005import java.beans.PropertyVetoException; 006import java.beans.VetoableChangeListener; 007import java.util.*; 008 009import javax.annotation.Nonnull; 010 011import jmri.*; 012import jmri.jmrit.display.EditorManager; 013import jmri.jmrit.display.layoutEditor.ConnectivityUtil; 014import jmri.jmrit.display.layoutEditor.LayoutBlock; 015import jmri.jmrit.display.layoutEditor.LayoutBlockConnectivityTools; 016import jmri.jmrit.display.layoutEditor.LayoutBlockManager; 017import jmri.jmrit.display.layoutEditor.LayoutEditor; 018import jmri.jmrit.display.layoutEditor.LayoutSlip; 019import jmri.jmrit.display.layoutEditor.LayoutTrackExpectedState; 020import jmri.jmrit.display.layoutEditor.LayoutTurnout; 021import jmri.jmrit.display.layoutEditor.LayoutTraverser; 022import jmri.jmrit.display.layoutEditor.LayoutTurntable; 023import jmri.jmrit.display.layoutEditor.LevelXing; 024import jmri.util.ThreadingUtil; 025 026/** 027 * Default implementation of {@link jmri.SignalMastLogic}. 028 * 029 * @author Kevin Dickerson Copyright (C) 2011 030 */ 031public class DefaultSignalMastLogic extends AbstractNamedBean implements SignalMastLogic, VetoableChangeListener { 032 033 SignalMast source; 034 SignalMast destination; 035 String stopAspect; 036 037 Hashtable<SignalMast, DestinationMast> destList = new Hashtable<>(); 038 LayoutEditor editor; 039 040 LayoutBlock facingBlock = null; 041 LayoutBlock remoteProtectingBlock = null; 042 043 boolean disposing = false; 044 045 /** 046 * Initialise a Signal Mast Logic for a given source Signal Mast. 047 * 048 * @param source The Signal Mast we are configuring an SML for 049 */ 050 public DefaultSignalMastLogic(@Nonnull SignalMast source) { 051 super(source.toString()); // default system name 052 this.source = source; 053 try { 054 this.stopAspect = source.getAppearanceMap().getSpecificAppearance(SignalAppearanceMap.DANGER); 055 this.source.addPropertyChangeListener(propertySourceMastListener); 056 if (source.getAspect() == null) { 057 source.setAspect(stopAspect); 058 } 059 } catch (Exception ex) { 060 log.error("Error while creating Signal Logic", ex); 061 } 062 } 063 064 // Most of the following methods will inherit Javadoc from SignalMastLogic.java 065 /** 066 * {@inheritDoc } 067 */ 068 @Override 069 public void setFacingBlock(LayoutBlock facing) { 070 facingBlock = facing; 071 } 072 073 /** 074 * {@inheritDoc } 075 */ 076 @Override 077 public LayoutBlock getFacingBlock() { 078 return facingBlock; 079 } 080 081 /** 082 * {@inheritDoc } 083 */ 084 @Override 085 public LayoutBlock getProtectingBlock(@Nonnull SignalMast dest) { 086 if (!destList.containsKey(dest)) { 087 return null; 088 } 089 return destList.get(dest).getProtectingBlock(); 090 } 091 092 /** 093 * {@inheritDoc } 094 */ 095 @Override 096 public SignalMast getSourceMast() { 097 return source; 098 } 099 100 /** 101 * {@inheritDoc } 102 */ 103 @Override 104 public void replaceSourceMast(SignalMast oldMast, SignalMast newMast) { 105 if (oldMast != source) { 106 // Old mast does not match new mast so will exit replace 107 return; 108 } 109 source.removePropertyChangeListener(propertySourceMastListener); 110 source = newMast; 111 stopAspect = source.getAppearanceMap().getSpecificAppearance(SignalAppearanceMap.DANGER); 112 source.addPropertyChangeListener(propertySourceMastListener); 113 if (source.getAspect() == null) { 114 source.setAspect(stopAspect); 115 } 116 getDestinationList().forEach(sm -> { 117 DestinationMast destMast = destList.get(sm); 118 if (destMast.getAssociatedSection() != null) { 119 String oldUserName = destMast.getAssociatedSection().getUserName(); 120 String newUserName = source.getDisplayName() + ":" + sm.getDisplayName(); 121 if (oldUserName != null) { 122 InstanceManager.getDefault(NamedBeanHandleManager.class) 123 .renameBean(oldUserName, newUserName, ((NamedBean) destMast.getAssociatedSection())); 124 } else { 125 log.warn("AssociatedSection oldUserName null for destination mast {}, skipped", 126 destMast.getDisplayName()); 127 } 128 } 129 }); 130 firePropertyChange(PROPERTY_UPDATED_SOURCE, oldMast, newMast); 131 } 132 133 /** 134 * {@inheritDoc } 135 */ 136 @Override 137 public void replaceDestinationMast(SignalMast oldMast, SignalMast newMast) { 138 if (!destList.containsKey(oldMast)) { 139 return; 140 } 141 DestinationMast destMast = destList.get(oldMast); 142 destMast.updateDestinationMast(newMast); 143 if (destination == oldMast) { 144 oldMast.removePropertyChangeListener(propertyDestinationMastListener); 145 newMast.addPropertyChangeListener(propertyDestinationMastListener); 146 destination = newMast; 147 setSignalAppearance(); 148 } 149 destList.remove(oldMast); 150 if (destMast.getAssociatedSection() != null) { 151 String oldUserName = destMast.getAssociatedSection().getUserName(); 152 String newUserName = source.getDisplayName() + ":" + newMast.getDisplayName(); 153 if (oldUserName != null) { 154 InstanceManager.getDefault(NamedBeanHandleManager.class) 155 .renameBean(oldUserName, newUserName, destMast.getAssociatedSection()); 156 } else { 157 log.warn("AssociatedSection oldUserName null for destination mast {}, skipped", 158 destMast.getDisplayName()); 159 } 160 } 161 destList.put(newMast, destMast); 162 firePropertyChange(PROPERTY_UPDATED_DESTINATION, oldMast, newMast); 163 } 164 165 /** 166 * {@inheritDoc } 167 */ 168 @Override 169 public void setDestinationMast(SignalMast dest) { 170 if (destList.containsKey(dest)) { 171 // if already present, not a change 172 log.debug("Destination mast '{}' was already defined in SML with this source mast", dest.getDisplayName()); 173 return; 174 } 175 int oldSize = destList.size(); 176 destList.put(dest, new DestinationMast(dest)); 177 //InstanceManager.getDefault(SignalMastLogicManager.class).addDestinationMastToLogic(this, dest); 178 firePropertyChange(PROPERTY_LENGTH, oldSize, destList.size()); 179 // make new dest mast appear in (update of) SignallingSourcePanel Table by having that table listen to PropertyChange Events from SML TODO 180 } 181 182 /** 183 * {@inheritDoc } 184 */ 185 @Override 186 public boolean isDestinationValid(SignalMast dest) { 187 if (dest == null) { 188 return false; 189 } 190 return destList.containsKey(dest); 191 } 192 193 /** 194 * {@inheritDoc } 195 */ 196 @Override 197 public List<SignalMast> getDestinationList() { 198 List<SignalMast> out = new ArrayList<>(); 199 Enumeration<SignalMast> en = destList.keys(); 200 while (en.hasMoreElements()) { 201 out.add(en.nextElement()); 202 } 203 return out; 204 } 205 206 /** 207 * {@inheritDoc } 208 */ 209 @Override 210 public String getComment(SignalMast dest) { 211 if (!destList.containsKey(dest)) { 212 return ""; 213 } 214 return destList.get(dest).getComment(); 215 } 216 217 /** 218 * {@inheritDoc } 219 */ 220 @Override 221 public void setComment(String comment, SignalMast dest) { 222 if (!destList.containsKey(dest)) { 223 return; 224 } 225 destList.get(dest).setComment(comment); 226 } 227 228 /** 229 * {@inheritDoc } 230 */ 231 @Override 232 public void setStore(int store, SignalMast destination) { 233 if (!destList.containsKey(destination)) { 234 return; 235 } 236 destList.get(destination).setStore(store); 237 } 238 239 /** 240 * {@inheritDoc } 241 */ 242 @Override 243 public int getStoreState(SignalMast destination) { 244 if (!destList.containsKey(destination)) { 245 return STORENONE; 246 } 247 return destList.get(destination).getStoreState(); 248 } 249 250 /** 251 * {@inheritDoc } 252 */ 253 @Override 254 public void setEnabled(SignalMast dest) { 255 if (!destList.containsKey(dest)) { 256 return; 257 } 258 destList.get(dest).setEnabled(); 259 } 260 261 /** 262 * {@inheritDoc } 263 */ 264 @Override 265 public void setDisabled(SignalMast dest) { 266 if (!destList.containsKey(dest)) { 267 return; 268 } 269 destList.get(dest).setDisabled(); 270 } 271 272 /** 273 * {@inheritDoc } 274 */ 275 @Override 276 public boolean isEnabled(SignalMast dest) { 277 if (!destList.containsKey(dest)) { 278 return false; 279 } 280 return destList.get(dest).isEnabled(); 281 } 282 283 /** 284 * {@inheritDoc } 285 */ 286 @Override 287 public boolean isActive(SignalMast dest) { 288 if (!destList.containsKey(dest)) { 289 return false; 290 } 291 return destList.get(dest).isActive(); 292 } 293 294 /** 295 * {@inheritDoc } 296 */ 297 @Override 298 public SignalMast getActiveDestination() { 299 for (SignalMast sm : getDestinationList()) { 300 if (destList.get(sm).isActive()) { 301 return sm; 302 } 303 } 304 return null; 305 } 306 307 /** 308 * {@inheritDoc } 309 */ 310 @Override 311 public boolean removeDestination(SignalMast dest) { 312 int oldSize = destList.size(); 313 if (destList.containsKey(dest)) { 314 //InstanceManager.getDefault(SignalMastLogicManager.class).removeDestinationMastToLogic(this, dest); 315 destList.get(dest).dispose(); 316 destList.remove(dest); 317 firePropertyChange(PROPERTY_LENGTH, oldSize, destList.size()); 318 } 319 return destList.isEmpty(); 320 } 321 322 /** 323 * {@inheritDoc } 324 */ 325 @Override 326 public void disableLayoutEditorUse() { 327 destList.values().forEach(dest -> { 328 try { 329 dest.useLayoutEditor(false); 330 } catch (JmriException e) { 331 log.error("Could not disable LayoutEditor ", e); 332 } 333 }); 334 } 335 336 /** 337 * {@inheritDoc } 338 */ 339 @Override 340 public void useLayoutEditor(boolean boo, SignalMast destination) throws JmriException { 341 if (!destList.containsKey(destination)) { 342 return; 343 } 344 if (boo) { 345 log.debug("Set use layout editor"); 346 Set<LayoutEditor> layout = InstanceManager.getDefault(EditorManager.class).getAll(LayoutEditor.class); 347 /*We don't care which layout editor panel the signalmast is on, just so long as 348 the routing is done via layout blocks*/ 349 // TODO: what is this? 350 log.debug("userLayoutEditor finds layout list size is {}", layout.size()); 351 for (LayoutEditor findeditor : layout) { 352 log.debug("layouteditor {}", findeditor.getLayoutName()); 353 if (facingBlock == null) { 354 facingBlock = InstanceManager.getDefault(LayoutBlockManager.class) 355 .getFacingBlockByMast(getSourceMast(), findeditor); 356 } 357 } 358 } 359 destList.get(destination).useLayoutEditor(boo); 360 } 361 362 /** 363 * Add direction sensors to SML 364 * 365 * @return number of errors 366 */ 367 @Override 368 public int setupDirectionSensors() { 369 // iterrate over the signal masts 370 int errorCount = 0; 371 for (SignalMast sm : getDestinationList()) { 372 String displayName = sm.getDisplayName(); 373 Section sec = getAssociatedSection(sm); 374 if (sec != null) { 375 Block thisFacingBlock; 376 Sensor fwd = sec.getForwardBlockingSensor(); 377 Sensor rev = sec.getReverseBlockingSensor(); 378 LayoutBlock lBlock = getFacingBlock(); 379 if (lBlock == null) { 380 try { 381 useLayoutEditor(true, sm); // force a refind 382 } catch (JmriException ex) { 383 continue; 384 } 385 } 386 if (lBlock != null) { 387 thisFacingBlock = lBlock.getBlock(); 388 EntryPoint fwdEntryPoint = sec.getEntryPointFromBlock(thisFacingBlock, Section.FORWARD); 389 EntryPoint revEntryPoint = sec.getEntryPointFromBlock(thisFacingBlock, Section.REVERSE); 390 log.debug("Mast[{}] Sec[{}] Fwd[{}] Rev [{}]", 391 displayName, sec, fwd, rev); 392 if (fwd != null && fwdEntryPoint != null) { 393 addSensor(fwd.getUserName(), Sensor.INACTIVE, sm); 394 log.debug("Mast[{}] Sec[{}] Fwd[{}] fwdEP[{}]", 395 displayName, sec, fwd, 396 fwdEntryPoint.getBlock().getUserName()); 397 398 } else if (rev != null && revEntryPoint != null) { 399 addSensor(rev.getUserName(), Sensor.INACTIVE, sm); 400 log.debug("Mast[{}] Sec[{}] Rev [{}] revEP[{}]", 401 displayName, sec, rev, 402 revEntryPoint.getBlock().getUserName()); 403 404 } else { 405 log.error("Mast[{}] Cannot Establish entry point to protected section", displayName); 406 errorCount += 1; 407 } 408 } else { 409 log.error("Mast[{}] No Facing Block", displayName); 410 errorCount += 1; 411 } 412 } else { 413 log.error("Mast[{}] No Associated Section", displayName); 414 errorCount += 1; 415 } 416 } 417 return errorCount; 418 } 419 420 /** 421 * {@inheritDoc } 422 */ 423 @Override 424 public void removeDirectionSensors() { 425 //TODO find aaway of easilty identifying the ones we added. 426 } 427 428 /** 429 * {@inheritDoc } 430 */ 431 @Override 432 public boolean useLayoutEditor(SignalMast destination) { 433 if (!destList.containsKey(destination)) { 434 return false; 435 } 436 return destList.get(destination).useLayoutEditor(); 437 } 438 439 /** 440 * {@inheritDoc } 441 */ 442 @Override 443 public void useLayoutEditorDetails(boolean turnouts, boolean blocks, SignalMast destination) throws JmriException { 444 if (!destList.containsKey(destination)) { 445 return; 446 } 447 destList.get(destination).useLayoutEditorDetails(turnouts, blocks); 448 } 449 450 /** 451 * {@inheritDoc } 452 */ 453 @Override 454 public boolean useLayoutEditorBlocks(SignalMast destination) { 455 if (!destList.containsKey(destination)) { 456 return false; 457 } 458 return destList.get(destination).useLayoutEditorBlocks(); 459 } 460 461 /** 462 * {@inheritDoc } 463 */ 464 @Override 465 public boolean useLayoutEditorTurnouts(SignalMast destination) { 466 if (!destList.containsKey(destination)) { 467 return false; 468 } 469 return destList.get(destination).useLayoutEditorTurnouts(); 470 } 471 472 /** 473 * {@inheritDoc } 474 */ 475 @Override 476 public Section getAssociatedSection(SignalMast destination) { 477 if (!destList.containsKey(destination)) { 478 return null; 479 } 480 return destList.get(destination).getAssociatedSection(); 481 } 482 483 /** 484 * {@inheritDoc } 485 */ 486 @Override 487 public void setAssociatedSection(Section sec, SignalMast destination) { 488 if (!destList.containsKey(destination)) { 489 return; 490 } 491 destList.get(destination).setAssociatedSection(sec); 492 } 493 494 /** 495 * {@inheritDoc } 496 */ 497 @Override 498 public boolean allowAutoMaticSignalMastGeneration(SignalMast destination) { 499 if (!destList.containsKey(destination)) { 500 return false; 501 } 502 return destList.get(destination).allowAutoSignalMastGen(); 503 } 504 505 /** 506 * {@inheritDoc } 507 */ 508 @Override 509 public void allowAutoMaticSignalMastGeneration(boolean allow, SignalMast destination) { 510 if (!destList.containsKey(destination)) { 511 return; 512 } 513 destList.get(destination).allowAutoSignalMastGen(allow); 514 } 515 516 /** 517 * {@inheritDoc } 518 */ 519 @Override 520 public void allowTurnoutLock(boolean lock, SignalMast destination) { 521 if (!destList.containsKey(destination)) { 522 return; 523 } 524 destList.get(destination).allowTurnoutLock(lock); 525 } 526 527 /** 528 * {@inheritDoc } 529 */ 530 @Override 531 public boolean isTurnoutLockAllowed(SignalMast destination) { 532 if (!destList.containsKey(destination)) { 533 return false; 534 } 535 return destList.get(destination).isTurnoutLockAllowed(); 536 } 537 538 /** 539 * {@inheritDoc } 540 */ 541 @Override 542 public void setTurnouts(Hashtable<NamedBeanHandle<Turnout>, Integer> turnouts, SignalMast destination) { 543 if (!destList.containsKey(destination)) { 544 return; 545 } 546 destList.get(destination).setTurnouts(turnouts); 547 } 548 549 /** 550 * {@inheritDoc } 551 */ 552 @Override 553 public void setAutoTurnouts(Hashtable<Turnout, Integer> turnouts, SignalMast destination) { 554 if (!destList.containsKey(destination)) { 555 return; 556 } 557 destList.get(destination).setAutoTurnouts(turnouts); 558 } 559 560 /** 561 * {@inheritDoc } 562 */ 563 @Override 564 public void setBlocks(Hashtable<Block, Integer> blocks, SignalMast destination) { 565 if (!destList.containsKey(destination)) { 566 return; 567 } 568 destList.get(destination).setBlocks(blocks); 569 } 570 571 /** 572 * {@inheritDoc } 573 */ 574 @Override 575 public void setAutoBlocks(LinkedHashMap<Block, Integer> blocks, SignalMast destination) { 576 if (!destList.containsKey(destination)) { 577 return; 578 } 579 destList.get(destination).setAutoBlocks(blocks); 580 } 581 582 /** 583 * {@inheritDoc } 584 */ 585 @Override 586 public void setMasts(Hashtable<SignalMast, String> masts, SignalMast destination) { 587 if (!destList.containsKey(destination)) { 588 return; 589 } 590 destList.get(destination).setMasts(masts); 591 } 592 593 /** 594 * {@inheritDoc } 595 */ 596 @Override 597 public void setAutoMasts(Hashtable<SignalMast, String> masts, SignalMast destination) { 598 if (!destList.containsKey(destination)) { 599 return; 600 } 601 destList.get(destination).setAutoMasts(masts, true); 602 } 603 604 /** 605 * {@inheritDoc } 606 */ 607 @Override 608 public void setSensors(Hashtable<NamedBeanHandle<Sensor>, Integer> sensors, SignalMast destination) { 609 if (!destList.containsKey(destination)) { 610 return; 611 } 612 destList.get(destination).setSensors(sensors); 613 } 614 615 /** 616 * {@inheritDoc } 617 */ 618 @Override 619 public void addSensor(String sensorName, int state, SignalMast destination) { 620 if (!destList.containsKey(destination)) { 621 return; 622 } 623 Sensor sen = InstanceManager.sensorManagerInstance().getSensor(sensorName); 624 if (sen != null) { 625 NamedBeanHandle<Sensor> namedSensor = InstanceManager.getDefault(NamedBeanHandleManager.class) 626 .getNamedBeanHandle(sensorName, sen); 627 destList.get(destination).addSensor(namedSensor, state); 628 } 629 } 630 631 /** 632 * {@inheritDoc } 633 */ 634 @Override 635 public void removeSensor(String sensorName, SignalMast destination) { 636 Sensor sen = InstanceManager.sensorManagerInstance().getSensor(sensorName); 637 removeSensor(sen, destination); 638 } 639 640 public void removeSensor(Sensor sen, SignalMast destination) { 641 if (!destList.containsKey(destination)) { 642 return; 643 } 644 if (sen != null) { 645 destList.get(destination).removeSensor(sen); 646 } 647 } 648 649 /** 650 * {@inheritDoc } 651 */ 652 @Override 653 public List<Block> getBlocks(SignalMast destination) { 654 if (!destList.containsKey(destination)) { 655 return new ArrayList<>(); 656 } 657 return destList.get(destination).getBlocks(); 658 } 659 660 /** 661 * {@inheritDoc } 662 */ 663 @Override 664 public List<Block> getAutoBlocks(SignalMast destination) { 665 if (!destList.containsKey(destination)) { 666 return new ArrayList<>(); 667 } 668 return destList.get(destination).getAutoBlocks(); 669 } 670 671 /** 672 * {@inheritDoc } 673 */ 674 @Override 675 public List<Block> getAutoBlocksBetweenMasts(SignalMast destination) { 676 if (!destList.containsKey(destination)) { 677 return new ArrayList<>(); 678 } 679 return destList.get(destination).getAutoBlocksBetweenMasts(); 680 } 681 682 /** 683 * {@inheritDoc } 684 */ 685 @Override 686 public List<Turnout> getTurnouts(SignalMast destination) { 687 if (!destList.containsKey(destination)) { 688 return new ArrayList<>(); 689 } 690 return destList.get(destination).getTurnouts(); 691 } 692 693 /** 694 * {@inheritDoc } 695 */ 696 @Override 697 public List<NamedBeanHandle<Turnout>> getNamedTurnouts(SignalMast destination) { 698 if (!destList.containsKey(destination)) { 699 return new ArrayList<>(); 700 } 701 return destList.get(destination).getNamedTurnouts(); 702 } 703 704 public void removeTurnout(Turnout turn, SignalMast destination) { 705 if (!destList.containsKey(destination)) { 706 return; 707 } 708 709 if (turn != null) { 710 destList.get(destination).removeTurnout(turn); 711 } 712 } 713 714 /** 715 * {@inheritDoc } 716 */ 717 @Override 718 public List<Turnout> getAutoTurnouts(SignalMast destination) { 719 if (!destList.containsKey(destination)) { 720 return new ArrayList<>(); 721 } 722 return destList.get(destination).getAutoTurnouts(); 723 } 724 725 /** 726 * {@inheritDoc } 727 */ 728 @Override 729 public List<Sensor> getSensors(SignalMast destination) { 730 if (!destList.containsKey(destination)) { 731 return new ArrayList<>(); 732 } 733 return destList.get(destination).getSensors(); 734 } 735 736 /** 737 * {@inheritDoc } 738 */ 739 @Override 740 public List<NamedBeanHandle<Sensor>> getNamedSensors(SignalMast destination) { 741 if (!destList.containsKey(destination)) { 742 return new ArrayList<>(); 743 } 744 return destList.get(destination).getNamedSensors(); 745 } 746 747 /** 748 * {@inheritDoc } 749 */ 750 @Override 751 public List<SignalMast> getSignalMasts(SignalMast destination) { 752 if (!destList.containsKey(destination)) { 753 return new ArrayList<>(); 754 } 755 return destList.get(destination).getSignalMasts(); 756 } 757 758 /** 759 * {@inheritDoc } 760 */ 761 @Override 762 public List<SignalMast> getAutoMasts(SignalMast destination) { 763 if (!destList.containsKey(destination)) { 764 return new ArrayList<>(); 765 } 766 return destList.get(destination).getAutoSignalMasts(); 767 } 768 769 /** 770 * {@inheritDoc } 771 */ 772 @Override 773 public void initialise() { 774 Enumeration<SignalMast> en = destList.keys(); 775 while (en.hasMoreElements()) { 776 destList.get(en.nextElement()).initialise(); 777 } 778 } 779 780 /** 781 * {@inheritDoc } 782 */ 783 @Override 784 public void initialise(SignalMast destination) { 785 if (disposing) { 786 return; 787 } 788 789 if (!destList.containsKey(destination)) { 790 return; 791 } 792 destList.get(destination).initialise(); 793 } 794 795 /** 796 * {@inheritDoc } 797 */ 798 @Override 799 public LinkedHashMap<Block, Integer> setupLayoutEditorTurnoutDetails(List<LayoutBlock> blks, SignalMast destination) { 800 if (disposing) { 801 return new LinkedHashMap<>(); 802 } 803 804 if (!destList.containsKey(destination)) { 805 return new LinkedHashMap<>(); 806 } 807 return destList.get(destination).setupLayoutEditorTurnoutDetails(blks); 808 } 809 810 /** 811 * {@inheritDoc } 812 */ 813 @Override 814 public void setupLayoutEditorDetails() { 815 if (disposing) { 816 return; 817 } 818 Enumeration<SignalMast> en = destList.keys(); 819 while (en.hasMoreElements()) { 820 try { 821 destList.get(en.nextElement()).setupLayoutEditorDetails(); 822 } catch (JmriException e) { 823 //Considered normal if no route is valid on a Layout Editor panel 824 } 825 } 826 } 827 828 /** 829 * Check if routes to the destination Signal Mast are clear. 830 * 831 * @return true if the path to the next signal is clear 832 */ 833 boolean checkStates() { 834 SignalMast oldActiveMast = destination; 835 if (destination != null) { 836 firePropertyChange(PROPERTY_STATE, oldActiveMast, null); 837 log.debug("Remove listener from destination"); 838 destination.removePropertyChangeListener(propertyDestinationMastListener); 839 if (destList.containsKey(destination)) { 840 destList.get(destination).clearTurnoutLock(); 841 } 842 } 843 844 Enumeration<SignalMast> en = destList.keys(); 845 log.debug("checkStates enumerates over {} mast(s)", destList.size()); 846 while (en.hasMoreElements()) { 847 SignalMast key = en.nextElement(); 848 log.debug(" Destination mast {}", key.getDisplayName()); 849 log.debug(" isEnabled: {}", (destList.get(key)).isEnabled()); 850 log.debug(" isActive: {}", destList.get(key).isActive()); 851 852 if ((destList.get(key)).isEnabled() && (destList.get(key).isActive())) { 853 destination = key; 854 log.debug(" Add listener to destination"); 855 destination.addPropertyChangeListener(propertyDestinationMastListener); 856 log.debug(" firePropertyChange: \"state\""); 857 firePropertyChange(PROPERTY_STATE, oldActiveMast, destination); 858 destList.get(key).lockTurnouts(); 859 return true; 860 } 861 } 862 return false; 863 } 864 865 /** 866 * {@inheritDoc } 867 */ 868 @Override 869 public boolean areBlocksIncluded(List<Block> blks) { 870 Enumeration<SignalMast> en = destList.keys(); 871 while (en.hasMoreElements()) { 872 SignalMast dm = en.nextElement(); 873 boolean included; 874 for (int i = 0; i < blks.size(); i++) { 875 included = destList.get(dm).isBlockIncluded(blks.get(i)); 876 if (included) { 877 return true; 878 } 879 included = destList.get(dm).isAutoBlockIncluded(blks.get(i)); 880 if (included) { 881 return true; 882 } 883 } 884 } 885 return false; 886 } 887 888 /** 889 * {@inheritDoc } 890 */ 891 @Override 892 public int getBlockState(Block block, SignalMast destination) { 893 if (!destList.containsKey(destination)) { 894 return -1; 895 } 896 return destList.get(destination).getBlockState(block); 897 } 898 899 /** 900 * {@inheritDoc } 901 */ 902 @Override 903 public boolean isBlockIncluded(Block block, SignalMast destination) { 904 if (!destList.containsKey(destination)) { 905 return false; 906 } 907 return destList.get(destination).isBlockIncluded(block); 908 } 909 910 /** 911 * {@inheritDoc } 912 */ 913 @Override 914 public boolean isTurnoutIncluded(Turnout turnout, SignalMast destination) { 915 if (!destList.containsKey(destination)) { 916 return false; 917 } 918 return destList.get(destination).isTurnoutIncluded(turnout); 919 } 920 921 /** 922 * {@inheritDoc } 923 */ 924 @Override 925 public boolean isSensorIncluded(Sensor sensor, SignalMast destination) { 926 if (!destList.containsKey(destination)) { 927 return false; 928 } 929 return destList.get(destination).isSensorIncluded(sensor); 930 } 931 932 /** 933 * {@inheritDoc } 934 */ 935 @Override 936 public boolean isSignalMastIncluded(SignalMast signal, SignalMast destination) { 937 if (!destList.containsKey(destination)) { 938 return false; 939 } 940 return destList.get(destination).isSignalMastIncluded(signal); 941 } 942 943 /** 944 * {@inheritDoc } 945 */ 946 @Override 947 public int getAutoBlockState(Block block, SignalMast destination) { 948 if (!destList.containsKey(destination)) { 949 return -1; 950 } 951 return destList.get(destination).getAutoBlockState(block); 952 } 953 954 /** 955 * {@inheritDoc } 956 */ 957 @Override 958 public int getSensorState(Sensor sensor, SignalMast destination) { 959 if (!destList.containsKey(destination)) { 960 return -1; 961 } 962 return destList.get(destination).getSensorState(sensor); 963 } 964 965 /** 966 * {@inheritDoc } 967 */ 968 @Override 969 public int getTurnoutState(Turnout turnout, SignalMast destination) { 970 if (!destList.containsKey(destination)) { 971 return -1; 972 } 973 return destList.get(destination).getTurnoutState(turnout); 974 } 975 976 /** 977 * {@inheritDoc } 978 */ 979 @Override 980 public int getAutoTurnoutState(Turnout turnout, SignalMast destination) { 981 if (!destList.containsKey(destination)) { 982 return -1; 983 } 984 return destList.get(destination).getAutoTurnoutState(turnout); 985 } 986 987 /** 988 * {@inheritDoc } 989 */ 990 @Override 991 public String getSignalMastState(SignalMast mast, SignalMast destination) { 992 if (!destList.containsKey(destination)) { 993 return null; 994 } 995 return destList.get(destination).getSignalMastState(mast); 996 } 997 998 /** 999 * {@inheritDoc } 1000 */ 1001 @Override 1002 public String getAutoSignalMastState(SignalMast mast, SignalMast destination) { 1003 if (!destList.containsKey(destination)) { 1004 return null; 1005 } 1006 return destList.get(destination).getAutoSignalMastState(mast); 1007 } 1008 1009 /** 1010 * {@inheritDoc } 1011 */ 1012 @Override 1013 public float getMaximumSpeed(SignalMast destination) { 1014 if (!destList.containsKey(destination)) { 1015 return -1; 1016 } 1017 return destList.get(destination).getMinimumSpeed(); 1018 } 1019 1020 volatile boolean inWait = false; 1021 1022 /** 1023 * Before going active or checking that we can go active, wait 500ms 1024 * for things to settle down to help prevent a race condition. 1025 */ 1026 synchronized void setSignalAppearance() { 1027 log.debug("setMastAppearance (Aspect) called for {}", source.getDisplayName()); 1028 if (inWait) { 1029 log.debug("setMastAppearance (Aspect) called with inWait set, returning"); 1030 return; 1031 } 1032 inWait = true; 1033 1034 // The next line forces a single initialization of InstanceManager.getDefault(SignalSpeedMap.class) 1035 // before launching parallel threads 1036 InstanceManager.getDefault(SignalSpeedMap.class); 1037 1038 // The next line forces a single initialization of InstanceManager.getDefault(SignalMastLogicManager.class) 1039 // before launching delay 1040 int tempDelay = InstanceManager.getDefault(SignalMastLogicManager.class).getSignalLogicDelay() / 2; 1041 log.debug("SignalMastLogicManager started (delay)"); 1042 ThreadingUtil.runOnLayoutDelayed( 1043 () -> { 1044 setMastAppearance(); 1045 inWait = false; 1046 }, 1047 tempDelay 1048 ); 1049 1050 } 1051 1052 /** 1053 * Evaluate the destination signal mast Aspect and set ours accordingly. 1054 */ 1055 void setMastAppearance() { 1056 log.debug("Set source Signal Mast Aspect"); 1057 if (getSourceMast().getHeld()) { 1058 log.debug("Signal is at a Held state so will set to the aspect defined for Held or Danger"); 1059 1060 String heldAspect = getSourceMast().getAppearanceMap().getSpecificAppearance(SignalAppearanceMap.HELD); 1061 if (heldAspect != null) { 1062 log.debug(" Setting to HELD value of {}", heldAspect); 1063 ThreadingUtil.runOnLayout(() -> { 1064 getSourceMast().setAspect(heldAspect); 1065 }); 1066 } else { 1067 String dangerAspect = getSourceMast().getAppearanceMap().getSpecificAppearance(SignalAppearanceMap.DANGER); 1068 log.debug(" Setting to DANGER value of {}", dangerAspect); 1069 ThreadingUtil.runOnLayout(() -> { 1070 getSourceMast().setAspect(dangerAspect); 1071 }); 1072 } 1073 return; 1074 } 1075 if (!checkStates()) { 1076 log.debug("Advanced routes not clear, set Stop aspect"); 1077 getSourceMast().setAspect(stopAspect); 1078 return; 1079 } 1080 String[] advancedAspect; 1081 if (destination.getHeld()) { 1082 if (destination.getAppearanceMap().getSpecificAppearance(SignalAppearanceMap.HELD) != null) { 1083 advancedAspect = getSourceMast().getAppearanceMap().getValidAspectsForAdvancedAspect(destination.getAppearanceMap().getSpecificAppearance(SignalAppearanceMap.HELD)); 1084 } else { 1085 advancedAspect = getSourceMast().getAppearanceMap().getValidAspectsForAdvancedAspect(destination.getAppearanceMap().getSpecificAppearance(SignalAppearanceMap.DANGER)); 1086 } 1087 } else { 1088 advancedAspect = getSourceMast().getAppearanceMap().getValidAspectsForAdvancedAspect(destination.getAspect()); 1089 } 1090 1091 log.debug("distant aspect is {}", destination.getAspect()); 1092 log.debug("advanced aspect is {}", advancedAspect != null ? advancedAspect : "<null>"); 1093 1094 if (advancedAspect != null) { 1095 String aspect = stopAspect; 1096 if (destList.get(destination).permissiveBlock) { 1097 if (!getSourceMast().isPermissiveSmlDisabled()) { 1098 //if a block is in a permissive state then we set the permissive appearance 1099 aspect = getSourceMast().getAppearanceMap().getSpecificAppearance(SignalAppearanceMap.PERMISSIVE); 1100 } 1101 } else { 1102 for (String advancedAspect1 : advancedAspect) { 1103 if (!getSourceMast().isAspectDisabled(advancedAspect1)) { 1104 aspect = advancedAspect1; 1105 break; 1106 } 1107 } 1108 List<Integer> divergAspects = new ArrayList<>(); 1109 List<Integer> nonDivergAspects = new ArrayList<>(); 1110 List<Integer> eitherAspects = new ArrayList<>(); 1111 if (advancedAspect.length > 1) { 1112 float maxSigSpeed = -1; 1113 float maxPathSpeed = destList.get(destination).getMinimumSpeed(); 1114 boolean divergRoute = destList.get(destination).turnoutThrown; 1115 1116 log.debug("Diverging route? {}", divergRoute); 1117 boolean divergFlagsAvailable = false; 1118 //We split the aspects into two lists, one with diverging flag set, the other without. 1119 for (int i = 0; i < advancedAspect.length; i++) { 1120 String div = null; 1121 if (!getSourceMast().isAspectDisabled(advancedAspect[i])) { 1122 div = (String) getSourceMast().getSignalSystem().getProperty(advancedAspect[i], "route"); 1123 } 1124 if (div != null) { 1125 if (div.equals("Diverging")) { 1126 log.debug("Aspect {} added as Diverging Route", advancedAspect[i]); 1127 divergAspects.add(i); 1128 divergFlagsAvailable = true; 1129 log.debug("Using Diverging Flag"); 1130 } else if (div.equals("Either")) { 1131 log.debug("Aspect {} added as both Diverging and Normal Route", advancedAspect[i]); 1132 nonDivergAspects.add(i); 1133 divergAspects.add(i); 1134 divergFlagsAvailable = true; 1135 eitherAspects.add(i); 1136 log.debug("Using Diverging Flag"); 1137 } else { 1138 log.debug("Aspect {} added as Normal Route", advancedAspect[i]); 1139 nonDivergAspects.add(i); 1140 log.debug("Aspect {} added as Normal Route", advancedAspect[i]); 1141 } 1142 } else { 1143 nonDivergAspects.add(i); 1144 log.debug("Aspect {} added as Normal Route", advancedAspect[i]); 1145 } 1146 } 1147 if ((eitherAspects.equals(divergAspects)) && (divergAspects.size() < nonDivergAspects.size())) { 1148 //There are no unique diverging aspects 1149 log.debug("'Either' aspects equals divergAspects and is less than non-diverging aspects"); 1150 divergFlagsAvailable = false; 1151 } 1152 log.debug("path max speed : {}", maxPathSpeed); 1153 for (int i = 0; i < advancedAspect.length; i++) { 1154 if (!getSourceMast().isAspectDisabled(advancedAspect[i])) { 1155 String strSpeed = (String) getSourceMast().getSignalSystem().getProperty(advancedAspect[i], "speed"); 1156 log.debug("Aspect Speed = {} for aspect {}", strSpeed, advancedAspect[i]); 1157 /* if the diverg flags available is set and the diverg aspect 1158 array contains the entry then we will check this aspect. 1159 1160 If the diverg flag has not been set then we will check. 1161 */ 1162 log.debug("advanced aspect {}",advancedAspect[i]); 1163 if ((divergRoute && (divergFlagsAvailable) && (divergAspects.contains(i))) || ((divergRoute && !divergFlagsAvailable) || (!divergRoute)) && (nonDivergAspects.contains(i))) { 1164 log.debug("In list"); 1165 if ((strSpeed != null) && (!strSpeed.isEmpty())) { 1166 float speed = 0.0f; 1167 try { 1168 speed = Float.parseFloat(strSpeed); 1169 } catch (NumberFormatException nx) { 1170 // not a number, perhaps a name? 1171 try { 1172 speed = InstanceManager.getDefault(SignalSpeedMap.class).getSpeed(strSpeed); 1173 } catch (IllegalArgumentException ex) { 1174 // not a name either 1175 log.warn("Using speed = 0.0 because could not understand \"{}\"", strSpeed); 1176 } 1177 } 1178 //Integer state = Integer.parseInt(strSpeed); 1179 /* This pics out either the highest speed signal if there 1180 * is no block speed specified or the highest speed signal 1181 * that is under the minimum block speed. 1182 */ 1183 log.debug("{} signal state speed {} maxSigSpeed {} maxPathSpeed {}", destination.getDisplayName(), speed, maxSigSpeed, maxPathSpeed); 1184 if (maxPathSpeed == 0) { 1185 if (maxSigSpeed == -1) { 1186 log.debug("min speed on this route is equal to 0 so will set this as our max speed"); 1187 maxSigSpeed = speed; 1188 aspect = advancedAspect[i]; 1189 log.debug("Aspect to set is {}", aspect); 1190 } else if (speed > maxSigSpeed) { 1191 log.debug("new speed is faster than old will use this"); 1192 maxSigSpeed = speed; 1193 aspect = advancedAspect[i]; 1194 log.debug("Aspect to set is {}", aspect); 1195 } 1196 } else if ((speed > maxSigSpeed) && (maxSigSpeed < maxPathSpeed) && (speed <= maxPathSpeed)) { 1197 //Only set the speed to the lowest if the max speed is greater than the path speed 1198 //and the new speed is less than the last max speed 1199 log.debug("our minimum speed on this route is less than our state speed, we will set this as our max speed"); 1200 maxSigSpeed = speed; 1201 aspect = advancedAspect[i]; 1202 log.debug("Aspect to set is {}", aspect); 1203 } else if ((maxSigSpeed > maxPathSpeed) && (speed < maxSigSpeed)) { 1204 log.debug("our max signal speed is greater than our path speed on this route, our speed is less that the maxSigSpeed"); 1205 maxSigSpeed = speed; 1206 aspect = advancedAspect[i]; 1207 log.debug("Aspect to set is {}", aspect); 1208 1209 } else if (maxSigSpeed == -1) { 1210 log.debug("maxSigSpeed returned as -1"); 1211 maxSigSpeed = speed; 1212 aspect = advancedAspect[i]; 1213 log.debug("Aspect to set is {}", aspect); 1214 } 1215 } 1216 } 1217 } else { 1218 log.debug("Aspect has been disabled {}", advancedAspect[i]); 1219 } 1220 } 1221 } 1222 } 1223 if ((aspect != null) && (!aspect.isEmpty())) { 1224 log.debug("setMastAppearance setting aspect \"{}\"", aspect); 1225 String aspectSet = aspect; // for lambda 1226 try { 1227 ThreadingUtil.runOnLayout(() -> { 1228 getSourceMast().setAspect(aspectSet); 1229 }); 1230 } catch (Exception ex) { 1231 log.error("Exception while setting Signal Logic", ex); 1232 } 1233 return; 1234 } 1235 } 1236 log.debug("Aspect returned is not valid, setting stop"); 1237 ThreadingUtil.runOnLayout(() -> { 1238 getSourceMast().setAspect(stopAspect); 1239 }); 1240 } 1241 1242 /** 1243 * {@inheritDoc } 1244 */ 1245 @Override 1246 public void setConflictingLogic(SignalMast sm, LevelXing lx) { 1247 if (sm == null) { 1248 return; 1249 } 1250 log.debug("setConflicting logic mast {}", sm.getDisplayName()); 1251 if (sm == source) { 1252 log.debug("source is us so exit"); 1253 return; 1254 } 1255 Enumeration<SignalMast> en = destList.keys(); 1256 while (en.hasMoreElements()) { 1257 SignalMast dm = en.nextElement(); 1258 if (destList.get(dm).isBlockIncluded(lx.getLayoutBlockAC())) { 1259 destList.get(dm).addAutoSignalMast(sm); 1260 } else if (destList.get(dm).isBlockIncluded(lx.getLayoutBlockBD())) { 1261 destList.get(dm).addAutoSignalMast(sm); 1262 } else if (destList.get(dm).isAutoBlockIncluded(lx.getLayoutBlockAC())) { 1263 destList.get(dm).addAutoSignalMast(sm); 1264 } else if (destList.get(dm).isAutoBlockIncluded(lx.getLayoutBlockBD())) { 1265 destList.get(dm).addAutoSignalMast(sm); 1266 } else { 1267 log.debug("Block not found"); 1268 } 1269 } 1270 } 1271 1272 /** 1273 * {@inheritDoc } 1274 */ 1275 @Override 1276 public void removeConflictingLogic(SignalMast sm, LevelXing lx) { 1277 if (sm == source) { 1278 return; 1279 } 1280 Enumeration<SignalMast> en = destList.keys(); 1281 while (en.hasMoreElements()) { 1282 SignalMast dm = en.nextElement(); 1283 if (destList.get(dm).isBlockIncluded(lx.getLayoutBlockAC())) { 1284 destList.get(dm).removeAutoSignalMast(sm); 1285 } else if (destList.get(dm).isBlockIncluded(lx.getLayoutBlockBD())) { 1286 destList.get(dm).removeAutoSignalMast(sm); 1287 } 1288 } 1289 } 1290 1291 /** 1292 * Class to store SML properties for a destination mast paired with this 1293 * source mast. 1294 */ 1295 private class DestinationMast { 1296 1297 LayoutBlock destinationBlock = null; 1298 LayoutBlock protectingBlock = null; //this is the block that the source signal is protecting 1299 1300 List<NamedBeanSetting> userSetTurnouts = new ArrayList<>(0); 1301 Hashtable<Turnout, Integer> autoTurnouts = new Hashtable<>(0); 1302 //Hashtable<Turnout, Boolean> turnoutThroats = new Hashtable<Turnout, Boolean>(0); 1303 //Hashtable<Turnout, Boolean> autoTurnoutThroats = new Hashtable<Turnout, Boolean>(0); 1304 1305 List<NamedBeanSetting> userSetMasts = new ArrayList<>(0); 1306 Hashtable<SignalMast, String> autoMasts = new Hashtable<>(0); 1307 List<NamedBeanSetting> userSetSensors = new ArrayList<>(0); 1308 List<NamedBeanSetting> userSetBlocks = new ArrayList<>(0); 1309 boolean turnoutThrown = false; 1310 boolean permissiveBlock = false; 1311 boolean disposed = false; 1312 1313 List<LevelXing> blockInXings = new ArrayList<>(); 1314 1315 //autoBlocks are for those automatically generated by the system. 1316 LinkedHashMap<Block, Integer> autoBlocks = new LinkedHashMap<>(0); 1317 1318 List<Block> xingAutoBlocks = new ArrayList<>(0); 1319 List<Block> dblCrossoverAutoBlocks = new ArrayList<>(0); 1320 SignalMast destinationSignalMast; 1321 boolean active = false; 1322 boolean destMastInit = false; 1323 1324 float minimumBlockSpeed = 0.0f; 1325 1326 boolean useLayoutEditor = false; 1327 boolean useLayoutEditorTurnouts = false; 1328 boolean useLayoutEditorBlocks = false; 1329 boolean lockTurnouts = false; 1330 1331 NamedBeanHandle<Section> associatedSection = null; 1332 1333 DestinationMast(SignalMast destination) { 1334 this.destinationSignalMast = destination; 1335 if (destination.getAspect() == null) { 1336 try { 1337 destination.setAspect(destination.getAppearanceMap().getSpecificAppearance(SignalAppearanceMap.DANGER)); 1338 } catch (Exception ex) { 1339 log.error("Error while creating Signal Logic", ex); 1340 } 1341 } 1342 } 1343 1344 void updateDestinationMast(SignalMast newMast) { 1345 destinationSignalMast = newMast; 1346 if (destinationSignalMast.getAspect() == null) { 1347 try { 1348 destinationSignalMast.setAspect(destinationSignalMast.getAppearanceMap().getSpecificAppearance(SignalAppearanceMap.DANGER)); 1349 } catch (Exception ex) { 1350 log.error("Error while creating Signal Logic", ex); 1351 } 1352 } 1353 } 1354 1355 LayoutBlock getProtectingBlock() { 1356 return protectingBlock; 1357 } 1358 1359 String getDisplayName() { 1360 return destinationSignalMast.getDisplayName(); 1361 } 1362 1363 String comment; 1364 1365 String getComment() { 1366 return comment; 1367 } 1368 1369 void setComment(String comment) { 1370 String old = this.comment; 1371 this.comment = comment; 1372 firePropertyChange(PROPERTY_COMMENT, old, comment); 1373 } 1374 1375 boolean isActive() { 1376 if (disposed) { 1377 log.error("checkState called even though this has been disposed of"); 1378 return false; 1379 } 1380 return active; 1381 } 1382 1383 float getMinimumSpeed() { 1384 return minimumBlockSpeed; 1385 } 1386 1387 boolean enable = true; 1388 1389 void setEnabled() { 1390 enable = true; 1391 firePropertyChange(PROPERTY_ENABLED, false, this.destinationSignalMast); 1392 } 1393 1394 void setDisabled() { 1395 enable = false; 1396 firePropertyChange(PROPERTY_ENABLED, true, this.destinationSignalMast); 1397 } 1398 1399 boolean isEnabled() { 1400 return enable; 1401 } 1402 1403 int store = STOREALL; 1404 1405 void setStore(int store) { 1406 this.store = store; 1407 } 1408 1409 int getStoreState() { 1410 return store; 1411 } 1412 1413 void setAssociatedSection(Section section) { 1414 if (section != null && (!useLayoutEditor || !useLayoutEditorBlocks)) { 1415 log.warn("This Logic {} to {} is not using the Layout Editor or its Blocks, the associated Section will not be populated correctly", source.getDisplayName(), destinationSignalMast.getDisplayName()); 1416 } 1417 if (section == null) { 1418 associatedSection = null; 1419 return; 1420 } 1421 associatedSection = InstanceManager.getDefault(NamedBeanHandleManager.class).getNamedBeanHandle(section.getDisplayName(), section); 1422 if (!autoBlocks.isEmpty()) { // associatedSection is guaranteed to exist 1423 createSectionDetails(); 1424 } 1425 } 1426 1427 Section getAssociatedSection() { 1428 if (associatedSection != null) { 1429 return associatedSection.getBean(); 1430 } 1431 return null; 1432 } 1433 1434 void createSectionDetails() { 1435 getAssociatedSection().removeAllBlocksFromSection(); 1436 getAutoBlocksBetweenMasts().forEach(key -> { 1437 getAssociatedSection().addBlock(key); 1438 }); 1439 String dir = Path.decodeDirection(getFacingBlock().getNeighbourDirection(getProtectingBlock())); 1440 EntryPoint ep = new EntryPoint(getProtectingBlock().getBlock(), getFacingBlock().getBlock(), dir); 1441 ep.setTypeForward(); 1442 getAssociatedSection().addToForwardList(ep); 1443 1444 LayoutBlock proDestLBlock = InstanceManager.getDefault(LayoutBlockManager.class).getProtectedBlockByNamedBean(destinationSignalMast, destinationBlock.getMaxConnectedPanel()); 1445 if (proDestLBlock != null) { 1446 log.debug("Add protecting Block {}", proDestLBlock.getDisplayName()); 1447 dir = Path.decodeDirection(proDestLBlock.getNeighbourDirection(destinationBlock)); 1448 ep = new EntryPoint(destinationBlock.getBlock(), proDestLBlock.getBlock(), dir); 1449 ep.setTypeReverse(); 1450 getAssociatedSection().addToReverseList(ep); 1451 } else { 1452 log.debug(" ### Protecting Block not found ### "); 1453 } 1454 } 1455 1456 boolean isTurnoutLockAllowed() { 1457 return lockTurnouts; 1458 } 1459 1460 void allowTurnoutLock(boolean lock) { 1461 if (lockTurnouts == lock) { 1462 return; 1463 } 1464 if (!lock) { 1465 clearTurnoutLock(); 1466 } 1467 lockTurnouts = lock; 1468 } 1469 1470 void setTurnouts(Hashtable<NamedBeanHandle<Turnout>, Integer> turnouts) { 1471 if (this.userSetTurnouts != null) { 1472 userSetTurnouts.forEach(nbh -> 1473 nbh.getBean().removePropertyChangeListener(propertyTurnoutListener)); 1474 } 1475 destMastInit = false; 1476 if (turnouts == null) { 1477 userSetTurnouts = new ArrayList<>(0); 1478 } else { 1479 userSetTurnouts = new ArrayList<>(); 1480 Enumeration<NamedBeanHandle<Turnout>> e = turnouts.keys(); 1481 while (e.hasMoreElements()) { 1482 NamedBeanHandle<Turnout> nbh = e.nextElement(); 1483 NamedBeanSetting nbs = new NamedBeanSetting(nbh, turnouts.get(nbh)); 1484 userSetTurnouts.add(nbs); 1485 } 1486 } 1487 firePropertyChange(PROPERTY_TURNOUTS, null, this.destinationSignalMast); 1488 } 1489 1490 void setAutoTurnouts(Hashtable<Turnout, Integer> turnouts) { 1491 log.debug("{} called setAutoTurnouts with {}", destinationSignalMast.getDisplayName(), 1492 (turnouts != null ? "" + turnouts.size() + " turnouts in hash table" : "null hash table reference")); 1493 if (this.autoTurnouts != null) { 1494 Enumeration<Turnout> keys = this.autoTurnouts.keys(); 1495 while (keys.hasMoreElements()) { 1496 Turnout key = keys.nextElement(); 1497 key.removePropertyChangeListener(propertyTurnoutListener); 1498 } 1499 //minimumBlockSpeed = 0; 1500 } 1501 destMastInit = false; 1502 if (turnouts == null) { 1503 this.autoTurnouts = new Hashtable<>(0); 1504 } else { 1505 this.autoTurnouts = new Hashtable<>(turnouts); 1506 } 1507 firePropertyChange(PROPERTY_AUTO_TURNOUTS, null, this.destinationSignalMast); 1508 } 1509 1510 void setBlocks(Hashtable<Block, Integer> blocks) { 1511 log.debug("{} Set blocks called", destinationSignalMast.getDisplayName()); 1512 if (this.userSetBlocks != null) { 1513 userSetBlocks.forEach( nbh -> 1514 nbh.getBean().removePropertyChangeListener(propertyBlockListener)); 1515 } 1516 destMastInit = false; 1517 1518 userSetBlocks = new ArrayList<>(0); 1519 if (blocks != null) { 1520 userSetBlocks = new ArrayList<>(); 1521 Enumeration<Block> e = blocks.keys(); 1522 while (e.hasMoreElements()) { 1523 Block blk = e.nextElement(); 1524 NamedBeanHandle<?> nbh = InstanceManager.getDefault(NamedBeanHandleManager.class).getNamedBeanHandle(blk.getDisplayName(), blk); 1525 NamedBeanSetting nbs = new NamedBeanSetting(nbh, blocks.get(blk)); 1526 userSetBlocks.add(nbs); 1527 } 1528 } 1529 firePropertyChange(PROPERTY_BLOCKS, null, this.destinationSignalMast); 1530 } 1531 1532 public void setAutoBlocks(LinkedHashMap<Block, Integer> blocks) { 1533 if (log.isDebugEnabled()) { 1534 log.debug("{} called setAutoBlocks with {}", destinationSignalMast.getDisplayName(), 1535 (blocks != null ? "" + blocks.size() + " blocks in hash table" : "null hash table reference")); 1536 } 1537 if (this.autoBlocks != null) { 1538 autoBlocks.keySet().forEach( key -> 1539 key.removePropertyChangeListener(propertyBlockListener)); 1540 } 1541 destMastInit = false; 1542 if (blocks == null) { 1543 this.autoBlocks = new LinkedHashMap<>(0); 1544 1545 } else { 1546 this.autoBlocks = new LinkedHashMap<>(blocks); 1547 //We shall remove the facing block in the list. 1548 if (facingBlock != null && autoBlocks.containsKey(facingBlock.getBlock())) { 1549 autoBlocks.remove(facingBlock.getBlock()); 1550 } 1551 if (getAssociatedSection() != null) { 1552 createSectionDetails(); 1553 } 1554 } 1555 firePropertyChange(PROPERTY_AUTO_BLOCKS, null, this.destinationSignalMast); 1556 } 1557 1558 void setMasts(Hashtable<SignalMast, String> masts) { 1559 if (this.userSetMasts != null) { 1560 userSetMasts.forEach( nbh -> 1561 nbh.getBean().removePropertyChangeListener(propertySignalMastListener)); 1562 } 1563 1564 destMastInit = false; 1565 1566 if (masts == null) { 1567 userSetMasts = new ArrayList<>(0); 1568 } else { 1569 userSetMasts = new ArrayList<>(); 1570 Enumeration<SignalMast> e = masts.keys(); 1571 while (e.hasMoreElements()) { 1572 SignalMast mast = e.nextElement(); 1573 NamedBeanHandle<?> nbh = InstanceManager.getDefault(NamedBeanHandleManager.class) 1574 .getNamedBeanHandle(mast.getDisplayName(), mast); 1575 NamedBeanSetting nbs = new NamedBeanSetting(nbh, masts.get(mast)); 1576 userSetMasts.add(nbs); 1577 } 1578 } 1579 firePropertyChange(PROPERTY_MASTS, null, this.destinationSignalMast); 1580 } 1581 1582 /** 1583 * 1584 * @param newAutoMasts Hashtable of signal masts and set to Aspects 1585 * @param overwrite When true, replace an existing autoMasts list in 1586 * the SML 1587 */ 1588 void setAutoMasts(Hashtable<SignalMast, String> newAutoMasts, boolean overwrite) { 1589 log.debug("{} setAutoMast Called", destinationSignalMast.getDisplayName()); 1590 if (this.autoMasts != null) { 1591 Enumeration<SignalMast> keys = this.autoMasts.keys(); 1592 while (keys.hasMoreElements()) { 1593 SignalMast key = keys.nextElement(); 1594 key.removePropertyChangeListener(propertySignalMastListener); 1595 } 1596 //minimumBlockSpeed = 0; 1597 } 1598 destMastInit = false; 1599 if (overwrite) { 1600 if (newAutoMasts == null) { 1601 this.autoMasts = new Hashtable<>(0); 1602 } else { 1603 this.autoMasts = new Hashtable<>(newAutoMasts); 1604 } 1605 } else { 1606 if (newAutoMasts == null) { 1607 this.autoMasts = new Hashtable<>(0); 1608 } else { 1609 Enumeration<SignalMast> keys = newAutoMasts.keys(); 1610 while (keys.hasMoreElements()) { 1611 SignalMast key = keys.nextElement(); 1612 this.autoMasts.put(key, newAutoMasts.get(key)); 1613 } 1614 } 1615 } 1616 //kick off the process to add back in signal masts at crossings. 1617 for (int i = 0; i < blockInXings.size(); i++) { 1618 blockInXings.get(i).addSignalMastLogic(source); 1619 } 1620 1621 firePropertyChange(PROPERTY_AUTO_MASTS, null, this.destinationSignalMast); 1622 } 1623 1624 void setSensors(Hashtable<NamedBeanHandle<Sensor>, Integer> sensors) { 1625 if (this.userSetSensors != null) { 1626 userSetSensors.forEach(nbh -> 1627 nbh.getBean().removePropertyChangeListener(propertySensorListener)); 1628 } 1629 destMastInit = false; 1630 1631 if (sensors == null) { 1632 userSetSensors = new ArrayList<>(0); 1633 } else { 1634 userSetSensors = new ArrayList<>(); 1635 Enumeration<NamedBeanHandle<Sensor>> e = sensors.keys(); 1636 while (e.hasMoreElements()) { 1637 NamedBeanHandle<Sensor> nbh = e.nextElement(); 1638 NamedBeanSetting nbs = new NamedBeanSetting(nbh, sensors.get(nbh)); 1639 userSetSensors.add(nbs); 1640 } 1641 } 1642 firePropertyChange(PROPERTY_SENSORS, null, this.destinationSignalMast); 1643 } 1644 1645 void addSensor(NamedBeanHandle<Sensor> sen, int state) { 1646 for (NamedBeanSetting nbh : userSetSensors) { 1647 if (nbh.getBean().equals(sen.getBean())) { 1648 return; 1649 } 1650 } 1651 sen.getBean().addPropertyChangeListener(propertySensorListener); 1652 NamedBeanSetting nbs = new NamedBeanSetting(sen, state); 1653 userSetSensors.add(nbs); 1654 firePropertyChange(PROPERTY_SENSORS, null, this.destinationSignalMast); 1655 } 1656 1657// not used now, preserved for later use 1658// void removeSensor(NamedBeanHandle<Sensor> sen) { 1659// for (NamedBeanSetting nbh : userSetSensors) { 1660// if (nbh.getBean().equals(sen.getBean())) { 1661// sen.getBean().removePropertyChangeListener(propertySensorListener); 1662// userSetSensors.remove(nbh); 1663// firePropertyChange("sensors", null, this.destination); 1664// return; 1665// } 1666// } 1667// } 1668 1669 void removeSensor(Sensor sen) { 1670 for (NamedBeanSetting nbh : userSetSensors) { 1671 if (nbh.getBean().equals(sen)) { 1672 sen.removePropertyChangeListener(propertySensorListener); 1673 userSetSensors.remove(nbh); 1674 firePropertyChange(PROPERTY_SENSORS, null, this.destinationSignalMast); 1675 return; 1676 } 1677 } 1678 } 1679 1680 List<Block> getBlocks() { 1681 List<Block> out = new ArrayList<>(); 1682 userSetBlocks.forEach( nbh -> out.add((Block) nbh.getBean())); 1683 return out; 1684 } 1685 1686 List<Block> getAutoBlocks() { 1687 List<Block> out = new ArrayList<>(); 1688 Set<Block> blockKeys = autoBlocks.keySet(); 1689 blockKeys.forEach(key -> out.add(key)); 1690 return out; 1691 } 1692 1693 List<Block> getAutoBlocksBetweenMasts() { 1694 if (destList.get(destinationSignalMast).xingAutoBlocks.isEmpty() 1695 && destList.get(destinationSignalMast).dblCrossoverAutoBlocks.isEmpty()) { 1696 return getAutoBlocks(); 1697 } 1698 List<Block> returnList = getAutoBlocks(); 1699 for (Block blk : getAutoBlocks()) { 1700 if (xingAutoBlocks.contains(blk)) { 1701 returnList.remove(blk); 1702 } 1703 if (dblCrossoverAutoBlocks.contains(blk)) { 1704 returnList.remove(blk); 1705 } 1706 } 1707 1708 return returnList; 1709 } 1710 1711 List<Turnout> getTurnouts() { 1712 List<Turnout> out = new ArrayList<>(); 1713 userSetTurnouts.forEach( nbh -> out.add((Turnout) nbh.getBean())); 1714 return out; 1715 } 1716 1717 void removeTurnout(Turnout turn) { 1718 Iterator<NamedBeanSetting> nbh = userSetTurnouts.iterator(); 1719 while (nbh.hasNext()) { 1720 NamedBeanSetting i = nbh.next(); 1721 if (i.getBean().equals(turn)) { 1722 turn.removePropertyChangeListener(propertyTurnoutListener); 1723 nbh.remove(); 1724 firePropertyChange(PROPERTY_TURNOUTS, null, this.destinationSignalMast); 1725 } 1726 } 1727 } 1728 1729 @SuppressWarnings("unchecked") // (NamedBeanHandle<Turnout>) nbh.getNamedBean() is unchecked cast 1730 List<NamedBeanHandle<Turnout>> getNamedTurnouts() { 1731 List<NamedBeanHandle<Turnout>> out = new ArrayList<>(); 1732 userSetTurnouts.forEach(nbh -> 1733 out.add((NamedBeanHandle<Turnout>) nbh.getNamedBean())); 1734 return out; 1735 } 1736 1737 List<Turnout> getAutoTurnouts() { 1738 List<Turnout> out = new ArrayList<>(); 1739 Enumeration<Turnout> en = autoTurnouts.keys(); 1740 while (en.hasMoreElements()) { 1741 out.add(en.nextElement()); 1742 } 1743 return out; 1744 } 1745 1746 List<SignalMast> getSignalMasts() { 1747 List<SignalMast> out = new ArrayList<>(); 1748 userSetMasts.forEach( nbh -> out.add((SignalMast) nbh.getBean())); 1749 return out; 1750 } 1751 1752 List<SignalMast> getAutoSignalMasts() { 1753 List<SignalMast> out = new ArrayList<>(); 1754 Enumeration<SignalMast> en = autoMasts.keys(); 1755 while (en.hasMoreElements()) { 1756 out.add(en.nextElement()); 1757 } 1758 return out; 1759 } 1760 1761 List<Sensor> getSensors() { 1762 List<Sensor> out = new ArrayList<>(); 1763 userSetSensors.forEach( nbh -> out.add((Sensor) nbh.getBean())); 1764 return out; 1765 } 1766 1767 @SuppressWarnings("unchecked") // (NamedBeanHandle<Sensor>) nbh.getNamedBean() is unchecked cast 1768 List<NamedBeanHandle<Sensor>> getNamedSensors() { 1769 List<NamedBeanHandle<Sensor>> out = new ArrayList<>(); 1770 userSetSensors.forEach( nbh -> out.add((NamedBeanHandle<Sensor>) nbh.getNamedBean())); 1771 return out; 1772 } 1773 1774 boolean isBlockIncluded(Block block) { 1775 return userSetBlocks.stream().anyMatch(nbh -> (nbh.getBean().equals(block))); 1776 } 1777 1778 boolean isAutoBlockIncluded(LayoutBlock block) { 1779 if (block != null) { 1780 return autoBlocks.containsKey(block.getBlock()); 1781 } 1782 return false; 1783 } 1784 1785 boolean isAutoBlockIncluded(Block block) { 1786 return autoBlocks.containsKey(block); 1787 } 1788 1789 boolean isBlockIncluded(LayoutBlock block) { 1790 return userSetBlocks.stream().anyMatch(nbh -> (nbh.getBean().equals(block.getBlock()))); 1791 } 1792 1793 boolean isTurnoutIncluded(Turnout turnout) { 1794 return userSetTurnouts.stream().anyMatch(nbh -> (nbh.getBean().equals(turnout))); 1795 } 1796 1797 boolean isSensorIncluded(Sensor sensor) { 1798 return userSetSensors.stream().anyMatch(nbh -> (nbh.getBean().equals(sensor))); 1799 } 1800 1801 boolean isSignalMastIncluded(SignalMast signal) { 1802 return userSetMasts.stream().anyMatch(nbh -> (nbh.getBean().equals(signal))); 1803 } 1804 1805 int getAutoBlockState(Block block) { 1806 if (autoBlocks == null) { 1807 return -1; 1808 } 1809 return autoBlocks.get(block); 1810 } 1811 1812 int getBlockState(Block block) { 1813 if (userSetBlocks == null) { 1814 return -1; 1815 } 1816 for (NamedBeanSetting nbh : userSetBlocks) { 1817 if (nbh.getBean().equals(block)) { 1818 return nbh.getSetting(); 1819 } 1820 } 1821 return -1; 1822 } 1823 1824 int getSensorState(Sensor sensor) { 1825 if (userSetSensors == null) { 1826 return -1; 1827 } 1828 for (NamedBeanSetting nbh : userSetSensors) { 1829 if (nbh.getBean().equals(sensor)) { 1830 return nbh.getSetting(); 1831 } 1832 } 1833 return -1; 1834 } 1835 1836 int getTurnoutState(Turnout turnout) { 1837 if (userSetTurnouts == null) { 1838 return -1; 1839 } 1840 for (NamedBeanSetting nbh : userSetTurnouts) { 1841 if (nbh.getBean().equals(turnout)) { 1842 return nbh.getSetting(); 1843 } 1844 } 1845 return -1; 1846 } 1847 1848 int getAutoTurnoutState(Turnout turnout) { 1849 if (autoTurnouts == null) { 1850 return -1; 1851 } 1852 if (autoTurnouts.containsKey(turnout)) { 1853 return autoTurnouts.get(turnout); 1854 } 1855 return -1; 1856 } 1857 1858 String getSignalMastState(SignalMast mast) { 1859 if (userSetMasts == null) { 1860 return null; 1861 } 1862 for (NamedBeanSetting nbh : userSetMasts) { 1863 if (nbh.getBean().equals(mast)) { 1864 return nbh.getStringSetting(); 1865 } 1866 } 1867 return null; 1868 } 1869 1870 String getAutoSignalMastState(SignalMast mast) { 1871 if (autoMasts == null) { 1872 return null; 1873 } 1874 return autoMasts.get(mast); 1875 } 1876 1877 // the following 2 methods are not supplied in the implementation 1878 boolean inWait = false; 1879 1880 /* 1881 * Before going active or checking that we can go active, wait 1882 * for things to settle down to help prevent a race condition. 1883 */ 1884 void checkState() { 1885 if (disposed) { 1886 log.error("checkState called even though this has been disposed of {}", 1887 getSourceMast().getDisplayName()); 1888 return; 1889 } 1890 1891 if (!enable) { 1892 return; 1893 } 1894 if (inWait) { 1895 return; 1896 } 1897 1898 log.debug("check Signal Dest State called"); 1899 inWait = true; 1900 1901 // The next line forces a single initialization of InstanceManager.getDefault(SignalMastLogicManager.class) 1902 // before launching parallel threads 1903 int tempDelay = InstanceManager.getDefault(SignalMastLogicManager.class).getSignalLogicDelay(); 1904 1905 ThreadingUtil.runOnLayoutDelayed( 1906 () -> { 1907 checkStateDetails(); 1908 inWait = false; 1909 }, tempDelay 1910 ); 1911 } 1912 1913 /** 1914 * Check the details of this source-destination signal mast logic pair. 1915 * Steps through every sensor, turnout etc. before setting the SML 1916 * Aspect on the source mast via { 1917 * 1918 * @see #setSignalAppearance } and { 1919 * @see #setMastAppearance } 1920 */ 1921 private void checkStateDetails() { 1922 turnoutThrown = false; 1923 permissiveBlock = false; 1924 if (disposed) { 1925 log.error("checkStateDetails called even though this has been disposed of {} {}", 1926 getSourceMast().getDisplayName(), destinationSignalMast.getDisplayName()); 1927 return; 1928 } 1929 if (!enable) { 1930 return; 1931 } 1932 log.debug("From {} to {} internal check state", getSourceMast().getDisplayName(), 1933 destinationSignalMast.getDisplayName()); 1934 active = false; 1935 if ((useLayoutEditor) && (autoTurnouts.isEmpty()) && (autoBlocks.isEmpty())) { 1936 return; 1937 } 1938 boolean state = true; 1939 Enumeration<Turnout> keys = autoTurnouts.keys(); 1940 while (keys.hasMoreElements()) { 1941 Turnout key = keys.nextElement(); 1942 if (key.getKnownState() != autoTurnouts.get(key)) { 1943 if (key.getState() != autoTurnouts.get(key)) { 1944 if (isTurnoutIncluded(key)) { 1945 if (key.getState() != getTurnoutState(key)) { 1946 state = false; 1947 } else if (key.getState() == Turnout.THROWN) { 1948 turnoutThrown = true; 1949 } 1950 } else { 1951 state = false; 1952 } 1953 } 1954 } else if (key.getState() == Turnout.THROWN) { 1955 turnoutThrown = true; 1956 } 1957 } 1958 1959 for (NamedBeanSetting nbh : userSetTurnouts) { 1960 Turnout key = (Turnout) nbh.getBean(); 1961 if (key.getKnownState() != nbh.getSetting()) { 1962 state = false; 1963 } else if (key.getState() == Turnout.THROWN) { 1964 turnoutThrown = true; 1965 } 1966 } 1967 1968 Enumeration<SignalMast> mastKeys = autoMasts.keys(); 1969 while (mastKeys.hasMoreElements()) { 1970 SignalMast key = mastKeys.nextElement(); 1971 String aspect = key.getAspect(); 1972 log.debug("key {} {} {}", key.getDisplayName(), aspect, autoMasts.get(key)); 1973 if ((aspect != null) && (!aspect.equals(autoMasts.get(key)))) { 1974 if (isSignalMastIncluded(key)) { 1975 //Basically if we have a blank aspect, we don't care about the state of the signalmast 1976 if (!getSignalMastState(key).isEmpty()) { 1977 if (!aspect.equals(getSignalMastState(key))) { 1978 state = false; 1979 } 1980 } 1981 } else { 1982 state = false; 1983 } 1984 } 1985 } 1986 for (NamedBeanSetting nbh : userSetMasts) { 1987 SignalMast key = (SignalMast) nbh.getBean(); 1988 String aspect = key.getAspect(); 1989 if ((aspect == null) || (!aspect.equals(nbh.getStringSetting()))) { 1990 state = false; 1991 } 1992 } 1993 1994 for (NamedBeanSetting nbh : userSetSensors) { 1995 Sensor key = (Sensor) nbh.getBean(); 1996 if (key.getKnownState() != nbh.getSetting()) { 1997 state = false; 1998 } 1999 } 2000 2001 for (Map.Entry<Block, Integer> entry : this.autoBlocks.entrySet()) { 2002 log.debug(" entry {} {} {}", entry.getKey().getDisplayName(), 2003 entry.getKey().getState(), entry.getValue()); 2004 if (entry.getKey().getState() != autoBlocks.get(entry.getKey())) { 2005 if (isBlockIncluded(entry.getKey())) { 2006 if (getBlockState(entry.getKey()) != 0x03) { 2007 if (entry.getKey().getState() != getBlockState(entry.getKey())) { 2008 if (entry.getKey().getState() == Block.OCCUPIED && entry.getKey().getPermissiveWorking()) { 2009 permissiveBlock = true; 2010 } else { 2011 state = false; 2012 } 2013 } 2014 } 2015 } else { 2016 if (entry.getKey().getState() == Block.OCCUPIED && entry.getKey().getPermissiveWorking()) { 2017 permissiveBlock = true; 2018 } else if (entry.getKey().getState() == Block.UNDETECTED) { 2019 log.debug("Block {} is UNDETECTED so treat as unoccupied", entry.getKey().getDisplayName()); 2020 } else { 2021 state = false; 2022 } 2023 } 2024 } 2025 } 2026 2027 for (NamedBeanSetting nbh : userSetBlocks) { 2028 Block key = (Block) nbh.getBean(); 2029 if (nbh.getSetting() != 0x03) { 2030 if (key.getState() != nbh.getSetting()) { 2031 if (key.getState() == Block.OCCUPIED && key.getPermissiveWorking()) { 2032 permissiveBlock = true; 2033 } else { 2034 state = false; 2035 } 2036 } 2037 } 2038 } 2039 if (permissiveBlock 2040 /*If a block has been found to be permissive, but the source signalmast 2041 does not support a call-on/permissive aspect then the route can not be set*/ 2042 && getSourceMast().getAppearanceMap().getSpecificAppearance(SignalAppearanceMap.PERMISSIVE) == null) { 2043 state = false; 2044 } 2045 2046 /*This check is purely for use with the dispatcher, it will check to see if any of the blocks are set to "useExtraColor" 2047 which is a means to determine if the block is in a section that is occupied and it not ours thus we can set the signal to danger.*/ 2048 if (state && getAssociatedSection() != null 2049 && InstanceManager.isInitialized(jmri.jmrit.dispatcher.DispatcherFrame.class) 2050 && InstanceManager.getNullableDefault(LayoutBlockManager.class) != null 2051 && getAssociatedSection().getState() != Section.FORWARD) { 2052 2053 LayoutBlockManager lbm = InstanceManager.getDefault(LayoutBlockManager.class); 2054 for (Block key : autoBlocks.keySet()) { 2055 LayoutBlock lb = lbm.getLayoutBlock(key); 2056 if (lb != null && lb.getUseExtraColor()) { 2057 state = false; 2058 break; 2059 } 2060 } 2061 if (!state) { 2062 for (NamedBeanSetting nbh : userSetBlocks) { 2063 Block key = (Block) nbh.getBean(); 2064 LayoutBlock lb = lbm.getLayoutBlock(key); 2065 if (lb != null && lb.getUseExtraColor()) { 2066 state = false; 2067 break; 2068 } 2069 } 2070 } 2071 } 2072 2073 if (!state) { 2074 turnoutThrown = false; 2075 permissiveBlock = false; 2076 } 2077 2078 active = state; 2079 ThreadingUtil.runOnLayout(() -> { 2080 setSignalAppearance(); 2081 }); 2082 } 2083 2084 /** 2085 * Set up this source-destination signal mast logic pair. Steps through 2086 * every list defined on the source mast. 2087 */ 2088 void initialise() { 2089 if ((destMastInit) || (disposed)) { 2090 return; 2091 } 2092 2093 active = false; 2094 turnoutThrown = false; 2095 permissiveBlock = false; 2096 boolean routeclear = true; 2097 if ((useLayoutEditor) && (autoTurnouts.isEmpty()) && (autoBlocks.isEmpty()) && (autoMasts.isEmpty())) { 2098 return; 2099 } 2100 2101 calculateSpeed(); 2102 2103 Enumeration<Turnout> keys = autoTurnouts.keys(); 2104 while (keys.hasMoreElements()) { 2105 Turnout key = keys.nextElement(); 2106 key.addPropertyChangeListener(propertyTurnoutListener); 2107 2108 if (key.getKnownState() != autoTurnouts.get(key)) { 2109 if (key.getState() != autoTurnouts.get(key)) { 2110 if (isTurnoutIncluded(key)) { 2111 if (key.getState() != getTurnoutState(key)) { 2112 routeclear = false; 2113 } else if (key.getState() == Turnout.THROWN) { 2114 turnoutThrown = true; 2115 } 2116 } else { 2117 routeclear = false; 2118 } 2119 } 2120 } else if (key.getState() == Turnout.THROWN) { 2121 turnoutThrown = true; 2122 } 2123 } 2124 2125 for (NamedBeanSetting nbh : userSetTurnouts) { 2126 Turnout key = (Turnout) nbh.getBean(); 2127 key.addPropertyChangeListener(propertyTurnoutListener, nbh.getBeanName(), 2128 "Signal Mast Logic:" + source.getDisplayName() + " to " + destinationSignalMast.getDisplayName()); 2129 if (key.getKnownState() != nbh.getSetting()) { 2130 routeclear = false; 2131 } else if (key.getState() == Turnout.THROWN) { 2132 turnoutThrown = true; 2133 } 2134 } 2135 2136 Enumeration<SignalMast> mastKeys = autoMasts.keys(); 2137 while (mastKeys.hasMoreElements()) { 2138 SignalMast key = mastKeys.nextElement(); 2139 log.debug("{} auto mast add list {}", destinationSignalMast.getDisplayName(), key.getDisplayName()); 2140 key.addPropertyChangeListener(propertySignalMastListener); 2141 String aspect = key.getAspect(); 2142 if ( aspect != null && !aspect.equals(autoMasts.get(key))) { 2143 if (isSignalMastIncluded(key)) { 2144 if (aspect.equals(getSignalMastState(key))) { 2145 routeclear = false; 2146 } 2147 } else { 2148 routeclear = false; 2149 } 2150 } 2151 } 2152 2153 for (NamedBeanSetting nbh : userSetMasts) { 2154 SignalMast key = (SignalMast) nbh.getBean(); 2155 key.addPropertyChangeListener(propertySignalMastListener); 2156 String aspect = key.getAspect(); 2157 log.debug("mast '{}' key aspect '{}'", destinationSignalMast.getDisplayName(), aspect); 2158 if ((aspect == null) || (!aspect.equals(nbh.getStringSetting()))) { 2159 routeclear = false; 2160 } 2161 } 2162 for (NamedBeanSetting nbh : userSetSensors) { 2163 Sensor sensor = (Sensor) nbh.getBean(); 2164 sensor.addPropertyChangeListener(propertySensorListener, nbh.getBeanName(), 2165 "Signal Mast Logic:" + source.getDisplayName() + " to " + destinationSignalMast.getDisplayName()); 2166 if (sensor.getKnownState() != nbh.getSetting()) { 2167 routeclear = false; 2168 } 2169 } 2170 2171 for (Map.Entry<Block, Integer> entry : this.autoBlocks.entrySet()) { 2172 log.debug("{} auto block add list {}", destinationSignalMast.getDisplayName(), 2173 entry.getKey().getDisplayName()); 2174 entry.getKey().addPropertyChangeListener(propertyBlockListener); 2175 if (entry.getKey().getState() != entry.getValue()) { 2176 if (isBlockIncluded(entry.getKey())) { 2177 if (entry.getKey().getState() != getBlockState(entry.getKey())) { 2178 if (entry.getKey().getState() == Block.OCCUPIED && entry.getKey().getPermissiveWorking()) { 2179 permissiveBlock = true; 2180 } else { 2181 routeclear = false; 2182 } 2183 } 2184 } else { 2185 if (entry.getKey().getState() == Block.OCCUPIED && entry.getKey().getPermissiveWorking()) { 2186 permissiveBlock = true; 2187 } else if (entry.getKey().getState() == Block.UNDETECTED) { 2188 log.debug("Block {} is UNDETECTED so treat as unoccupied", entry.getKey().getDisplayName()); 2189 } else { 2190 routeclear = false; 2191 } 2192 } 2193 } 2194 } 2195 2196 for (NamedBeanSetting nbh : userSetBlocks) { 2197 Block key = (Block) nbh.getBean(); 2198 key.addPropertyChangeListener(propertyBlockListener); 2199 if (key.getState() != getBlockState(key)) { 2200 if (key.getState() == Block.OCCUPIED && key.getPermissiveWorking()) { 2201 permissiveBlock = true; 2202 } else { 2203 routeclear = false; 2204 } 2205 } 2206 } 2207 if ( permissiveBlock 2208 /* If a block has been found to be permissive, but the source signalmast 2209 does not support a call-on/permissive aspect then the route can not be set */ 2210 && getSourceMast().getAppearanceMap().getSpecificAppearance(SignalAppearanceMap.PERMISSIVE) == null) { 2211 routeclear = false; 2212 } 2213 if (routeclear) { 2214 active = true; 2215 setSignalAppearance(); 2216 } else { 2217 permissiveBlock = false; 2218 turnoutThrown = false; 2219 } 2220 destMastInit = true; 2221 } 2222 2223 void useLayoutEditor(boolean boo) throws JmriException { 2224 log.debug("{} called useLayoutEditor({}), is {}", 2225 destinationSignalMast.getDisplayName(), boo, useLayoutEditor); 2226 if (useLayoutEditor == boo) { 2227 return; 2228 } 2229 useLayoutEditor = boo; 2230 if ((boo) && (InstanceManager.getDefault(LayoutBlockManager.class).routingStablised())) { 2231 // JmriException considered normal if there is no valid path using the layout editor. 2232 setupLayoutEditorDetails(); 2233 } else { 2234 destinationBlock = null; 2235 facingBlock = null; 2236 protectingBlock = null; 2237 setAutoBlocks(null); 2238 setAutoTurnouts(null); 2239 } 2240 } 2241 2242 void useLayoutEditorDetails(boolean turnouts, boolean blocks) throws JmriException { 2243 log.debug("{} use layout editor details called {}", 2244 destinationSignalMast.getDisplayName(), useLayoutEditor); 2245 useLayoutEditorTurnouts = turnouts; 2246 useLayoutEditorBlocks = blocks; 2247 if ((useLayoutEditor) && (InstanceManager.getDefault(LayoutBlockManager.class).routingStablised())) { 2248 // JmriException considered normal if there is no valid path using the Layout Editor. 2249 setupLayoutEditorDetails(); 2250 } 2251 } 2252 2253 void setupLayoutEditorDetails() throws JmriException { 2254 log.debug("setupLayoutEditorDetails: useLayoutEditor={} disposed={}", useLayoutEditor, disposed); 2255 if ((!useLayoutEditor) || (disposed)) { 2256 return; 2257 } 2258 LayoutBlockManager lbm = InstanceManager.getDefault(LayoutBlockManager.class); 2259 if ( destinationBlock != null) { 2260 log.debug("{} Set use layout editor", destinationSignalMast.getDisplayName()); 2261 } 2262 Set<LayoutEditor> layout = InstanceManager.getDefault(EditorManager.class).getAll(LayoutEditor.class); 2263 List<LayoutBlock> protectingBlocks = new ArrayList<>(); 2264 // We don't care which Layout Editor panel the signal mast is on, just so long as 2265 // the routing is done via layout blocks. 2266 remoteProtectingBlock = null; 2267 for (int i = 0; i < layout.size(); i++) { 2268 log.debug("{} Layout name {}", destinationSignalMast.getDisplayName(), editor ); 2269 if (facingBlock == null) { 2270 facingBlock = lbm.getFacingBlockByNamedBean(getSourceMast(), editor); 2271 } 2272 if (protectingBlock == null && protectingBlocks.isEmpty()) { 2273 //This is wrong 2274 protectingBlocks = lbm.getProtectingBlocksByNamedBean(getSourceMast(), editor); 2275 } 2276 if (destinationBlock == null) { 2277 destinationBlock = lbm.getFacingBlockByNamedBean(destinationSignalMast, editor); 2278 } 2279 if (remoteProtectingBlock == null) { 2280 remoteProtectingBlock = lbm.getProtectedBlockByNamedBean(destinationSignalMast, editor); 2281 } 2282 } 2283 // At this point, if we are not using the Layout Editor turnout or block 2284 // details then there is no point in trying to gather them. 2285 if ((!useLayoutEditorTurnouts) && (!useLayoutEditorBlocks)) { 2286 return; 2287 } 2288 if (facingBlock == null) { 2289 log.error("No facing block found for source mast {}", getSourceMast().getDisplayName()); 2290 throw new JmriException("No facing block found for source mast " + getSourceMast().getDisplayName()); 2291 } 2292 if (destinationBlock == null) { 2293 log.error("No facing block found for destination mast {}", destinationSignalMast.getDisplayName()); 2294 throw new JmriException("No facing block found for destination mast " + destinationSignalMast.getDisplayName()); 2295 } 2296 List<LayoutBlock> lblks = new ArrayList<>(); 2297 if (protectingBlock == null) { 2298 log.debug("protecting block is null"); 2299 String pBlkNames = ""; 2300 StringBuffer lBlksNamesBuf = new StringBuffer(); 2301 for (LayoutBlock pBlk : protectingBlocks) { 2302 log.debug("checking layoutBlock {}", pBlk.getDisplayName()); 2303 pBlkNames = pBlkNames + pBlk.getDisplayName() + " (" + lbm.getLayoutBlockConnectivityTools().checkValidDest(facingBlock, pBlk, destinationBlock, remoteProtectingBlock, LayoutBlockConnectivityTools.Routing.MASTTOMAST) + "), "; 2304 if (lbm.getLayoutBlockConnectivityTools().checkValidDest(facingBlock, pBlk, destinationBlock, remoteProtectingBlock, LayoutBlockConnectivityTools.Routing.MASTTOMAST)) { 2305 try { 2306 lblks = lbm.getLayoutBlockConnectivityTools().getLayoutBlocks(facingBlock, destinationBlock, pBlk, true, LayoutBlockConnectivityTools.Routing.MASTTOMAST); 2307 protectingBlock = pBlk; 2308 log.debug("building path names..."); 2309 for (LayoutBlock lBlk : lblks) { 2310 lBlksNamesBuf.append(" "); 2311 lBlksNamesBuf.append(lBlk.getDisplayName()); 2312 } 2313 break; 2314 } catch (JmriException ee) { 2315 log.debug("path not found this time"); 2316 } 2317 } 2318 } 2319 String lBlksNames = new String(lBlksNamesBuf); 2320 2321 if (protectingBlock == null) { 2322 throw new JmriException("Path not valid, protecting block is null. Protecting block: " + pBlkNames 2323 + " not connected to " + facingBlock.getDisplayName() + ". Layout block names: " + lBlksNames); 2324 } 2325 } 2326 if (!lbm.getLayoutBlockConnectivityTools().checkValidDest(facingBlock,protectingBlock, 2327 destinationBlock, remoteProtectingBlock, LayoutBlockConnectivityTools.Routing.MASTTOMAST)) { 2328 throw new JmriException("Path not valid, destination check failed."); 2329 } 2330 if (log.isDebugEnabled()) { 2331 log.debug("{} face {}", destinationSignalMast.getDisplayName(), facingBlock); 2332 log.debug("{} prot {}", destinationSignalMast.getDisplayName(), protectingBlock); 2333 log.debug("{} dest {}", destinationSignalMast.getDisplayName(), destinationBlock); 2334 } 2335 2336 if (destinationBlock != null && protectingBlock != null && facingBlock != null) { 2337 setAutoMasts(null, true); 2338 if (log.isDebugEnabled()) { 2339 log.debug("{} face {}", destinationSignalMast.getDisplayName(), facingBlock.getDisplayName()); 2340 log.debug("{} prot {}", destinationSignalMast.getDisplayName(), protectingBlock.getDisplayName()); 2341 log.debug("{} dest {}", destinationSignalMast.getDisplayName(), destinationBlock.getDisplayName()); 2342 } 2343 2344 try { 2345 lblks = lbm.getLayoutBlockConnectivityTools().getLayoutBlocks( 2346 facingBlock, destinationBlock, protectingBlock, 2347 true, LayoutBlockConnectivityTools.Routing.MASTTOMAST); 2348 } catch (JmriException ee) { 2349 log.error("No blocks found by the layout editor for pair {}-{}", 2350 source.getDisplayName(), destinationSignalMast.getDisplayName()); 2351 } 2352 LinkedHashMap<Block, Integer> block = setupLayoutEditorTurnoutDetails(lblks); 2353 2354 for (int i = 0; i < blockInXings.size(); i++) { 2355 blockInXings.get(i).removeSignalMastLogic(source); 2356 } 2357 blockInXings = new ArrayList<>(0); 2358 xingAutoBlocks = new ArrayList<>(0); 2359 for (LayoutEditor lay : layout) { 2360 for (LevelXing levelXing : lay.getLevelXings()) { 2361 //Looking for a crossing that both layout blocks defined and they are individual. 2362 if ((levelXing.getLayoutBlockAC() != null) 2363 && (levelXing.getLayoutBlockBD() != null) 2364 && (levelXing.getLayoutBlockAC() != levelXing.getLayoutBlockBD())) { 2365 if (lblks.contains(levelXing.getLayoutBlockAC()) && 2366 levelXing.getLayoutBlockAC() != facingBlock) { // Don't include the facing xing blocks 2367 block.put(levelXing.getLayoutBlockBD().getBlock(), Block.UNOCCUPIED); 2368 xingAutoBlocks.add(levelXing.getLayoutBlockBD().getBlock()); 2369 blockInXings.add(levelXing); 2370 } else if (lblks.contains(levelXing.getLayoutBlockBD()) && 2371 levelXing.getLayoutBlockBD() != facingBlock) { // Don't include the facing xing blocks 2372 block.put(levelXing.getLayoutBlockAC().getBlock(), Block.UNOCCUPIED); 2373 xingAutoBlocks.add(levelXing.getLayoutBlockAC().getBlock()); 2374 blockInXings.add(levelXing); 2375 } 2376 } 2377 } 2378 } 2379 if (useLayoutEditorBlocks) { 2380 setAutoBlocks(block); 2381 } else { 2382 setAutoBlocks(null); 2383 } 2384 if (!useLayoutEditorTurnouts) { 2385 setAutoTurnouts(null); 2386 } 2387 2388 setupAutoSignalMast(null, false); 2389 } 2390 initialise(); 2391 } 2392 2393 /** 2394 * From a list of Layout Blocks, search for included Turnouts and their 2395 * Set To state. 2396 * 2397 * @param lblks List of Layout Blocks 2398 * @return a list of block - turnout state pairs 2399 */ 2400 LinkedHashMap<Block, Integer> setupLayoutEditorTurnoutDetails(List<LayoutBlock> lblks) { 2401 ConnectivityUtil connection; 2402 List<LayoutTrackExpectedState<LayoutTurnout>> turnoutList; 2403 Hashtable<Turnout, Integer> turnoutSettings = new Hashtable<>(); 2404 LinkedHashMap<Block, Integer> block = new LinkedHashMap<>(); 2405 for (int i = 0; i < lblks.size(); i++) { 2406 log.debug("layoutblock {}",lblks.get(i).getDisplayName()); 2407 block.put(lblks.get(i).getBlock(), Block.UNOCCUPIED); 2408 if ((i > 0)) { 2409 int nxtBlk = i + 1; 2410 int preBlk = i - 1; 2411 if (i == lblks.size() - 1) { 2412 nxtBlk = i; 2413 } 2414 //We use the best connectivity for the current block. 2415 connection = new ConnectivityUtil(lblks.get(i).getMaxConnectedPanel()); 2416 if (i == lblks.size() - 1 && remoteProtectingBlock != null) { 2417 turnoutList = connection.getTurnoutList(lblks.get(i) 2418 .getBlock(), lblks.get(preBlk).getBlock(), remoteProtectingBlock.getBlock()); 2419 }else{ 2420 turnoutList = connection.getTurnoutList(lblks.get(i) 2421 .getBlock(), lblks.get(preBlk).getBlock(), lblks.get(nxtBlk).getBlock()); 2422 } 2423 for (int x = 0; x < turnoutList.size(); x++) { 2424 LayoutTurnout lt = turnoutList.get(x).getObject(); 2425 if (lt instanceof LayoutSlip) { 2426 LayoutSlip ls = (LayoutSlip) lt; 2427 int slipState = turnoutList.get(x).getExpectedState(); 2428 int taState = ls.getTurnoutState(slipState); 2429 Turnout tTemp = ls.getTurnout(); 2430 if (tTemp == null ) { 2431 log.error("Unexpected null Turnout in {}, skipped", ls); 2432 continue; // skip this one in loop, what else can you do? 2433 } 2434 turnoutSettings.put(ls.getTurnout(), taState); 2435 int tbState = ls.getTurnoutBState(slipState); 2436 turnoutSettings.put(ls.getTurnoutB(), tbState); 2437 } else if ( lt != null ) { 2438 String t = lt.getTurnoutName(); 2439 // temporary = why is this looking up the Turnout instead of using getTurnout()? 2440 Turnout turnout = InstanceManager.turnoutManagerInstance().getTurnout(t); 2441 if (log.isDebugEnabled()) { 2442 if ( (lt.getTurnoutType() == LayoutTurnout.TurnoutType.RH_TURNOUT || 2443 lt.getTurnoutType() == LayoutTurnout.TurnoutType.LH_TURNOUT || 2444 lt.getTurnoutType() == LayoutTurnout.TurnoutType.WYE_TURNOUT) 2445 && (!lt.getBlockName().isEmpty())) { 2446 log.debug("turnout in list is straight left/right wye"); 2447 log.debug("turnout block Name {}", lt.getBlockName()); 2448 log.debug("current {} - pre {}", lblks.get(i).getBlock().getDisplayName(), lblks.get(preBlk).getBlock().getDisplayName()); 2449 log.debug("A {}", lt.getConnectA()); 2450 log.debug("B {}", lt.getConnectB()); 2451 log.debug("C {}", lt.getConnectC()); 2452 log.debug("D {}", lt.getConnectD()); 2453 } 2454 } 2455 if (turnout != null ) { 2456 turnoutSettings.put(turnout, turnoutList.get(x).getExpectedState()); 2457 } 2458 Turnout tempT; 2459 if ((tempT = lt.getSecondTurnout()) != null) { 2460 turnoutSettings.put(tempT, turnoutList.get(x).getExpectedState()); 2461 } 2462 /* TODO: We could do with a more intelligent way to deal with double crossovers, other than 2463 just looking at the state of the other conflicting blocks, such as looking at Signalmasts 2464 that protect the other blocks and the settings of any other turnouts along the way. 2465 */ 2466 if (lt.getTurnoutType() == LayoutTurnout.TurnoutType.DOUBLE_XOVER) { 2467 LayoutBlock tempLB; 2468 if (turnoutList.get(x).getExpectedState() == Turnout.THROWN) { 2469 if (lt.getLayoutBlock() == lblks.get(i) || lt.getLayoutBlockC() == lblks.get(i)) { 2470 // A or C, add B and D to remove list unless A=B or C=D 2471 if ((tempLB = lt.getLayoutBlockB()) != null) { 2472 if (!tempLB.equals(lt.getLayoutBlock())) { 2473 dblCrossoverAutoBlocks.add(tempLB.getBlock()); 2474 } 2475 block.put(tempLB.getBlock(), Block.UNOCCUPIED); 2476 } 2477 if ((tempLB = lt.getLayoutBlockD()) != null) { 2478 if (!tempLB.equals(lt.getLayoutBlockC())) { 2479 dblCrossoverAutoBlocks.add(tempLB.getBlock()); 2480 } 2481 block.put(tempLB.getBlock(), Block.UNOCCUPIED); 2482 } 2483 } else if (lt.getLayoutBlockB() == lblks.get(i) || lt.getLayoutBlockD() == lblks.get(i)) { 2484 // B or D, add A and C to remove list unless A=B or C=D 2485 if ((tempLB = lt.getLayoutBlock()) != null) { 2486 if (!tempLB.equals(lt.getLayoutBlockB())) { 2487 dblCrossoverAutoBlocks.add(tempLB.getBlock()); 2488 } 2489 block.put(tempLB.getBlock(), Block.UNOCCUPIED); 2490 } 2491 if ((tempLB = lt.getLayoutBlockC()) != null) { 2492 if (!tempLB.equals(lt.getLayoutBlockD())) { 2493 dblCrossoverAutoBlocks.add(tempLB.getBlock()); 2494 } 2495 block.put(tempLB.getBlock(), Block.UNOCCUPIED); 2496 } 2497 } 2498 } 2499 } 2500 } 2501 } 2502 } 2503 } 2504 // ----- Begin Turntable Alignment Check ----- 2505 // For paths onto a turntable, we must add a condition for the turntable's alignment. The 2506 // turnout that controls the turntable position is associated with the specific ray track. 2507 // Each ray track can have a control turnout assigned. Setting this turnout to a specific 2508 // state (usually THROWN) is the command to align the turntable to that ray. 2509 // The following logic adds a CONDITION to the Signal Mast Logic, requiring that the 2510 // correct ray's turnout is in its required state before the signal will clear. 2511 // This does NOT command the turnout to move; it only checks its state for the interlocking. 2512 Set<LayoutEditor> layout = InstanceManager.getDefault(EditorManager.class).getAll(LayoutEditor.class); 2513 for (LayoutEditor lay : layout) { 2514 for (LayoutTurntable turntable : lay.getLayoutTurntables()) { 2515 // Check for a path from an Approach Mast to the Buffer Mast (Path 3). 2516 // The destination block is the turntable block, and the destination mast is the buffer mast. 2517 if (turntable.getLayoutBlock() == destinationBlock && turntable.getBufferMast() == destinationSignalMast) { 2518 // The source mast's facing block is the ray block for this path. 2519 for (LayoutTurntable.RayTrack ray : turntable.getRayTrackList()) { 2520 if (ray.getConnect() != null && ray.getConnect().getLayoutBlock() == DefaultSignalMastLogic.this.facingBlock) { 2521 // This is the correct ray. Get its control turnout and required state. 2522 Turnout rayTurnout = ray.getTurnout(); 2523 int requiredState = ray.getTurnoutState(); 2524 if (rayTurnout != null) { 2525 turnoutSettings.put(rayTurnout, requiredState); 2526 } 2527 break; // Found the ray, no need to check others. 2528 } 2529 } 2530 } 2531 // Check for a path from the Exit Mast to a remote mast (Path 1). 2532 // The source mast is the turntable's exit mast. 2533 if (turntable.getExitSignalMast() == getSourceMast()) { 2534 // The protecting block is the ray block for this path. 2535 for (LayoutTurntable.RayTrack ray : turntable.getRayTrackList()) { 2536 if (ray.getConnect() != null && ray.getConnect().getLayoutBlock() == protectingBlock) { 2537 // This is the correct ray. Get its control turnout and required state. 2538 Turnout rayTurnout = ray.getTurnout(); 2539 int requiredState = ray.getTurnoutState(); 2540 if (rayTurnout != null) { 2541 turnoutSettings.put(rayTurnout, requiredState); 2542 } 2543 break; // Found the ray, no need to check others. 2544 } 2545 } 2546 } 2547 } 2548 } 2549 // ----- End Turntable Alignment Check ----- 2550 // ----- Begin Traverser Alignment Check ----- 2551 for (LayoutEditor lay : layout) { 2552 for (LayoutTraverser traverser : lay.getLayoutTraversers()) { 2553 // Check for a path from an Approach Mast to the Buffer Mast (Path 3). 2554 // The destination block is the traverser block, and the destination mast is the buffer mast. 2555 if (traverser.getLayoutBlock() == destinationBlock && traverser.getBufferMast() == destinationSignalMast) { 2556 // The source mast's facing block is the slot block for this path. 2557 for (LayoutTraverser.SlotTrack slot : traverser.getSlotList()) { 2558 if (slot.getConnect() != null && slot.getConnect().getLayoutBlock() == DefaultSignalMastLogic.this.facingBlock) { 2559 // This is the correct slot. Get its control turnout and required state. 2560 Turnout slotTurnout = slot.getTurnout(); 2561 int requiredState = slot.getTurnoutState(); 2562 if (slotTurnout != null) { 2563 turnoutSettings.put(slotTurnout, requiredState); 2564 } 2565 break; // Found the slot, no need to check others. 2566 } 2567 } 2568 } 2569 // Check for a path from the Exit Mast to a remote mast (Path 1). 2570 // The source mast is the traverser's exit mast. 2571 if (traverser.getExitSignalMast() == getSourceMast()) { 2572 // The protecting block is the slot block for this path. 2573 for (LayoutTraverser.SlotTrack slot : traverser.getSlotList()) { 2574 if (slot.getConnect() != null && slot.getConnect().getLayoutBlock() == protectingBlock) { 2575 // This is the correct slot. Get its control turnout and required state. 2576 Turnout slotTurnout = slot.getTurnout(); 2577 int requiredState = slot.getTurnoutState(); 2578 if (slotTurnout != null) { 2579 turnoutSettings.put(slotTurnout, requiredState); 2580 } 2581 break; // Found the slot, no need to check others. 2582 } 2583 } 2584 } 2585 } 2586 } 2587 // ----- End Traverser Alignment Check ----- 2588 if (useLayoutEditorTurnouts) { 2589 setAutoTurnouts(turnoutSettings); 2590 } 2591 return block; 2592 } 2593 2594 /** 2595 * Generate auto signalmast for a given SML. Looks through all the other 2596 * logics to see if there are any blocks that are in common and thus 2597 * will add the other signal mast protecting that block. 2598 * 2599 * @param sml The Signal Mast Logic for which to set up 2600 * autoSignalMasts 2601 * @param overwrite When true, replace an existing autoMasts list in the 2602 * SML 2603 */ 2604 void setupAutoSignalMast(SignalMastLogic sml, boolean overwrite) { 2605 if (!allowAutoSignalMastGeneration) { 2606 return; 2607 } 2608 List<SignalMastLogic> smlList = InstanceManager.getDefault(SignalMastLogicManager.class) 2609 .getLogicsByDestination(destinationSignalMast); 2610 List<Block> allBlock = new ArrayList<>(); 2611 2612 userSetBlocks.forEach(nbh -> allBlock.add((Block) nbh.getBean())); 2613 2614 Set<Block> blockKeys = autoBlocks.keySet(); 2615 blockKeys.stream().filter(key -> (!allBlock.contains(key))).forEachOrdered(key -> 2616 allBlock.add(key)); 2617 Hashtable<SignalMast, String> masts; 2618 if (sml != null) { 2619 masts = autoMasts; 2620 if (sml.areBlocksIncluded(allBlock)) { 2621 SignalMast mast = sml.getSourceMast(); 2622 String danger = mast.getAppearanceMap().getSpecificAppearance(SignalAppearanceMap.DANGER); 2623 masts.put(mast, danger); 2624 } else { 2625 //No change so will leave. 2626 return; 2627 } 2628 } else { 2629 masts = new Hashtable<>(); 2630 for (int i = 0; i < smlList.size(); i++) { 2631 if (smlList.get(i).areBlocksIncluded(allBlock)) { 2632 SignalMast mast = smlList.get(i).getSourceMast(); 2633 String danger = mast.getAppearanceMap().getSpecificAppearance(SignalAppearanceMap.DANGER); 2634 masts.put(mast, danger); 2635 } 2636 } 2637 } 2638 setAutoMasts(masts, overwrite); 2639 } 2640 2641 /** 2642 * Add a certain Signal Mast to the list of AutoSignalMasts for this 2643 * SML. 2644 * 2645 * @param mast The Signal Mast to be added 2646 */ 2647 void addAutoSignalMast(SignalMast mast) { 2648 log.debug("{} add mast to auto list {}", destinationSignalMast.getDisplayName(), mast); 2649 String danger = mast.getAppearanceMap().getSpecificAppearance(SignalAppearanceMap.DANGER); 2650 if (danger == null) { 2651 log.error("Can not add SignalMast {} to logic for {} to {} " 2652 + "as it does not have a Danger appearance configured", 2653 mast.getDisplayName(), source.getDisplayName(), destinationSignalMast.getDisplayName()); 2654 return; 2655 } 2656 this.autoMasts.put(mast, danger); 2657 if (destMastInit) { 2658 mast.addPropertyChangeListener(propertySignalMastListener); 2659 } 2660 firePropertyChange(PROPERTY_AUTO_MASTS, null, this.destinationSignalMast); 2661 } 2662 2663 /** 2664 * Remove a certain Signal Mast from the list of AutoSignalMasts for 2665 * this SML. 2666 * 2667 * @param mast The Signal Mast to be removed 2668 */ 2669 void removeAutoSignalMast(SignalMast mast) { 2670 this.autoMasts.remove(mast); 2671 if (destMastInit) { 2672 mast.removePropertyChangeListener(propertySignalMastListener); 2673 } 2674 firePropertyChange(PROPERTY_AUTO_MASTS, this.destinationSignalMast, null); 2675 } 2676 2677 boolean useLayoutEditor() { 2678 return useLayoutEditor; 2679 } 2680 2681 boolean useLayoutEditorBlocks() { 2682 return useLayoutEditorBlocks; 2683 } 2684 2685 boolean useLayoutEditorTurnouts() { 2686 return useLayoutEditorTurnouts; 2687 } 2688 2689 boolean allowAutoSignalMastGeneration = false; 2690 2691 boolean allowAutoSignalMastGen() { 2692 return allowAutoSignalMastGeneration; 2693 } 2694 2695 void allowAutoSignalMastGen(boolean gen) { 2696 if (allowAutoSignalMastGeneration == gen) { 2697 return; 2698 } 2699 allowAutoSignalMastGeneration = gen; 2700 } 2701 2702 /** 2703 * Remove references from this Destination Mast and clear lists, so that 2704 * it can eventually be garbage-collected. 2705 * <p> 2706 * Note: This does not stop any delayed operations that might be queued. 2707 */ 2708 void dispose() { 2709 disposed = true; 2710 clearTurnoutLock(); 2711 destinationSignalMast.removePropertyChangeListener(propertyDestinationMastListener); 2712 setBlocks(null); 2713 setAutoBlocks(null); 2714 setTurnouts(null); 2715 setAutoTurnouts(null); 2716 setSensors(null); 2717 setMasts(null); 2718 setAutoMasts(null, true); 2719 } 2720 2721 void lockTurnouts() { 2722 // We do not allow the turnouts to be locked if we are disposing the logic, 2723 // if the logic is not active, or if we do not allow the turnouts to be locked. 2724 if ((disposed) || (!lockTurnouts) || (!active)) { 2725 return; 2726 } 2727 2728 userSetTurnouts.stream().map(nbh -> (Turnout) nbh.getBean()).forEachOrdered(key -> { 2729 key.setLocked(Turnout.CABLOCKOUT + Turnout.PUSHBUTTONLOCKOUT, true); 2730 }); 2731 Enumeration<Turnout> keys = autoTurnouts.keys(); 2732 while (keys.hasMoreElements()) { 2733 Turnout key = keys.nextElement(); 2734 key.setLocked(Turnout.CABLOCKOUT + Turnout.PUSHBUTTONLOCKOUT, true); 2735 } 2736 } 2737 2738 void clearTurnoutLock() { 2739 // We do not allow the turnout lock to be cleared if we are not active, 2740 // and the lock flag has not been set. 2741 if ((!lockTurnouts) && (!active)) { 2742 return; 2743 } 2744 2745 Enumeration<Turnout> keys = autoTurnouts.keys(); 2746 while (keys.hasMoreElements()) { 2747 Turnout key = keys.nextElement(); 2748 key.setLocked(Turnout.CABLOCKOUT + Turnout.PUSHBUTTONLOCKOUT, false); 2749 } 2750 2751 userSetTurnouts.stream().map(nbh -> (Turnout) nbh.getBean()).forEachOrdered(key -> 2752 key.setLocked(Turnout.CABLOCKOUT + Turnout.PUSHBUTTONLOCKOUT, false)); 2753 } 2754 2755 protected void calculateSpeed() { 2756 log.debug("{} calculate the speed setting for this logic ie what the signalmast will display", destinationSignalMast.getDisplayName()); 2757 minimumBlockSpeed = 0.0f; 2758 Enumeration<Turnout> keys = autoTurnouts.keys(); 2759 while (keys.hasMoreElements()) { 2760 Turnout key = keys.nextElement(); 2761 log.debug("{} turnout {}", destinationSignalMast.getDisplayName(), key.getDisplayName()); 2762 if (!isTurnoutIncluded(key)) { 2763 if (autoTurnouts.get(key) == Turnout.CLOSED) { 2764 if (((key.getStraightLimit() < minimumBlockSpeed) || (minimumBlockSpeed == 0)) && (key.getStraightLimit() != -1)) { 2765 minimumBlockSpeed = key.getStraightLimit(); 2766 log.debug("{} turnout {} set speed to {}", destinationSignalMast.getDisplayName(), key.getDisplayName(), minimumBlockSpeed); 2767 } 2768 } else { 2769 if (((key.getDivergingLimit() < minimumBlockSpeed) || (minimumBlockSpeed == 0)) && (key.getDivergingLimit() != -1)) { 2770 minimumBlockSpeed = key.getDivergingLimit(); 2771 log.debug("{} turnout {} set speed to {}", destinationSignalMast.getDisplayName(), key.getDisplayName(), minimumBlockSpeed); 2772 } 2773 } 2774 } 2775 } 2776 2777 userSetTurnouts.forEach(nbh -> { 2778 Turnout key = (Turnout) nbh.getBean(); 2779 if (nbh.getSetting() == Turnout.CLOSED) { 2780 if (((key.getStraightLimit() < minimumBlockSpeed) || (minimumBlockSpeed == 0)) && (key.getStraightLimit() != -1)) { 2781 minimumBlockSpeed = key.getStraightLimit(); 2782 log.debug("{} turnout {} set speed to {}", destinationSignalMast.getDisplayName(), key.getDisplayName(), minimumBlockSpeed); 2783 } 2784 } else if (nbh.getSetting() == Turnout.THROWN) { 2785 if (((key.getDivergingLimit() < minimumBlockSpeed) || (minimumBlockSpeed == 0)) && (key.getDivergingLimit() != -1)) { 2786 minimumBlockSpeed = key.getDivergingLimit(); 2787 log.debug("{} turnout {} set speed to {}", destinationSignalMast.getDisplayName(), key.getDisplayName(), minimumBlockSpeed); 2788 } 2789 } 2790 }); 2791 2792 Set<Block> autoBlockKeys = autoBlocks.keySet(); 2793 for (Block key : autoBlockKeys) { 2794 log.debug("{} auto block add list {}", destinationSignalMast.getDisplayName(), key.getDisplayName()); 2795 if (!isBlockIncluded(key)) { 2796 if (((key.getSpeedLimit() < minimumBlockSpeed) || (minimumBlockSpeed == 0)) && (key.getSpeedLimit() != -1)) { 2797 minimumBlockSpeed = key.getSpeedLimit(); 2798 log.debug("{} block {} set speed to {}", destinationSignalMast.getDisplayName(), key.getDisplayName(), minimumBlockSpeed); 2799 } 2800 } 2801 } 2802 for (NamedBeanSetting nbh : userSetBlocks) { 2803 Block key = (Block) nbh.getBean(); 2804 if (((key.getSpeedLimit() < minimumBlockSpeed) || (minimumBlockSpeed == 0)) && (key.getSpeedLimit() != -1)) { 2805 log.debug("{} block {} set speed to {}", destinationSignalMast.getDisplayName(), key.getDisplayName(), minimumBlockSpeed); 2806 minimumBlockSpeed = key.getSpeedLimit(); 2807 } 2808 } 2809 /*if(minimumBlockSpeed==-0.1f) 2810 minimumBlockSpeed==0.0f;*/ 2811 } 2812 2813 protected PropertyChangeListener propertySensorListener = new PropertyChangeListener() { 2814 @Override 2815 public void propertyChange(PropertyChangeEvent e) { 2816 Sensor sen = (Sensor) e.getSource(); 2817 log.debug("{} to {} destination sensor {} trigger {}",source.getDisplayName(), destinationSignalMast.getDisplayName(), sen.getDisplayName(), e.getPropertyName()); 2818 if ( Sensor.PROPERTY_KNOWN_STATE.equals(e.getPropertyName())) { 2819 int now = ((Integer) e.getNewValue()); 2820 log.debug("current value {} value we want {}", now, getSensorState(sen)); 2821 if (isSensorIncluded(sen) && getSensorState(sen) != now) { 2822 log.debug("Sensor {} caused the signalmast to be set to danger", sen.getDisplayName()); 2823 //getSourceMast().setAspect(stopAspect); 2824 if (active == true) { 2825 active = false; 2826 setSignalAppearance(); 2827 } 2828 } else if (getSensorState(sen) == now) { 2829 log.debug("{} sensor {} triggers a calculation of change", destinationSignalMast.getDisplayName(), sen.getDisplayName()); 2830 checkState(); 2831 } 2832 } 2833 } 2834 }; 2835 2836 protected PropertyChangeListener propertyTurnoutListener = new PropertyChangeListener() { 2837 @Override 2838 public void propertyChange(PropertyChangeEvent e) { 2839 Turnout turn = (Turnout) e.getSource(); 2840 // log.debug(destination.getDisplayName() + " destination sensor "+ sen.getDisplayName() + "trigger"); 2841 if ( Turnout.PROPERTY_KNOWN_STATE.equals(e.getPropertyName())) { 2842 //Need to check this against the manual list vs auto list 2843 //The manual list should over-ride the auto list 2844 int now = ((Integer) e.getNewValue()); 2845 if (isTurnoutIncluded(turn)) { 2846 if (getTurnoutState(turn) != now) { 2847 log.debug("Turnout {} caused the signalmast to be set", turn.getDisplayName()); 2848 log.debug("From {} to {} Turnout {} caused the signalmast to be set to danger", getSourceMast().getDisplayName(), destinationSignalMast.getDisplayName(), turn.getDisplayName()); 2849 if (active == true) { 2850 active = false; 2851 setSignalAppearance(); 2852 } 2853 } else { 2854 log.debug("{} turnout {} triggers a calculation of change", destinationSignalMast.getDisplayName(), turn.getDisplayName()); 2855 checkState(); 2856 } 2857 } else if (autoTurnouts.containsKey(turn)) { 2858 if (getAutoTurnoutState(turn) != now) { 2859 log.debug("Turnout {} auto caused the signalmast to be set", turn.getDisplayName()); 2860 log.debug("From {} to {} Auto Turnout {} auto caused the signalmast to be set to danger", getSourceMast().getDisplayName(), destinationSignalMast.getDisplayName(), turn.getDisplayName()); 2861 if (active == true) { 2862 active = false; 2863 setSignalAppearance(); 2864 } 2865 } else { 2866 log.debug("From {} to {} turnout {} triggers a calculation of change", getSourceMast().getDisplayName(), destinationSignalMast.getDisplayName(), turn.getDisplayName()); 2867 checkState(); 2868 } 2869 } 2870 2871 } else if ( Turnout.PROPERTY_TURNOUT_STRAIGHT_SPEED.equals(e.getPropertyName()) 2872 || Turnout.PROPERTY_TURNOUT_DIVERGING_SPEED.equals(e.getPropertyName())) { 2873 calculateSpeed(); 2874 } 2875 } 2876 }; 2877 2878 protected PropertyChangeListener propertyBlockListener = new PropertyChangeListener() { 2879 @Override 2880 public void propertyChange(PropertyChangeEvent e) { 2881 Block block = (Block) e.getSource(); 2882 log.debug("{} destination block {} trigger {} {}", destinationSignalMast.getDisplayName(), block.getDisplayName(), e.getPropertyName(), e.getNewValue()); 2883 if ( Block.PROPERTY_STATE.equals(e.getPropertyName()) || Block.PROPERTY_ALLOCATED.equals(e.getPropertyName())) { 2884 // TODO: what is this? 2885 log.debug("Included in user entered block {}", Boolean.toString(isBlockIncluded(block))); 2886 log.debug("Included in AutoGenerated Block {}", Boolean.toString(autoBlocks.containsKey(block))); 2887 if (isBlockIncluded(block)) { 2888 log.debug("{} in manual block", destinationSignalMast.getDisplayName()); 2889 log.debug(" state: {} {}", getBlockState(block), block.getState()); 2890 checkState(); 2891 } else if (autoBlocks.containsKey(block)) { 2892 log.debug("{} in auto block", destinationSignalMast.getDisplayName()); 2893 log.debug(" states: {} {}", getAutoBlockState(block), block.getState()); 2894 checkState(); 2895 } else { 2896 log.debug("{} Not found", destinationSignalMast.getDisplayName()); 2897 } 2898 } else if ( e.getPropertyName().equals("BlockSpeedChange")) { 2899 calculateSpeed(); 2900 } 2901 } 2902 }; 2903 2904 protected PropertyChangeListener propertySignalMastListener = new PropertyChangeListener() { 2905 @Override 2906 public void propertyChange(PropertyChangeEvent e) { 2907 2908 SignalMast mast = (SignalMast) e.getSource(); 2909 log.debug("{} signalmast change {} {}", destinationSignalMast.getDisplayName(), mast.getDisplayName(), e.getPropertyName()); 2910 // log.debug(destination.getDisplayName() + " destination sensor "+ sen.getDisplayName() + "trigger"); 2911 if ( SignalMast.PROPERTY_ASPECT.equals(e.getPropertyName())) { 2912 2913 String now = ((String) e.getNewValue()); 2914 log.debug("{} match property {}", destinationSignalMast.getDisplayName(), now); 2915 if (isSignalMastIncluded(mast)) { 2916 if (!now.equals(getSignalMastState(mast))) { 2917 log.debug("{} in mast list SignalMast {} caused the signalmast to be set", destinationSignalMast.getDisplayName(), mast.getDisplayName()); 2918 log.debug("SignalMast {} caused the signalmast to be set", mast.getDisplayName()); 2919 if (active) { 2920 active = false; 2921 setSignalAppearance(); 2922 } 2923 } else { 2924 log.debug("{} in mast list signalmast change", destinationSignalMast.getDisplayName()); 2925 checkState(); 2926 } 2927 } else if (autoMasts.containsKey(mast)) { 2928 if (!now.equals(getAutoSignalMastState(mast))) { 2929 log.debug("SignalMast {} caused the signalmast to be set", mast.getDisplayName()); 2930 log.debug("{} in auto mast list SignalMast {} caused the signalmast to be set", destinationSignalMast.getDisplayName(), mast.getDisplayName()); 2931 if (active) { 2932 active = false; 2933 setSignalAppearance(); 2934 } 2935 } else { 2936 log.debug("{} in auto mast list signalmast change", destinationSignalMast.getDisplayName()); 2937 checkState(); 2938 } 2939 } 2940 } 2941 } 2942 }; 2943 2944 private class NamedBeanSetting { 2945 2946 NamedBeanHandle<?> namedBean; 2947 int setting = 0; 2948 String strSetting = null; 2949 2950 NamedBeanSetting(NamedBeanHandle<?> namedBean, int setting) { 2951 this.namedBean = namedBean; 2952 this.setting = setting; 2953 } 2954 2955 NamedBeanSetting(NamedBeanHandle<?> namedBean, String setting) { 2956 this.namedBean = namedBean; 2957 strSetting = setting; 2958 } 2959 2960 NamedBean getBean() { 2961 return namedBean.getBean(); 2962 } 2963 2964 NamedBeanHandle<?> getNamedBean() { 2965 return namedBean; 2966 } 2967 2968 int getSetting() { 2969 return setting; 2970 } 2971 2972 String getStringSetting() { 2973 return strSetting; 2974 } 2975 2976 String getBeanName() { 2977 return namedBean.getName(); 2978 } 2979 } 2980 } 2981 2982 /** 2983 * The listener on the destination Signal Mast. 2984 */ 2985 private PropertyChangeListener propertyDestinationMastListener = new PropertyChangeListener() { 2986 @Override 2987 public void propertyChange(PropertyChangeEvent e) { 2988 SignalMast mast = (SignalMast) e.getSource(); 2989 if (mast == destination) { 2990 log.debug("destination mast change {}", mast.getDisplayName()); 2991 setSignalAppearance(); 2992 } 2993 } 2994 }; 2995 2996 /** 2997 * The listener on the source Signal Mast. 2998 */ 2999 private PropertyChangeListener propertySourceMastListener = new PropertyChangeListener() { 3000 @Override 3001 public void propertyChange(PropertyChangeEvent e) { 3002 SignalMast mast = (SignalMast) e.getSource(); 3003 if ((mast == source) && ( SignalMast.PROPERTY_HELD.equals(e.getPropertyName()))) { 3004 log.debug("source mast change {} {}", mast.getDisplayName(), e.getPropertyName()); 3005 setSignalAppearance(); 3006 } 3007 } 3008 }; 3009 3010 //@todo need to think how we deal with auto generated lists based upon the layout editor. 3011 @Override 3012 public void vetoableChange(PropertyChangeEvent evt) throws PropertyVetoException { 3013 NamedBean nb = (NamedBean) evt.getOldValue(); 3014 if (Manager.PROPERTY_CAN_DELETE.equals(evt.getPropertyName())) { 3015 boolean found = false; 3016 StringBuilder message = new StringBuilder(); 3017 if (nb instanceof SignalMast) { 3018 if (nb.equals(source)) { 3019 message.append("Has SignalMast Logic attached which will be <b>Deleted</b> to <ul>"); 3020 for (SignalMast sm : getDestinationList()) { 3021 message.append("<li>"); 3022 message.append(sm.getDisplayName()); 3023 message.append("</li>"); 3024 } 3025 message.append("</ul>"); 3026 throw new PropertyVetoException(message.toString(), evt); 3027 3028 } else if (isDestinationValid((SignalMast) nb)) { 3029 throw new PropertyVetoException("Is the end point mast for logic attached to signal mast " + source.getDisplayName() + " which will be <b>Deleted</b> ", evt); 3030 } 3031 for (SignalMast sm : getDestinationList()) { 3032 if (isSignalMastIncluded((SignalMast) nb, sm)) { 3033 message.append("<li>"); 3034 message.append("Used in conflicting logic of ").append(source.getDisplayName()) 3035 .append(" & ").append(sm.getDisplayName()).append("</li>"); 3036 } 3037 } 3038 } 3039 if (nb instanceof Turnout) { 3040 for (SignalMast sm : getDestinationList()) { 3041 if (isTurnoutIncluded((Turnout) nb, sm)) { 3042 message.append("<li>Is in logic between Signal Masts ").append(source.getDisplayName()) 3043 .append(" ").append(sm.getDisplayName()).append("</li>"); 3044 found = true; 3045 } 3046 } 3047 } 3048 if (nb instanceof Sensor) { 3049 for (SignalMast sm : getDestinationList()) { 3050 if (isSensorIncluded((Sensor) nb, sm)) { 3051 message.append("<li>"); 3052 message.append("Is in logic between Signal Masts ").append(source.getDisplayName()) 3053 .append(" ").append(sm.getDisplayName()).append("</li>"); 3054 found = true; 3055 } 3056 } 3057 } 3058 if (found) { 3059 throw new PropertyVetoException(message.toString(), evt); 3060 } 3061 } else if (Manager.PROPERTY_DO_DELETE.equals(evt.getPropertyName())) { 3062 if (nb instanceof SignalMast) { 3063 if (nb.equals(source)) { 3064 dispose(); 3065 } 3066 if (isDestinationValid((SignalMast) nb)) { 3067 removeDestination((SignalMast) nb); 3068 } 3069 for (SignalMast sm : getDestinationList()) { 3070 if (isSignalMastIncluded((SignalMast) nb, sm)) { 3071 log.warn("Unhandled condition: signal mast included during DoDelete"); 3072 // @todo need to deal with this situation 3073 } 3074 } 3075 } 3076 if (nb instanceof Turnout) { 3077 Turnout t = (Turnout) nb; 3078 getDestinationList().stream().filter(sm -> (isTurnoutIncluded(t, sm))).forEachOrdered(sm -> { 3079 removeTurnout(t, sm); 3080 }); 3081 } 3082 if (nb instanceof Sensor) { 3083 Sensor s = (Sensor) nb; 3084 getDestinationList().stream().filter(sm -> (isSensorIncluded(s, sm))).forEachOrdered(sm -> { 3085 removeSensor(s, sm); 3086 }); 3087 } 3088 } 3089 } 3090 3091 /** 3092 * Note: This does not stop any delayed operations that might be queued. 3093 */ 3094 @Override 3095 public void dispose() { 3096 disposing = true; 3097 getSourceMast().removePropertyChangeListener(propertySourceMastListener); 3098 Enumeration<SignalMast> en = destList.keys(); 3099 while (en.hasMoreElements()) { 3100 SignalMast dm = en.nextElement(); 3101 destList.get(dm).dispose(); 3102 } 3103 super.dispose(); // release any prop change listeners 3104 } 3105 3106 /** 3107 * {@inheritDoc } 3108 */ 3109 @Override 3110 public String getBeanType() { 3111 return Bundle.getMessage("BeanNameSignalMastLogic"); 3112 } 3113 3114 /** 3115 * No valid integer state, always return a constant. 3116 * 3117 * @return Always zero 3118 */ 3119 @Override 3120 public int getState() { 3121 return 0; 3122 } 3123 3124 @Override 3125 public void setState(int i) { 3126 } 3127 3128 /** 3129 * {@inheritDoc } 3130 */ 3131 @Override 3132 public List<NamedBeanUsageReport> getUsageReport(NamedBean bean) { 3133 List<NamedBeanUsageReport> report = new ArrayList<>(); 3134 if (bean != null) { 3135 if (bean.equals(getSourceMast())) { 3136 report.add(new NamedBeanUsageReport("SMLSourceMast")); // NOI18N 3137 } 3138 getDestinationList().forEach((dest) -> { 3139 if (bean.equals(dest)) { 3140 report.add(new NamedBeanUsageReport("SMLDestinationMast")); // NOI18N 3141 } 3142 getAutoBlocks(dest).forEach((block) -> { 3143 if (bean.equals(block)) { 3144 report.add(new NamedBeanUsageReport("SMLBlockAuto", dest)); // NOI18N 3145 } 3146 }); 3147 getBlocks(dest).forEach((block) -> { 3148 if (bean.equals(block)) { 3149 report.add(new NamedBeanUsageReport("SMLBlockUser", dest)); // NOI18N 3150 } 3151 }); 3152 getAutoTurnouts(dest).forEach((turnout) -> { 3153 if (bean.equals(turnout)) { 3154 report.add(new NamedBeanUsageReport("SMLTurnoutAuto", dest)); // NOI18N 3155 } 3156 }); 3157 getTurnouts(dest).forEach((turnout) -> { 3158 if (bean.equals(turnout)) { 3159 report.add(new NamedBeanUsageReport("SMLTurnoutUser", dest)); // NOI18N 3160 } 3161 }); 3162 getSensors(dest).forEach((sensor) -> { 3163 if (bean.equals(sensor)) { 3164 report.add(new NamedBeanUsageReport("SMLSensor", dest)); // NOI18N 3165 } 3166 }); 3167 getAutoMasts(dest).forEach((mast) -> { 3168 if (bean.equals(mast)) { 3169 report.add(new NamedBeanUsageReport("SMLMastAuto", dest)); // NOI18N 3170 } 3171 }); 3172 getSignalMasts(dest).forEach((mast) -> { 3173 if (bean.equals(mast)) { 3174 report.add(new NamedBeanUsageReport("SMLMastUser", dest)); // NOI18N 3175 } 3176 }); 3177 }); 3178 } 3179 return report; 3180 } 3181 3182 private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(DefaultSignalMastLogic.class); 3183 3184}