001package jmri.jmrit.entryexit; 002 003import java.beans.PropertyChangeEvent; 004import java.beans.PropertyChangeListener; 005import java.util.Hashtable; 006import java.util.List; 007import java.util.Map.Entry; 008import jmri.InstanceManager; 009import jmri.NamedBean; 010import jmri.Sensor; 011import jmri.SignalHead; 012import jmri.SignalMast; 013import jmri.jmrit.display.EditorManager; 014import jmri.jmrit.display.SensorIcon; 015import jmri.jmrit.display.layoutEditor.LayoutBlock; 016import jmri.jmrit.display.layoutEditor.LayoutEditor; 017import jmri.jmrit.display.layoutEditor.LayoutSlip; 018import jmri.jmrit.display.layoutEditor.LayoutTurnout; 019import jmri.jmrit.display.layoutEditor.LevelXing; 020import jmri.jmrit.display.layoutEditor.PositionablePoint; 021import org.slf4j.Logger; 022import org.slf4j.LoggerFactory; 023 024public class PointDetails { 025 026 //May want to look at putting a listener on the refLoc to listen to updates to blocks, signals and sensors attached to it 027 LayoutEditor panel = null; 028 LayoutBlock facing; 029 List<LayoutBlock> protectingBlocks; 030 private NamedBean refObj; 031 private Object refLoc; 032 private Sensor sensor; 033 private SignalMast signalmast; 034 private SignalHead signalhead; 035 036 static int nxButtonTimeout = 10; 037 038 Source sourceRoute; 039 transient Hashtable<DestinationPoints, Source> destinations = new Hashtable<>(5); 040 041 public PointDetails(LayoutBlock facing, List<LayoutBlock> protecting) { 042 this.facing = facing; 043 this.protectingBlocks = protecting; 044 } 045 046 public LayoutBlock getFacing() { 047 return facing; 048 } 049 050 public List<LayoutBlock> getProtecting() { 051 return protectingBlocks; 052 } 053 054 //This might be better off a ref to the source pointdetail. 055 boolean routeToSet = false; 056 057 void setRouteTo(boolean boo) { 058 routeToSet = boo; 059 } 060 061 boolean routeFromSet = false; 062 063 void setRouteFrom(boolean boo) { 064 routeFromSet = boo; 065 } 066 067 public void setPanel(LayoutEditor panel) { 068 this.panel = panel; 069 // find the panel that actually contains this sensor, default to the supplied panel 070 for (LayoutEditor layout : InstanceManager.getDefault(EditorManager.class).getAll(LayoutEditor.class)) { 071 for (SensorIcon si : layout.getSensorList()) { 072 if (sensor == si.getNamedBean()) { 073 this.panel = layout; 074 return; 075 } 076 } 077 } 078 } 079 080 void setSensor(Sensor sen) { 081 if (sensor == sen) { 082 return; 083 } 084 if (sensor != null) { 085 sensor.removePropertyChangeListener(nxButtonListener); 086 } 087 sensor = sen; 088 if (sensor != null) { 089 sensor.addPropertyChangeListener(nxButtonListener); 090 } 091 } 092 093 void addSensorList() { 094 sensor.addPropertyChangeListener(nxButtonListener); 095 } 096 097 void removeSensorList() { 098 sensor.removePropertyChangeListener(nxButtonListener); 099 } 100 101 //Sensor getSensor() { return sensor; } 102 protected PropertyChangeListener nxButtonListener = new PropertyChangeListener() { 103 //First off if we were inactive, and now active 104 @Override 105 public void propertyChange(PropertyChangeEvent e) { 106 nxButtonStateChange(e); 107 } 108 }; 109 110 private void nxButtonStateChange(PropertyChangeEvent e) { 111 if (!e.getPropertyName().equals("KnownState")) { // NOI18N 112 return; 113 } 114 int now = ((Integer) e.getNewValue()); 115 int old = ((Integer) e.getOldValue()); 116 117 if ((old == Sensor.UNKNOWN) || (old == Sensor.INCONSISTENT)) { 118 setButtonState(EntryExitPairs.NXBUTTONINACTIVE); 119 return; 120 } 121 int changesWhenClicked = getButtonChanges(); 122 if (InstanceManager.getDefault(EntryExitPairs.class).holdButtonClick(() -> handleHeldClick(e, changesWhenClicked))) { 123 // The click is handled when the route being set is complete. The sensor is not 124 // written now, so that a hardware button only sees the click itself. 125 return; 126 } 127 128 DestinationPoints destPoint = null; 129 130 for (Entry<DestinationPoints, Source> dp : destinations.entrySet()) { 131 // This point might be a destination in zero or more NX pairs. 132 // If the source point is active, then this is a single point route. 133 destPoint = dp.getKey(); 134 if (destPoint.isEnabled() && dp.getValue().getPoint().getNXState() == EntryExitPairs.NXBUTTONSELECTED) { 135 // This destination point has an active source point 136 setButtonState(EntryExitPairs.NXBUTTONSELECTED); 137 // Call activeBean directly 138 destPoint.activeBean(false); 139 log.debug("[nxButtonStateChange] Single point route selected"); 140 return; 141 } 142 } 143 144 if (sourceRoute != null) { 145 if (now == Sensor.ACTIVE && getNXState() == EntryExitPairs.NXBUTTONINACTIVE) { 146 setButtonState(EntryExitPairs.NXBUTTONSELECTED); 147 for (Entry<PointDetails, DestinationPoints> en : sourceRoute.pointToDest.entrySet()) { 148 //Sensor sen = getSensorFromPoint(en.getKey().getPoint()); 149 //Set a time out on the source sensor, so that if its state hasn't been changed, then we will clear it out. 150 if (en.getValue().isEnabled() && !en.getValue().getUniDirection()) { 151 if (en.getKey().getNXState() == EntryExitPairs.NXBUTTONSELECTED) { 152 // Call activeBean via the Source object when bi-directional 153 sourceRoute.activeBean(en.getValue(), true); 154 } 155 } 156 } 157 } else if (now == Sensor.INACTIVE && getNXState() == EntryExitPairs.NXBUTTONSELECTED) { 158 //sensor inactive, nxbutton state was selected, going to set back to inactive - ie user cancelled button 159 setButtonState(EntryExitPairs.NXBUTTONINACTIVE); 160 } else if (now == Sensor.INACTIVE && getNXState() == EntryExitPairs.NXBUTTONACTIVE) { 161 //Sensor gone inactive, while nxbutton was selected - potential start of user either clear route or setting another 162 setButtonState(EntryExitPairs.NXBUTTONSELECTED); 163 for (Entry<PointDetails, DestinationPoints> en : sourceRoute.pointToDest.entrySet()) { 164 //Sensor sen = getSensorFromPoint(en.getKey().getPoint()); 165 //Set a time out on the source sensor, so that if its state hasn't been changed, then we will clear it out. 166 if (en.getValue().isEnabled() && !en.getValue().getUniDirection()) { 167 if (en.getKey().getNXState() == EntryExitPairs.NXBUTTONSELECTED) { 168 // Call activeBean via the Source object when bi-directional 169 sourceRoute.activeBean(en.getValue(), false); 170 } 171 } 172 } 173 } 174 } else if (destPoint != null) { 175 //Button set as a destination but has no source, it has had a change in state 176 if (now == Sensor.ACTIVE) { 177 //State now is Active will set flashing 178 setButtonState(EntryExitPairs.NXBUTTONSELECTED); 179 } else if (getNXState() == EntryExitPairs.NXBUTTONACTIVE) { 180 //Sensor gone inactive while it was previosly active 181 setButtonState(EntryExitPairs.NXBUTTONSELECTED); 182 } else if (getNXState() == EntryExitPairs.NXBUTTONSELECTED) { 183 //Sensor gone inactive while it was previously selected therefore will cancel 184 setButtonState(EntryExitPairs.NXBUTTONINACTIVE); 185 } 186 } 187 188 log.debug("[nxButtonStateChange] Initial button or possible multiple point route"); 189 jmri.InstanceManager.getDefault(jmri.jmrit.entryexit.EntryExitPairs.class).setMultiPointRoute(this, panel); 190 } 191 192 /** 193 * Number of changes NX has made to the state of this button or to its 194 * sensor. A held click compares it to tell if the route changed the button. 195 */ 196 private int buttonChanges = 0; 197 198 private synchronized int getButtonChanges() { 199 return buttonChanges; 200 } 201 202 private synchronized void buttonChanged() { 203 buttonChanges++; 204 } 205 206 /** 207 * Handle a click on the button that was held back while a route was being 208 * set. 209 * <p> 210 * If nothing has changed the button since the click, the click is handled 211 * as it happened, without writing the sensor again. If the route changed 212 * the button, the click is handled as if it happened now: like a click, it 213 * changes the sensor to its other state. This is how the click was handled 214 * when the panel waited for the route to be set. 215 * 216 * @param e the sensor change of the click 217 * @param changesWhenClicked the number of button changes when the click was 218 * held back 219 */ 220 private void handleHeldClick(PropertyChangeEvent e, int changesWhenClicked) { 221 Sensor s = getSensor(); 222 if (s == null) { 223 return; 224 } 225 if (getButtonChanges() == changesWhenClicked && e.getNewValue().equals(s.getKnownState())) { 226 nxButtonStateChange(e); 227 return; 228 } 229 try { 230 s.setKnownState(s.getKnownState() == Sensor.ACTIVE ? Sensor.INACTIVE : Sensor.ACTIVE); 231 } catch (jmri.JmriException ex) { 232 log.error("Could not set Sensor known state.", ex); 233 } 234 } 235 236 void setSignalMast(SignalMast mast) { 237 signalmast = mast; 238 } 239 240 void setSource(Source src) { 241 if (sourceRoute == src) { 242 return; 243 } 244 sourceRoute = src; 245 } 246 247 void setDestination(DestinationPoints srcdp, Source src) { 248 if (!destinations.containsKey(srcdp)) { 249 destinations.put(srcdp, src); 250 } 251 } 252 253 void removeDestination(DestinationPoints srcdp) { 254 destinations.remove(srcdp); 255 if (sourceRoute == null && destinations.isEmpty()) { 256 stopFlashSensor(); 257 sensor.removePropertyChangeListener(nxButtonListener); 258 setSensor(null); 259 } 260 } 261 262 void removeSource(Source src) { 263 sourceRoute = null; 264 if (destinations.isEmpty()) { 265 stopFlashSensor(); 266 setSensor(null); 267 } 268 } 269 270 private int nxButtonState = EntryExitPairs.NXBUTTONINACTIVE; 271 272 void setButtonState(int state) { 273 setNXButtonState(state); 274 } 275 276 void setNXState(int state) { 277 if (state == nxButtonState) { 278 return; 279 } 280 if (state == EntryExitPairs.NXBUTTONSELECTED) { 281 nxButtonTimeOut(); 282 flashSensor(); 283 } else { 284 cancelNXButtonTimeOut(); 285 stopFlashSensor(); 286 } 287 nxButtonState = state; 288 buttonChanged(); 289 } 290 291 public int getNXState() { 292 return nxButtonState; 293 } 294 295 SignalMast getSignalMast() { 296 return signalmast; 297 } 298 299 void setSignalHead(SignalHead head) { 300 signalhead = head; 301 } 302 303 SignalHead getSignalHead() { 304 return signalhead; 305 } 306 307 public LayoutEditor getPanel() { 308 return panel; 309 } 310 311 public void setRefObject(NamedBean refObs) { 312 for (LayoutEditor pnl : InstanceManager.getDefault(EditorManager.class).getAll(LayoutEditor.class)) { 313 if (refLoc == null) { 314 setRefObjectByPanel(refObs, pnl); 315 } 316 } 317 } 318 319 public void setRefObjectByPanel(NamedBean refObs, LayoutEditor pnl) { 320 refObj = refObs; 321 if (pnl != null && refObj != null) { 322 if (refObj instanceof SignalMast || refObj instanceof Sensor) { 323 //String mast = ((SignalMast)refObj).getUserName(); 324 refLoc = pnl.getFinder().findPositionablePointByEastBoundBean(refObj); 325 if (refLoc == null) { 326 refLoc = pnl.getFinder().findPositionablePointByWestBoundBean(refObj); 327 } 328 if (refLoc == null) { 329 refLoc = pnl.getFinder().findLayoutTurnoutByBean(refObj); 330 } 331 if (refLoc == null) { 332 refLoc = pnl.getFinder().findLevelXingByBean(refObj); 333 } 334 if (refLoc == null) { 335 refLoc = pnl.getFinder().findLayoutSlipByBean(refObj); 336 } 337 if (refObj instanceof Sensor) { 338 setSensor((Sensor) refObj); 339 } 340 } else if (refObj instanceof SignalHead) { 341 String signal = refObj.getDisplayName(); 342 refLoc = pnl.getFinder().findPositionablePointByEastBoundSignal(signal); 343 if (refLoc == null) { 344 refLoc = pnl.getFinder().findPositionablePointByWestBoundSignal(signal); 345 } 346 } 347 } 348// if (refLoc != null) { 349// if (refLoc instanceof PositionablePoint) { 350// //((PositionablePoint)refLoc).addPropertyChangeListener(this); 351// } else if (refLoc instanceof LayoutTurnout) { //<== this includes LayoutSlips 352// //((LayoutTurnout)refLoc).addPropertyChangeListener(this); 353// } else if (refLoc instanceof LevelXing) { 354// //((LevelXing)refLoc).addPropertyChangeListener(this); 355// } 356// } 357 //With this set ref we can probably add a listener to it, so that we can detect when a change to the point details takes place 358 } 359 360 public NamedBean getRefObject() { 361 return refObj; 362 } 363 364 public Object getRefLocation() { 365 return refLoc; 366 } 367 368 //LayoutEditor getLayoutEditor() { return panel; } 369 public boolean isRouteToPointSet() { 370 return routeToSet; 371 } 372 373 public boolean isRouteFromPointSet() { 374 return routeFromSet; 375 } 376 377 public String getDisplayName() { 378 if (sensor != null) { 379 String description = sensor.getDisplayName(); 380 if (signalmast != null) { 381 description = description + " (" + signalmast.getDisplayName() + ")"; 382 } 383 return description; 384 } 385 386 if (refObj instanceof SignalMast) { 387 return refObj.getDisplayName(); 388 } else if (refObj instanceof Sensor) { 389 return refObj.getDisplayName(); 390 } else if (refObj instanceof SignalHead) { 391 return refObj.getDisplayName(); 392 } 393 return "no display name"; // NOI18N 394 } 395 396 transient Thread nxButtonTimeOutThr; 397 398 void nxButtonTimeOut() { 399 if ((nxButtonTimeOutThr != null) && (nxButtonTimeOutThr.isAlive())) { 400 return; 401 } 402 extendedtime = true; 403 class ButtonTimeOut implements Runnable { 404 405 ButtonTimeOut() { 406 } 407 408 @Override 409 public void run() { 410 try { 411 //Stage one default timer for the button if no other button has been pressed 412 Thread.sleep(nxButtonTimeout * 1000L); 413 //Stage two if an extended time out has been requested 414 if (extendedtime) { 415 Thread.sleep(60000); //timeout after a minute waiting for the sml to set. 416 } 417 } catch (InterruptedException ex) { 418 log.debug("[nxButtonTimeOut] Flash timer cancelled"); // NOI18N 419 } 420 setNXButtonState(EntryExitPairs.NXBUTTONINACTIVE); 421 } 422 } 423 ButtonTimeOut t = new ButtonTimeOut(); 424 nxButtonTimeOutThr = jmri.util.ThreadingUtil.newThread(t, "NX Button Timeout " + getSensor().getDisplayName()); // NOI18N 425 426 nxButtonTimeOutThr.start(); 427 } 428 429 void cancelNXButtonTimeOut() { 430 if (nxButtonTimeOutThr != null) { 431 nxButtonTimeOutThr.interrupt(); 432 } 433 434 } 435 436 boolean extendedtime = false; 437 438 public void flashSensor() { 439 for (SensorIcon si : getPanel().getSensorList()) { 440 if (si.getSensor() == getSensor()) { 441 si.flashSensor(2, Sensor.ACTIVE, Sensor.INACTIVE); 442 } 443 } 444 } 445 446 public void stopFlashSensor() { 447 for (SensorIcon si : getPanel().getSensorList()) { 448 if (si.getSensor() == getSensor()) { 449 si.stopFlash(); 450 } 451 } 452 } 453 454 synchronized public void setNXButtonState(int state) { 455 if (getSensor() == null) { 456 return; 457 } 458 if (state == EntryExitPairs.NXBUTTONINACTIVE) { 459 //If a route is set to or from out point then we need to leave/set the sensor to ACTIVE 460 if (isRouteToPointSet()) { 461 state = EntryExitPairs.NXBUTTONACTIVE; 462 } else if (isRouteFromPointSet()) { 463 state = EntryExitPairs.NXBUTTONACTIVE; 464 } 465 } 466 setNXState(state); 467 int sensorState; 468 switch (state) { 469 case EntryExitPairs.NXBUTTONINACTIVE: 470 sensorState = Sensor.INACTIVE; 471 break; 472 case EntryExitPairs.NXBUTTONACTIVE: 473 sensorState = Sensor.ACTIVE; 474 break; 475 case EntryExitPairs.NXBUTTONSELECTED: 476 sensorState = Sensor.ACTIVE; 477 break; 478 default: 479 sensorState = Sensor.UNKNOWN; 480 break; 481 } 482 483 //Might need to clear listeners at the stage and then reapply them after. 484 if (getSensor().getKnownState() != sensorState) { 485 buttonChanged(); 486 removeSensorList(); 487 try { 488 getSensor().setKnownState(sensorState); 489 } catch (jmri.JmriException ex) { 490 log.error("Could not set Sensor known state.", ex); 491 } 492 addSensorList(); 493 } 494 } 495 496 /** 497 * @since 4.17.6 498 * Making the source object available for scripting in Jython. 499 * @return the sensor. 500 */ 501 public Sensor getSensor() { 502 if (getRefObject() == null) { 503 return null; 504 } 505 if ((getPanel() != null) && (!getPanel().isEditable()) && (sensor != null)) { 506 return sensor; 507 } 508 509 if (getRefObject() instanceof Sensor) { 510 setSensor((Sensor) getRefObject()); 511 return (Sensor) getRefObject(); 512 } 513 Object objLoc = getRefLocation(); 514 Object objRef = getRefObject(); 515 SignalHead head = null; 516 SignalMast mast = null; 517 String username = ""; 518 String systemname = ""; 519 Sensor foundSensor = null; 520 if (objRef instanceof SignalMast) { 521 mast = (SignalMast) objRef; 522 } 523 if (objRef instanceof SignalHead) { 524 head = (SignalHead) objRef; 525 username = head.getUserName(); 526 systemname = head.getSystemName(); 527 } 528 jmri.SensorManager sm = InstanceManager.sensorManagerInstance(); 529 if (objLoc instanceof PositionablePoint) { 530 PositionablePoint p = (PositionablePoint) objLoc; 531 if (mast != null) { 532 if (p.getEastBoundSignalMast() == objRef) { 533 foundSensor = p.getEastBoundSensor(); 534 } else if (p.getWestBoundSignalMast() == objRef) { 535 foundSensor = p.getWestBoundSensor(); 536 } 537 } else if (head != null) { 538 if ((p.getEastBoundSignal().equals(username)) 539 || p.getEastBoundSignal().equals(systemname)) { 540 foundSensor = p.getEastBoundSensor(); 541 } else if ((p.getWestBoundSignal().equals(username)) 542 || p.getWestBoundSignal().equals(systemname)) { 543 foundSensor = p.getWestBoundSensor(); 544 } 545 } 546 } else if (objLoc instanceof LayoutSlip) { 547 LayoutSlip sl = (LayoutSlip) objLoc; 548 if (mast != null) { 549 if (sl.getSignalAMast() == objRef) { 550 foundSensor = sl.getSensorA(); 551 } else if (sl.getSignalBMast() == objRef) { 552 foundSensor = sl.getSensorB(); 553 } else if (sl.getSignalCMast() == objRef) { 554 foundSensor = sl.getSensorC(); 555 } else if (sl.getSignalDMast() == objRef) { 556 foundSensor = sl.getSensorD(); 557 } 558 } 559 if (head != null) { 560 if ((sl.getSignalA1Name().equals(username)) || (sl.getSignalA1Name().equals(systemname))) { 561 foundSensor = sm.getSensor(sl.getSensorAName()); 562 } else if ((sl.getSignalB1Name().equals(username)) || (sl.getSignalB1Name().equals(systemname))) { 563 foundSensor = sm.getSensor(sl.getSensorBName()); 564 } else if ((sl.getSignalC1Name().equals(username)) || (sl.getSignalC1Name().equals(systemname))) { 565 foundSensor = sm.getSensor(sl.getSensorCName()); 566 } else if ((sl.getSignalD1Name().equals(username)) || (sl.getSignalD1Name().equals(systemname))) { 567 foundSensor = sm.getSensor(sl.getSensorDName()); 568 } 569 } 570 } else //note: you have to do this after LayoutSlip 571 // because LayoutSlip extends LayoutTurnout 572 // (So a LayoutSlip would be an instance of LayoutTurnout.) 573 if (objLoc instanceof LayoutTurnout) { //<== this includes LayoutSlips 574 LayoutTurnout t = (LayoutTurnout) objLoc; 575 if (mast != null) { 576 if (t.getSignalAMast() == objRef) { 577 foundSensor = t.getSensorA(); 578 } else if (t.getSignalBMast() == objRef) { 579 foundSensor = t.getSensorB(); 580 } else if (t.getSignalCMast() == objRef) { 581 foundSensor = t.getSensorC(); 582 } else if (t.getSignalDMast() == objRef) { 583 foundSensor = t.getSensorD(); 584 } 585 } 586 if (head != null) { 587 if ((t.getSignalA1Name().equals(username)) || (t.getSignalA1Name().equals(systemname))) { 588 foundSensor = t.getSensorA(); 589 } else if ((t.getSignalA2Name().equals(username)) || (t.getSignalA2Name().equals(systemname))) { 590 foundSensor = t.getSensorA(); 591 } else if ((t.getSignalA3Name().equals(username)) || (t.getSignalA3Name().equals(systemname))) { 592 foundSensor = t.getSensorA(); 593 } else if ((t.getSignalB1Name().equals(username)) || (t.getSignalB1Name().equals(systemname))) { 594 foundSensor = t.getSensorB(); 595 } else if ((t.getSignalB2Name().equals(username)) || (t.getSignalB2Name().equals(systemname))) { 596 foundSensor = t.getSensorB(); 597 } else if ((t.getSignalC1Name().equals(username)) || (t.getSignalC1Name().equals(systemname))) { 598 foundSensor = t.getSensorC(); 599 } else if ((t.getSignalC2Name().equals(username)) || (t.getSignalC2Name().equals(systemname))) { 600 foundSensor = t.getSensorC(); 601 } else if ((t.getSignalD1Name().equals(username)) || (t.getSignalD1Name().equals(systemname))) { 602 foundSensor = t.getSensorD(); 603 } else if ((t.getSignalD2Name().equals(username)) || (t.getSignalD2Name().equals(systemname))) { 604 foundSensor = t.getSensorD(); 605 } 606 } 607 } else if (objLoc instanceof LevelXing) { 608 LevelXing x = (LevelXing) objLoc; 609 if (mast != null) { 610 if (x.getSignalAMast() == objRef) { 611 foundSensor = x.getSensorA(); 612 } else if (x.getSignalBMast() == objRef) { 613 foundSensor = x.getSensorB(); 614 } else if (x.getSignalCMast() == objRef) { 615 foundSensor = x.getSensorC(); 616 } else if (x.getSignalDMast() == objRef) { 617 foundSensor = x.getSensorD(); 618 } 619 } 620 if (head != null) { 621 if ((x.getSignalAName().equals(username)) || (x.getSignalAName().equals(systemname))) { 622 foundSensor = x.getSensorA(); 623 } else if ((x.getSignalBName().equals(username)) || (x.getSignalBName().equals(systemname))) { 624 foundSensor = x.getSensorB(); 625 } else if ((x.getSignalCName().equals(username)) || (x.getSignalCName().equals(systemname))) { 626 foundSensor = x.getSensorC(); 627 } else if ((x.getSignalDName().equals(username)) || (x.getSignalDName().equals(systemname))) { 628 foundSensor = x.getSensorD(); 629 } 630 } 631 } 632 setSensor(foundSensor); 633 return foundSensor; 634 } 635 636 NamedBean getSignal() { 637 if ((getPanel() != null) && (!getPanel().isEditable()) && (getSignalMast() != null)) { 638 return getSignalMast(); 639 } 640 if ((getPanel() != null) && (!getPanel().isEditable()) && (getSignalHead() != null)) { 641 return getSignalHead(); 642 } 643 jmri.SignalHeadManager sh = InstanceManager.getDefault(jmri.SignalHeadManager.class); 644 NamedBean signal = null; 645 646 if (getRefObject() == null) { 647 log.error("Signal not found at point"); // NOI18N 648 return null; 649 } else if (getRefObject() instanceof SignalMast) { 650 signal = getRefObject(); 651 setSignalMast(((SignalMast) getRefObject())); 652 return signal; 653 } else if (getRefObject() instanceof SignalHead) { 654 signal = getRefObject(); 655 setSignalHead(((SignalHead) getRefObject())); 656 return signal; 657 } 658 659 Sensor sen = (Sensor) getRefObject(); 660 log.debug(" Looking at sensor '{}' on panel '{}' at '{}'", 661 sen.getDisplayName(), getPanel().getLayoutName(), getRefLocation()); 662 if (getRefLocation() instanceof PositionablePoint) { 663 PositionablePoint p = (PositionablePoint) getRefLocation(); 664 if (p.getEastBoundSensor() == sen) { 665 if (p.getEastBoundSignalMast() != null) { 666 signal = p.getEastBoundSignalMast(); 667 } else if (!p.getEastBoundSignal().isEmpty()) { 668 signal = sh.getSignalHead(p.getEastBoundSignal()); 669 } 670 } else if (p.getWestBoundSensor() == sen) { 671 if (p.getWestBoundSignalMast() != null) { 672 signal = p.getWestBoundSignalMast(); 673 } else if (!p.getWestBoundSignal().isEmpty()) { 674 signal = sh.getSignalHead(p.getWestBoundSignal()); 675 } 676 } 677 } else if (getRefLocation() instanceof LayoutSlip) { 678 LayoutSlip t = (LayoutSlip) getRefLocation(); 679 if (t.getSensorA() == sen) { 680 if (t.getSignalAMast() != null) { 681 signal = t.getSignalAMast(); 682 } else if (!t.getSignalA1Name().isEmpty()) { 683 signal = sh.getSignalHead(t.getSignalA1Name()); 684 } 685 } else if (t.getSensorB() == sen) { 686 if (t.getSignalBMast() != null) { 687 signal = t.getSignalBMast(); 688 } else if (!t.getSignalB1Name().isEmpty()) { 689 signal = sh.getSignalHead(t.getSignalB1Name()); 690 } 691 } else if (t.getSensorC() == sen) { 692 if (t.getSignalCMast() != null) { 693 signal = t.getSignalCMast(); 694 } else if (!t.getSignalC1Name().isEmpty()) { 695 signal = sh.getSignalHead(t.getSignalC1Name()); 696 } 697 } else if (t.getSensorD() == sen) { 698 if (t.getSignalDMast() != null) { 699 signal = t.getSignalDMast(); 700 } else if (!t.getSignalD1Name().isEmpty()) { 701 signal = sh.getSignalHead(t.getSignalD1Name()); 702 } 703 } 704 } else //note: you have to do this after LayoutSlip 705 // because LayoutSlip extends LayoutTurnout 706 // (So a LayoutSlip would be an instance of LayoutTurnout.) 707 if (getRefLocation() instanceof LayoutTurnout) { //<== this includes LayoutSlips 708 LayoutTurnout t = (LayoutTurnout) getRefLocation(); 709 if (t.getSensorA() == sen) { 710 if (t.getSignalAMast() != null) { 711 signal = t.getSignalAMast(); 712 } else if (!t.getSignalA1Name().isEmpty()) { 713 signal = sh.getSignalHead(t.getSignalA1Name()); 714 } 715 } else if (t.getSensorB() == sen) { 716 if (t.getSignalBMast() != null) { 717 signal = t.getSignalBMast(); 718 } else if (!t.getSignalB1Name().isEmpty()) { 719 signal = sh.getSignalHead(t.getSignalB1Name()); 720 } 721 } else if (t.getSensorC() == sen) { 722 if (t.getSignalCMast() != null) { 723 signal = t.getSignalCMast(); 724 } else if (!t.getSignalC1Name().isEmpty()) { 725 signal = sh.getSignalHead(t.getSignalC1Name()); 726 } 727 } else if (t.getSensorD() == sen) { 728 if (t.getSignalDMast() != null) { 729 signal = t.getSignalDMast(); 730 } else if (!t.getSignalD1Name().isEmpty()) { 731 signal = sh.getSignalHead(t.getSignalD1Name()); 732 } 733 } 734 } else if (getRefLocation() instanceof LevelXing) { 735 LevelXing x = (LevelXing) getRefLocation(); 736 if (x.getSensorA() == sen) { 737 if (x.getSignalAMast() != null) { 738 signal = x.getSignalAMast(); 739 } else if (!x.getSignalAName().isEmpty()) { 740 signal = sh.getSignalHead(x.getSignalAName()); 741 } 742 } else if (x.getSensorB() == sen) { 743 if (x.getSignalBMast() != null) { 744 signal = x.getSignalBMast(); 745 } else if (!x.getSignalBName().isEmpty()) { 746 signal = sh.getSignalHead(x.getSignalBName()); 747 } 748 } else if (x.getSensorC() == sen) { 749 if (x.getSignalCMast() != null) { 750 signal = x.getSignalCMast(); 751 } else if (!x.getSignalCName().isEmpty()) { 752 signal = sh.getSignalHead(x.getSignalCName()); 753 } 754 } else if (x.getSensorD() == sen) { 755 if (x.getSignalDMast() != null) { 756 signal = x.getSignalDMast(); 757 } else if (!x.getSignalDName().isEmpty()) { 758 signal = sh.getSignalHead(x.getSignalDName()); 759 } 760 } 761 } 762 763 if (signal instanceof SignalMast) { 764 setSignalMast(((SignalMast) signal)); 765 } else if (signal instanceof SignalHead) { 766 setSignalHead(((SignalHead) signal)); 767 } 768 return signal; 769 } 770 771 @Override 772 public boolean equals(Object obj) { 773 if (obj == this) { 774 return true; 775 } 776 if (obj == null) { 777 return false; 778 } 779 780 if (!(getClass() == obj.getClass())) { 781 return false; 782 } else { 783 PointDetails tmp = (PointDetails) obj; 784 if (tmp.getFacing() != this.facing) { 785 return false; 786 } 787 if (!tmp.getProtecting().equals(this.protectingBlocks)) { 788 return false; 789 } 790 if (tmp.getPanel() != this.panel) { 791 return false; 792 } 793 } 794 return true; 795 } 796 797 @Override 798 public int hashCode() { 799 int hash = 7; 800 hash = 37 * hash + (this.panel != null ? this.panel.hashCode() : 0); 801 hash = 37 * hash + (this.facing != null ? this.facing.hashCode() : 0); 802 hash = 37 * hash + (this.protectingBlocks != null ? this.protectingBlocks.hashCode() : 0); 803 return hash; 804 } 805 806 java.beans.PropertyChangeSupport pcs = new java.beans.PropertyChangeSupport(this); 807 808 public synchronized void addPropertyChangeListener(java.beans.PropertyChangeListener l) { 809 pcs.addPropertyChangeListener(l); 810 } 811 812 public synchronized void removePropertyChangeListener(java.beans.PropertyChangeListener l) { 813 pcs.removePropertyChangeListener(l); 814 } 815 816 protected void firePropertyChange(String p, Object old, Object n) { 817 pcs.firePropertyChange(p, old, n); 818 } 819 820 private static final Logger log = LoggerFactory.getLogger(PointDetails.class); 821}