001package jmri.jmrit.display.layoutEditor; 002 003import java.awt.Color; 004import java.awt.Graphics2D; 005import java.awt.event.ActionEvent; 006import java.awt.geom.*; 007import java.util.List; 008 009import javax.annotation.CheckForNull; 010import javax.annotation.Nonnull; 011import javax.swing.*; 012 013import jmri.InstanceManager; 014import jmri.Turnout; 015import jmri.jmrit.display.layoutEditor.LayoutTurnout.TurnoutType; 016import jmri.jmrit.display.layoutEditor.blockRoutingTable.LayoutBlockRouteTableAction; 017import jmri.util.MathUtil; 018import jmri.util.swing.JmriJOptionPane; 019import jmri.util.swing.JmriMouseEvent; 020 021/** 022 * MVC View component for the LayoutSlip class. 023 * 024 * @author Bob Jacobsen Copyright (c) 2020 025 * 026 */ 027public class LayoutSlipView extends LayoutTurnoutView { 028 029 /** 030 * Constructor method. 031 * @param slip the layout sip to create view for. 032 * @param c 2D point. 033 * @param rot rotation. 034 * @param layoutEditor the layout editor. 035 */ 036 public LayoutSlipView(@Nonnull LayoutSlip slip, 037 Point2D c, double rot, 038 @Nonnull LayoutEditor layoutEditor) { 039 super(slip, c, rot, layoutEditor); 040 this.slip = slip; 041 042 dispA = new Point2D.Double(-20.0, 0.0); 043 pointA = MathUtil.add(getCoordsCenter(), dispA); 044 pointC = MathUtil.subtract(getCoordsCenter(), dispA); 045 dispB = new Point2D.Double(-14.0, 14.0); 046 pointB = MathUtil.add(getCoordsCenter(), dispB); 047 pointD = MathUtil.subtract(getCoordsCenter(), dispB); 048 049 rotateCoords(rot); 050 051 editor = new jmri.jmrit.display.layoutEditor.LayoutEditorDialogs.LayoutSlipEditor(layoutEditor); 052 } 053 054 final private LayoutSlip slip; 055 056 public int currentState = UNKNOWN; 057 058 public LayoutSlip getSlip() {return slip; } 059 // this should only be used for debugging... 060 @Override 061 public String toString() { 062 return String.format("LayoutSlip %s (%s)", getId(), getSlipStateString(getSlipState())); 063 } 064 065 public TurnoutType getSlipType() { 066 return slip.getSlipType(); 067 } 068 069 public int getSlipState() { 070 return slip.getSlipState(); 071 } 072 073 public String getTurnoutBName() { 074 return slip.getTurnoutBName(); 075 } 076 077 public Turnout getTurnoutB() { 078 return slip.getTurnoutB(); 079 } 080 081 public void setTurnoutB(@CheckForNull String tName) { 082 slip.setTurnoutB(tName); 083 } 084 085 /** 086 * {@inheritDoc} 087 */ 088 @Override 089 public LayoutTrack getConnection(HitPointType connectionType) throws jmri.JmriException { 090 return slip.getConnection(connectionType); 091 } 092 093 /** 094 * {@inheritDoc} 095 */ 096 @Override 097 public void setConnection(HitPointType connectionType, @CheckForNull LayoutTrack o, HitPointType type) throws jmri.JmriException { 098 slip.setConnection(connectionType, o, type); 099 } 100 101 public String getDisplayName() { 102 String name = "Slip " + getId(); 103 String tnA = getTurnoutName(); 104 String tnB = getTurnoutBName(); 105 if ((tnA != null) && !tnA.isEmpty()) { 106 name += " (" + tnA; 107 } 108 if ((tnB != null) && !tnB.isEmpty()) { 109 if (name.contains(" (")) { 110 name += ", "; 111 } else { 112 name += "("; 113 } 114 name += tnB; 115 } 116 if (name.contains("(")) { 117 name += ")"; 118 } 119 return name; 120 } 121 122 private String getSlipStateString(int slipState) { 123 return slip.getSlipStateString(slipState); 124 } 125 126 /** 127 * Toggle slip states if clicked on, physical turnout exists, and not 128 * disabled 129 * @param selectedPointType See {@link LayoutSlip#toggleState} for definition 130 */ 131 public void toggleState(HitPointType selectedPointType) { 132 slip.toggleState(selectedPointType); 133 } 134 135 /** 136 * is this turnout occupied? 137 * 138 * @return true if occupied 139 */ 140 private boolean isOccupied() { 141 return slip.isOccupied(); 142 } 143 144 @Override 145 public Point2D getCoordsA() { 146 return pointA; 147 } 148 149 @Override 150 public Point2D getCoordsB() { 151 return pointB; 152 } 153 154 @Override 155 public Point2D getCoordsC() { 156 return pointC; 157 } 158 159 @Override 160 public Point2D getCoordsD() { 161 return pointD; 162 } 163 164 Point2D getCoordsLeft() { 165 Point2D leftCenter = MathUtil.midPoint(getCoordsA(), getCoordsB()); 166 double circleRadius = LayoutEditor.SIZE * layoutEditor.getTurnoutCircleSize(); 167 double leftFract = circleRadius / getCoordsCenter().distance(leftCenter); 168 return MathUtil.lerp(getCoordsCenter(), leftCenter, leftFract); 169 } 170 171 Point2D getCoordsRight() { 172 Point2D rightCenter = MathUtil.midPoint(getCoordsC(), getCoordsD()); 173 double circleRadius = LayoutEditor.SIZE * layoutEditor.getTurnoutCircleSize(); 174 double rightFract = circleRadius / getCoordsCenter().distance(rightCenter); 175 return MathUtil.lerp(getCoordsCenter(), rightCenter, rightFract); 176 } 177 178 /** 179 * return the coordinates for the specified connection type 180 * 181 * @param connectionType the connection type 182 * @return the Point2D coordinates 183 */ 184 @Override 185 public Point2D getCoordsForConnectionType(HitPointType connectionType) { 186 Point2D result = getCoordsCenter(); 187 switch (connectionType) { 188 case SLIP_A: 189 result = getCoordsA(); 190 break; 191 case SLIP_B: 192 result = getCoordsB(); 193 break; 194 case SLIP_C: 195 result = getCoordsC(); 196 break; 197 case SLIP_D: 198 result = getCoordsD(); 199 break; 200 case SLIP_LEFT: 201 result = getCoordsLeft(); 202 break; 203 case SLIP_RIGHT: 204 result = getCoordsRight(); 205 break; 206 default: 207 log.error("{}.getCoordsForConnectionType({}); Invalid Connection Type", getName(), connectionType); // I18IN 208 } 209 return result; 210 } 211 212 /** 213 * {@inheritDoc} 214 */ 215 // just here for testing; should be removed when I'm done... 216 @Override 217 public Rectangle2D getBounds() { 218 return super.getBounds(); 219 } 220 221 @Override 222 public void updateBlockInfo() { 223 slip.updateBlockInfo(); 224 } 225 226 /** 227 * {@inheritDoc} 228 */ 229 @Override 230 protected HitPointType findHitPointType(@Nonnull Point2D hitPoint, boolean useRectangles, boolean requireUnconnected) { 231 HitPointType result = HitPointType.NONE; // assume point not on connection 232 233 if (!requireUnconnected) { 234 // calculate radius of turnout control circle 235 double circleRadius = LayoutEditor.SIZE * layoutEditor.getTurnoutCircleSize(); 236 237 // get left and right centers 238 Point2D leftCenter = getCoordsLeft(); 239 Point2D rightCenter = getCoordsRight(); 240 241 if (useRectangles) { 242 // calculate turnout's left control rectangle 243 Rectangle2D leftRectangle = layoutEditor.layoutEditorControlCircleRectAt(leftCenter); 244 if (leftRectangle.contains(hitPoint)) { 245 // point is in this turnout's left control rectangle 246 result = HitPointType.SLIP_LEFT; 247 } 248 Rectangle2D rightRectangle = layoutEditor.layoutEditorControlCircleRectAt(rightCenter); 249 if (rightRectangle.contains(hitPoint)) { 250 // point is in this turnout's right control rectangle 251 result = HitPointType.SLIP_RIGHT; 252 } 253 } else { 254 // check east/west turnout control circles 255 double leftDistance = hitPoint.distance(leftCenter); 256 double rightDistance = hitPoint.distance(rightCenter); 257 258 if ((leftDistance <= circleRadius) || (rightDistance <= circleRadius)) { 259 // mouse was pressed on this slip 260 result = (leftDistance < rightDistance) ? HitPointType.SLIP_LEFT : HitPointType.SLIP_RIGHT; 261 } 262 } 263 } 264 265 // have we found anything yet? 266 if (result == HitPointType.NONE) { 267 // rather than create rectangles for all the points below and 268 // see if the passed in point is in one of those rectangles 269 // we can create a rectangle for the passed in point and then 270 // test if any of the points below are in that rectangle instead. 271 Rectangle2D r = layoutEditor.layoutEditorControlRectAt(hitPoint); 272 273 if (!requireUnconnected || (getConnectA() == null)) { 274 // check the A connection point 275 if (r.contains(getCoordsA())) { 276 result = HitPointType.SLIP_A; 277 } 278 } 279 280 if (!requireUnconnected || (getConnectB() == null)) { 281 // check the B connection point 282 if (r.contains(getCoordsB())) { 283 result = HitPointType.SLIP_B; 284 } 285 } 286 287 if (!requireUnconnected || (getConnectC() == null)) { 288 // check the C connection point 289 if (r.contains(getCoordsC())) { 290 result = HitPointType.SLIP_C; 291 } 292 } 293 294 if (!requireUnconnected || (getConnectD() == null)) { 295 // check the D connection point 296 if (r.contains(getCoordsD())) { 297 result = HitPointType.SLIP_D; 298 } 299 } 300 } 301 return result; 302 } // findHitPointType 303 304 /* 305 * Modify coordinates methods 306 */ 307 /** 308 * set center coordinates 309 * 310 * @param p the coordinates to set 311 */ 312 @Override 313 public void setCoordsCenter(@Nonnull Point2D p) { 314 super.setCoordsCenter(p); 315 pointA = MathUtil.add(getCoordsCenter(), dispA); 316 pointB = MathUtil.add(getCoordsCenter(), dispB); 317 pointC = MathUtil.subtract(getCoordsCenter(), dispA); 318 pointD = MathUtil.subtract(getCoordsCenter(), dispB); 319 } 320 321 @Override 322 public void setCoordsA(@Nonnull Point2D p) { 323 pointA = p; 324 dispA = MathUtil.subtract(pointA, getCoordsCenter()); 325 pointC = MathUtil.subtract(getCoordsCenter(), dispA); 326 } 327 328 @Override 329 public void setCoordsB(@Nonnull Point2D p) { 330 pointB = p; 331 dispB = MathUtil.subtract(pointB, getCoordsCenter()); 332 pointD = MathUtil.subtract(getCoordsCenter(), dispB); 333 } 334 335 @Override 336 public void setCoordsC(@Nonnull Point2D p) { 337 pointC = p; 338 dispA = MathUtil.subtract(getCoordsCenter(), pointC); 339 pointA = MathUtil.add(getCoordsCenter(), dispA); 340 } 341 342 @Override 343 public void setCoordsD(@Nonnull Point2D p) { 344 pointD = p; 345 dispB = MathUtil.subtract(getCoordsCenter(), pointD); 346 pointB = MathUtil.add(getCoordsCenter(), dispB); 347 } 348 349 JPopupMenu popup = null; 350 351 /** 352 * {@inheritDoc} 353 */ 354 @Override 355 @Nonnull 356 protected JPopupMenu showPopup(@Nonnull JmriMouseEvent mouseEvent) { 357 if (popup != null) { 358 popup.removeAll(); 359 } else { 360 popup = new JPopupMenu(); 361 } 362 if (layoutEditor.isEditable()) { 363 String slipStateString = getSlipStateString(getSlipState()); 364 slipStateString = String.format(" (%s)", slipStateString); 365 366 JMenuItem jmi = null; 367 switch (getSlipType()) { 368 case SINGLE_SLIP: { 369 jmi = popup.add(Bundle.getMessage("MakeLabel", Bundle.getMessage("LayoutSingleSlip")) + getId() + slipStateString); 370 break; 371 } 372 case DOUBLE_SLIP: { 373 jmi = popup.add(Bundle.getMessage("MakeLabel", Bundle.getMessage("LayoutDoubleSlip")) + getId() + slipStateString); 374 break; 375 } 376 default: { 377 log.error("{}.showPopup(<mouseEvent>); Invalid slip type: {}", getName(), getSlipType()); // I18IN 378 } 379 } 380 if (jmi != null) { 381 jmi.setEnabled(false); 382 } 383 384 if (getTurnout() == null) { 385 jmi = popup.add(Bundle.getMessage("NoTurnout")); 386 } else { 387 String stateString = getTurnoutStateString(getTurnout().getKnownState()); 388 stateString = String.format(" (%s)", stateString); 389 jmi = popup.add(Bundle.getMessage("BeanNameTurnout") + ": " + getTurnoutName() + stateString); 390 } 391 jmi.setEnabled(false); 392 393 if (getTurnoutB() == null) { 394 jmi = popup.add(Bundle.getMessage("NoTurnout")); 395 } else { 396 String stateString = getTurnoutStateString(getTurnoutB().getKnownState()); 397 stateString = String.format(" (%s)", stateString); 398 jmi = popup.add(Bundle.getMessage("BeanNameTurnout") + ": " + getTurnoutBName() + stateString); 399 } 400 jmi.setEnabled(false); 401 402 boolean blockAssigned = false; 403 if (getBlockName().isEmpty()) { 404 jmi = popup.add(Bundle.getMessage("NoBlock")); 405 jmi.setEnabled(false); 406 } else { 407 blockAssigned = true; 408 409 jmi = popup.add(Bundle.getMessage("MakeLabel", Bundle.getMessage("Block_ID", "A")) + getLayoutBlock().getDisplayName()); 410 jmi.setEnabled(false); 411 412 // check if extra blocks have been entered 413 if ((getLayoutBlockB() != null) && (getLayoutBlockB() != getLayoutBlock())) { 414 jmi = popup.add(Bundle.getMessage("MakeLabel", Bundle.getMessage("Block_ID", "B")) + getLayoutBlockB().getDisplayName()); 415 jmi.setEnabled(false); 416 } 417 if ((getLayoutBlockC() != null) && (getLayoutBlockC() != getLayoutBlock())) { 418 jmi = popup.add(Bundle.getMessage("MakeLabel", Bundle.getMessage("Block_ID", "C")) + getLayoutBlockC().getDisplayName()); 419 jmi.setEnabled(false); 420 } 421 if ((getLayoutBlockD() != null) && (getLayoutBlockD() != getLayoutBlock())) { 422 jmi = popup.add(Bundle.getMessage("MakeLabel", Bundle.getMessage("Block_ID", "D")) + getLayoutBlockD().getDisplayName()); 423 jmi.setEnabled(false); 424 } 425 } 426 427 // if there are any track connections 428 if ((getConnectA() != null) || (getConnectB() != null) 429 || (getConnectC() != null) || (getConnectD() != null)) { 430 JMenu connectionsMenu = new JMenu(Bundle.getMessage("Connections")); // there is no pane opening (which is what ... implies) 431 if (getConnectA() != null) { 432 connectionsMenu.add(new AbstractAction(Bundle.getMessage("MakeLabel", "A") + getConnectA().getName()) { 433 @Override 434 public void actionPerformed(ActionEvent e) { 435 LayoutEditorFindItems lf = layoutEditor.getFinder(); 436 LayoutTrack lt = lf.findObjectByName(getConnectA().getName()); 437 // this shouldn't ever be null... however... 438 if (lt != null) { 439 LayoutTrackView ltv = layoutEditor.getLayoutTrackView(lt); 440 layoutEditor.setSelectionRect(ltv.getBounds()); 441 ltv.showPopup(); 442 } 443 } 444 }); 445 } 446 if (getConnectB() != null) { 447 connectionsMenu.add(new AbstractAction(Bundle.getMessage("MakeLabel", "B") + getConnectB().getName()) { 448 @Override 449 public void actionPerformed(ActionEvent e) { 450 LayoutEditorFindItems lf = layoutEditor.getFinder(); 451 LayoutTrack lt = lf.findObjectByName(getConnectB().getName()); 452 // this shouldn't ever be null... however... 453 if (lt != null) { 454 LayoutTrackView ltv = layoutEditor.getLayoutTrackView(lt); 455 layoutEditor.setSelectionRect(ltv.getBounds()); 456 ltv.showPopup(); 457 } 458 } 459 }); 460 } 461 if (getConnectC() != null) { 462 connectionsMenu.add(new AbstractAction(Bundle.getMessage("MakeLabel", "C") + getConnectC().getName()) { 463 @Override 464 public void actionPerformed(ActionEvent e) { 465 LayoutEditorFindItems lf = layoutEditor.getFinder(); 466 LayoutTrack lt = lf.findObjectByName(getConnectC().getName()); 467 // this shouldn't ever be null... however... 468 if (lt != null) { 469 LayoutTrackView ltv = layoutEditor.getLayoutTrackView(lt); 470 layoutEditor.setSelectionRect(ltv.getBounds()); 471 ltv.showPopup(); 472 } 473 } 474 }); 475 } 476 if (getConnectD() != null) { 477 connectionsMenu.add(new AbstractAction(Bundle.getMessage("MakeLabel", "D") + getConnectD().getName()) { 478 @Override 479 public void actionPerformed(ActionEvent e) { 480 LayoutEditorFindItems lf = layoutEditor.getFinder(); 481 LayoutTrack lt = lf.findObjectByName(getConnectD().getName()); 482 // this shouldn't ever be null... however... 483 if (lt != null) { 484 LayoutTrackView ltv = layoutEditor.getLayoutTrackView(lt); 485 layoutEditor.setSelectionRect(ltv.getBounds()); 486 ltv.showPopup(); 487 } 488 } 489 }); 490 } 491 popup.add(connectionsMenu); 492 } 493 494 popup.add(new JSeparator(JSeparator.HORIZONTAL)); 495 496 JCheckBoxMenuItem hiddenCheckBoxMenuItem = new JCheckBoxMenuItem(Bundle.getMessage("Hidden")); 497 hiddenCheckBoxMenuItem.setSelected(isHidden()); 498 popup.add(hiddenCheckBoxMenuItem); 499 hiddenCheckBoxMenuItem.addActionListener((java.awt.event.ActionEvent e1) -> { 500 JCheckBoxMenuItem o = (JCheckBoxMenuItem) e1.getSource(); 501 setHidden(o.isSelected()); 502 }); 503 504 JCheckBoxMenuItem cbmi = new JCheckBoxMenuItem(Bundle.getMessage("Disabled")); 505 cbmi.setSelected(isDisabled()); 506 popup.add(cbmi); 507 cbmi.addActionListener((java.awt.event.ActionEvent e2) -> { 508 JCheckBoxMenuItem o = (JCheckBoxMenuItem) e2.getSource(); 509 setDisabled(o.isSelected()); 510 }); 511 512 cbmi = new JCheckBoxMenuItem(Bundle.getMessage("DisabledWhenOccupied")); 513 cbmi.setSelected(isDisabledWhenOccupied()); 514 popup.add(cbmi); 515 cbmi.addActionListener((java.awt.event.ActionEvent e3) -> { 516 JCheckBoxMenuItem o = (JCheckBoxMenuItem) e3.getSource(); 517 setDisableWhenOccupied(o.isSelected()); 518 }); 519 520 popup.add(new AbstractAction(Bundle.getMessage("ButtonEdit")) { 521 @Override 522 public void actionPerformed(ActionEvent e) { 523 editor.editLayoutTrack(LayoutSlipView.this); 524 } 525 }); 526 popup.add(new AbstractAction(Bundle.getMessage("ButtonDelete")) { 527 @Override 528 public void actionPerformed(ActionEvent e) { 529 if (canRemove() && removeInlineLogixNG() 530 && layoutEditor.removeLayoutSlip(slip)) { 531 // Returned true if user did not cancel 532 remove(); 533 dispose(); 534 } 535 } 536 }); 537 if ((getConnectA() == null) && (getConnectB() == null) 538 && (getConnectC() == null) && (getConnectD() == null)) { 539 JMenuItem rotateItem = new JMenuItem(Bundle.getMessage("Rotate") + "..."); 540 popup.add(rotateItem); 541 rotateItem.addActionListener( 542 (ActionEvent event) -> { 543 boolean entering = true; 544 boolean error = false; 545 String newAngle = ""; 546 while (entering) { 547 // prompt for rotation angle 548 error = false; 549 newAngle = JmriJOptionPane.showInputDialog(layoutEditor, 550 Bundle.getMessage("MakeLabel", Bundle.getMessage("EnterRotation")),""); 551 if ( newAngle==null || newAngle.isEmpty()) { 552 return; // cancelled 553 } 554 double rot = 0.0; 555 try { 556 rot = Double.parseDouble(newAngle); 557 } catch (Exception e1) { 558 JmriJOptionPane.showMessageDialog(layoutEditor, Bundle.getMessage("Error3") 559 + " " + e1, Bundle.getMessage("ErrorTitle"), JmriJOptionPane.ERROR_MESSAGE); 560 error = true; 561 newAngle = ""; 562 } 563 if (!error) { 564 entering = false; 565 if (rot != 0.0) { 566 rotateCoords(rot); 567 layoutEditor.redrawPanel(); 568 } 569 } 570 } 571 } 572 ); 573 } 574 if ((getTurnout() != null) && (getTurnoutB() != null)) { 575 if (blockAssigned) { 576 AbstractAction ssaa = new AbstractAction(Bundle.getMessage("SetSignals")) { 577 @Override 578 public void actionPerformed(ActionEvent e) { 579 layoutEditor.getLETools().setSignalsAtSlipFromMenu( 580 slip, 581 getLayoutEditorToolBarPanel().signalIconEditor, 582 getLayoutEditorToolBarPanel().signalFrame); 583 } 584 }; 585 JMenu jm = new JMenu(Bundle.getMessage("SignalHeads")); 586 if (layoutEditor.getLETools().addLayoutSlipSignalHeadInfoToMenu( 587 slip, jm)) { 588 jm.add(ssaa); 589 popup.add(jm); 590 } else { 591 popup.add(ssaa); 592 } 593 594 } 595 596 final String[] boundaryBetween = getBlockBoundaries(); 597 boolean blockBoundaries = false; 598 599 for (int i = 0; i < 4; i++) { 600 if (boundaryBetween[i] != null) { 601 blockBoundaries = true; 602 } 603 } 604 if (blockBoundaries) { 605 popup.add(new AbstractAction(Bundle.getMessage("SetSignalMasts")) { 606 @Override 607 public void actionPerformed(ActionEvent e) { 608 layoutEditor.getLETools().setSignalMastsAtSlipFromMenu( 609 slip, 610 boundaryBetween, 611 getLayoutEditorToolBarPanel().signalFrame); 612 } 613 }); 614 popup.add(new AbstractAction(Bundle.getMessage("SetSensors")) { 615 @Override 616 public void actionPerformed(ActionEvent e) { 617 layoutEditor.getLETools().setSensorsAtSlipFromMenu( 618 slip, boundaryBetween, 619 getLayoutEditorToolBarPanel().sensorIconEditor, 620 getLayoutEditorToolBarPanel().sensorFrame); 621 } 622 }); 623 } 624 625 if (jmri.InstanceManager.getDefault(LayoutBlockManager.class).isAdvancedRoutingEnabled() 626 && blockAssigned) { 627 popup.add(new AbstractAction(Bundle.getMessage("ViewBlockRouting")) { 628 @Override 629 public void actionPerformed(ActionEvent event) { 630 AbstractAction routeTableAction = new LayoutBlockRouteTableAction("ViewRouting", getLayoutBlock()); 631 routeTableAction.actionPerformed(event); 632 } 633 }); 634 } 635 } 636 setAdditionalEditPopUpMenu(popup); 637 layoutEditor.setShowAlignmentMenu(popup); 638 addCommonPopupItems(mouseEvent, popup); 639 popup.show(mouseEvent.getComponent(), mouseEvent.getX(), mouseEvent.getY()); 640 } else if (!viewAdditionalMenu.isEmpty()) { 641 setAdditionalViewPopUpMenu(popup); 642 addCommonPopupItems(mouseEvent, popup); 643 popup.show(mouseEvent.getComponent(), mouseEvent.getX(), mouseEvent.getY()); 644 } 645 return popup; 646 } // showPopup 647 648 @Override 649 public String[] getBlockBoundaries() { 650 return slip.getBlockBoundaries(); 651 } 652 653 /** 654 * Clean up when this object is no longer needed. Should not be called while 655 * the object is still displayed; see remove() 656 */ 657 @Override 658 public void dispose() { 659 if (popup != null) { 660 popup.removeAll(); 661 } 662 popup = null; 663 } 664 665 /** 666 * Removes this object from display and persistance 667 */ 668 @Override 669 public void remove() { 670 slip.remove(); 671 } 672 673 674 public int getTurnoutState(@Nonnull Turnout turn, int state) { 675 return slip.getTurnoutState(turn, state); 676 } 677 678 public int getTurnoutState(int state) { 679 return slip.getTurnoutState(state); 680 } 681 682 public int getTurnoutBState(int state) { 683 return slip.getTurnoutBState(state); 684 } 685 686 public void setTurnoutStates(int state, @Nonnull String turnStateA, @Nonnull String turnStateB) { 687 slip.setTurnoutStates(state, turnStateA, turnStateB); 688 } 689 690 /** 691 * Check if either turnout is inconsistent. This is used to create an 692 * alternate slip image. 693 * 694 * @return true if either turnout is inconsistent. 695 */ 696 private boolean isTurnoutInconsistent() { 697 return slip.isTurnoutInconsistent(); 698 } 699 700 @Override 701 protected void draw1(Graphics2D g2, boolean drawMain, boolean isBlock) { 702 Point2D pA = getCoordsA(); 703 Point2D pB = getCoordsB(); 704 Point2D pC = getCoordsC(); 705 Point2D pD = getCoordsD(); 706 707 boolean mainlineA = isMainlineA(); 708 boolean mainlineB = isMainlineB(); 709 boolean mainlineC = isMainlineC(); 710 boolean mainlineD = isMainlineD(); 711 712 boolean drawUnselectedLeg = layoutEditor.isTurnoutDrawUnselectedLeg() 713 || isTurnoutInconsistent(); 714 715 int slipState = getSlipState(); 716 717 Color color = g2.getColor(); 718 719 // if this isn't a block line all these will be the same color 720 Color colorA = color, colorB = color, colorC = color, colorD = color; 721 722 if (isBlock) { 723 LayoutBlock layoutBlockA = getLayoutBlock(); 724 colorA = (layoutBlockA != null) ? layoutBlockA.getBlockTrackColor() : color; 725 LayoutBlock layoutBlockB = getLayoutBlockB(); 726 colorB = (layoutBlockB != null) ? layoutBlockB.getBlockTrackColor() : color; 727 LayoutBlock layoutBlockC = getLayoutBlockC(); 728 colorC = (layoutBlockC != null) ? layoutBlockC.getBlockTrackColor() : color; 729 LayoutBlock layoutBlockD = getLayoutBlockD(); 730 colorD = (layoutBlockD != null) ? layoutBlockD.getBlockTrackColor() : color; 731 732 if (slipState == STATE_AC) { 733 colorA = (layoutBlockA != null) ? layoutBlockA.getBlockColor() : color; 734 colorC = (layoutBlockC != null) ? layoutBlockC.getBlockColor() : color; 735 } else if (slipState == STATE_BD) { 736 colorB = (layoutBlockB != null) ? layoutBlockB.getBlockColor() : color; 737 colorD = (layoutBlockD != null) ? layoutBlockD.getBlockColor() : color; 738 } else if (slipState == STATE_AD) { 739 colorA = (layoutBlockA != null) ? layoutBlockA.getBlockColor() : color; 740 colorD = (layoutBlockD != null) ? layoutBlockD.getBlockColor() : color; 741 } else if (slipState == STATE_BC) { 742 colorB = (layoutBlockB != null) ? layoutBlockB.getBlockColor() : color; 743 colorC = (layoutBlockC != null) ? layoutBlockC.getBlockColor() : color; 744 } 745 } 746 Point2D oneForthPointAC = MathUtil.oneFourthPoint(pA, pC); 747 Point2D oneThirdPointAC = MathUtil.oneThirdPoint(pA, pC); 748 Point2D midPointAC = MathUtil.midPoint(pA, pC); 749 Point2D twoThirdsPointAC = MathUtil.twoThirdsPoint(pA, pC); 750 Point2D threeFourthsPointAC = MathUtil.threeFourthsPoint(pA, pC); 751 752 Point2D oneForthPointBD = MathUtil.oneFourthPoint(pB, pD); 753 Point2D oneThirdPointBD = MathUtil.oneThirdPoint(pB, pD); 754 Point2D midPointBD = MathUtil.midPoint(pB, pD); 755 Point2D twoThirdsPointBD = MathUtil.twoThirdsPoint(pB, pD); 756 Point2D threeFourthsPointBD = MathUtil.threeFourthsPoint(pB, pD); 757 758 Point2D midPointAD = MathUtil.midPoint(oneThirdPointAC, twoThirdsPointBD); 759 Point2D midPointBC = MathUtil.midPoint(oneThirdPointBD, twoThirdsPointAC); 760 761 if (slipState == STATE_AD) { 762 // draw A<===>D 763 if (drawMain == mainlineA) { 764 g2.setColor(colorA); 765 g2.draw(new Line2D.Double(pA, oneThirdPointAC)); 766 g2.draw(new Line2D.Double(oneThirdPointAC, midPointAD)); 767 } 768 if (drawMain == mainlineD) { 769 g2.setColor(colorD); 770 g2.draw(new Line2D.Double(midPointAD, twoThirdsPointBD)); 771 g2.draw(new Line2D.Double(twoThirdsPointBD, pD)); 772 } 773 } else if (slipState == STATE_AC) { 774 // draw A<===>C 775 if (drawMain == mainlineA) { 776 g2.setColor(colorA); 777 g2.draw(new Line2D.Double(pA, oneThirdPointAC)); 778 g2.draw(new Line2D.Double(oneThirdPointAC, midPointAC)); 779 } 780 if (drawMain == mainlineC) { 781 g2.setColor(colorC); 782 g2.draw(new Line2D.Double(midPointAC, twoThirdsPointAC)); 783 g2.draw(new Line2D.Double(twoThirdsPointAC, pC)); 784 } 785 } else if (slipState == STATE_BD) { 786 // draw B<===>D 787 if (drawMain == mainlineB) { 788 g2.setColor(colorB); 789 g2.draw(new Line2D.Double(pB, oneThirdPointBD)); 790 g2.draw(new Line2D.Double(oneThirdPointBD, midPointBD)); 791 } 792 if (drawMain == mainlineD) { 793 g2.setColor(colorD); 794 g2.draw(new Line2D.Double(midPointBD, twoThirdsPointBD)); 795 g2.draw(new Line2D.Double(twoThirdsPointBD, pD)); 796 } 797 } else if (slipState == STATE_BC) { 798 if (getTurnoutType() == TurnoutType.DOUBLE_SLIP) { 799 // draw B<===>C 800 if (drawMain == mainlineB) { 801 g2.setColor(colorB); 802 g2.draw(new Line2D.Double(pB, oneThirdPointBD)); 803 g2.draw(new Line2D.Double(oneThirdPointBD, midPointBC)); 804 } 805 if (drawMain == mainlineC) { 806 g2.setColor(colorC); 807 g2.draw(new Line2D.Double(midPointBC, twoThirdsPointAC)); 808 g2.draw(new Line2D.Double(twoThirdsPointAC, pC)); 809 } 810 } // DOUBLE_SLIP 811 } 812 813 if (!isBlock || drawUnselectedLeg) { 814 if (slipState == STATE_AC) { 815 if (drawMain == mainlineB) { 816 g2.setColor(colorB); 817 g2.draw(new Line2D.Double(pB, oneForthPointBD)); 818 } 819 if (drawMain == mainlineD) { 820 g2.setColor(colorD); 821 g2.draw(new Line2D.Double(threeFourthsPointBD, pD)); 822 } 823 } else if (slipState == STATE_BD) { 824 if (drawMain == mainlineA) { 825 g2.setColor(colorA); 826 g2.draw(new Line2D.Double(pA, oneForthPointAC)); 827 } 828 if (drawMain == mainlineC) { 829 g2.setColor(colorC); 830 g2.draw(new Line2D.Double(threeFourthsPointAC, pC)); 831 } 832 } else if (slipState == STATE_AD) { 833 if (drawMain == mainlineB) { 834 g2.setColor(colorB); 835 g2.draw(new Line2D.Double(pB, oneForthPointBD)); 836 } 837 if (drawMain == mainlineC) { 838 g2.setColor(colorC); 839 g2.draw(new Line2D.Double(threeFourthsPointAC, pC)); 840 } 841 } else if (slipState == STATE_BC) { 842 if (drawMain == mainlineA) { 843 g2.setColor(colorA); 844 g2.draw(new Line2D.Double(pA, oneForthPointAC)); 845 } 846 if (drawMain == mainlineD) { 847 g2.setColor(colorD); 848 g2.draw(new Line2D.Double(threeFourthsPointBD, pD)); 849 } 850 } else { 851 if (drawMain == mainlineA) { 852 g2.setColor(colorA); 853 g2.draw(new Line2D.Double(pA, oneForthPointAC)); 854 } 855 if (drawMain == mainlineB) { 856 g2.setColor(colorB); 857 g2.draw(new Line2D.Double(pB, oneForthPointBD)); 858 } 859 if (drawMain == mainlineC) { 860 g2.setColor(colorC); 861 g2.draw(new Line2D.Double(threeFourthsPointAC, pC)); 862 } 863 if (drawMain == mainlineD) { 864 g2.setColor(colorD); 865 g2.draw(new Line2D.Double(threeFourthsPointBD, pD)); 866 } 867 } 868 } 869 } // draw1 870 871 /** 872 * {@inheritDoc} 873 */ 874 @Override 875 protected void draw2(Graphics2D g2, boolean drawMain, float railDisplacement) { 876 Point2D pA = getCoordsA(); 877 Point2D pB = getCoordsB(); 878 Point2D pC = getCoordsC(); 879 Point2D pD = getCoordsD(); 880 Point2D pM = getCoordsCenter(); 881 882 Point2D vAC = MathUtil.normalize(MathUtil.subtract(pC, pA), railDisplacement); 883 double dirAC_DEG = MathUtil.computeAngleDEG(pA, pC); 884 Point2D vACo = MathUtil.orthogonal(vAC); 885 Point2D pAL = MathUtil.subtract(pA, vACo); 886 Point2D pAR = MathUtil.add(pA, vACo); 887 Point2D pCL = MathUtil.subtract(pC, vACo); 888 Point2D pCR = MathUtil.add(pC, vACo); 889 890 Point2D vBD = MathUtil.normalize(MathUtil.subtract(pD, pB), railDisplacement); 891 double dirBD_DEG = MathUtil.computeAngleDEG(pB, pD); 892 Point2D vBDo = MathUtil.orthogonal(vBD); 893 Point2D pBL = MathUtil.subtract(pB, vBDo); 894 Point2D pBR = MathUtil.add(pB, vBDo); 895 Point2D pDL = MathUtil.subtract(pD, vBDo); 896 Point2D pDR = MathUtil.add(pD, vBDo); 897 898 double deltaDEG = MathUtil.absDiffAngleDEG(dirAC_DEG, dirBD_DEG); 899 double deltaRAD = Math.toRadians(deltaDEG); 900 901 double hypotV = railDisplacement / Math.cos((Math.PI - deltaRAD) / 2.0); 902 double hypotK = railDisplacement / Math.cos(deltaRAD / 2.0); 903 904 log.debug("dir AC: {}, BD: {}, diff: {}", dirAC_DEG, dirBD_DEG, deltaDEG); 905 906 Point2D vDisK = MathUtil.normalize(MathUtil.subtract(vAC, vBD), hypotK); 907 Point2D vDisV = MathUtil.normalize(MathUtil.orthogonal(vDisK), hypotV); 908 Point2D pKL = MathUtil.subtract(pM, vDisK); 909 Point2D pKR = MathUtil.add(pM, vDisK); 910 Point2D pVL = MathUtil.add(pM, vDisV); 911 Point2D pVR = MathUtil.subtract(pM, vDisV); 912 913 // this is the vector (rail gaps) for the diamond parts 914 double railGap = 2.0 / Math.sin(deltaRAD); 915 Point2D vAC2 = MathUtil.normalize(vAC, railGap); 916 Point2D vBD2 = MathUtil.normalize(vBD, railGap); 917 // KR and VR toward A, KL and VL toward C 918 Point2D pKRtA = MathUtil.subtract(pKR, vAC2); 919 Point2D pVRtA = MathUtil.subtract(pVR, vAC2); 920 Point2D pKLtC = MathUtil.add(pKL, vAC2); 921 Point2D pVLtC = MathUtil.add(pVL, vAC2); 922 923 // VR and KL toward B, KR and VL toward D 924 Point2D pVRtB = MathUtil.subtract(pVR, vBD2); 925 Point2D pKLtB = MathUtil.subtract(pKL, vBD2); 926 Point2D pKRtD = MathUtil.add(pKR, vBD2); 927 Point2D pVLtD = MathUtil.add(pVL, vBD2); 928 929 // outer (closed) switch points 930 Point2D pAPL = MathUtil.add(pAL, MathUtil.subtract(pVL, pAR)); 931 Point2D pBPR = MathUtil.add(pBR, MathUtil.subtract(pVL, pBL)); 932 Point2D pCPR = MathUtil.add(pCR, MathUtil.subtract(pVR, pCL)); 933 Point2D pDPL = MathUtil.add(pDL, MathUtil.subtract(pVR, pDR)); 934 935 // this is the vector (rail gaps) for the inner (open) switch points 936 Point2D vACo2 = MathUtil.normalize(vACo, 2.0); 937 Point2D vBDo2 = MathUtil.normalize(vBDo, 2.0); 938 Point2D pASL = MathUtil.add(pAPL, vACo2); 939 Point2D pBSR = MathUtil.subtract(pBPR, vBDo2); 940 Point2D pCSR = MathUtil.subtract(pCPR, vACo2); 941 Point2D pDSL = MathUtil.add(pDPL, vBDo2); 942 943 Point2D pVLP = MathUtil.add(pVLtD, vAC2); 944 Point2D pVRP = MathUtil.subtract(pVRtA, vBD2); 945 946 Point2D pKLH = MathUtil.midPoint(pM, pKL); 947 Point2D pKRH = MathUtil.midPoint(pM, pKR); 948 949 boolean mainlineA = isMainlineA(); 950 boolean mainlineB = isMainlineB(); 951 boolean mainlineC = isMainlineC(); 952 boolean mainlineD = isMainlineD(); 953 954 if (drawMain == mainlineA) { 955 g2.draw(new Line2D.Double(pAR, pVL)); 956 g2.draw(new Line2D.Double(pVLtD, pKLtB)); 957 GeneralPath path = new GeneralPath(); 958 path.moveTo(pAL.getX(), pAL.getY()); 959 path.lineTo(pAPL.getX(), pAPL.getY()); 960 path.quadTo(pKL.getX(), pKL.getY(), pDPL.getX(), pDPL.getY()); 961 g2.draw(path); 962 } 963 if (drawMain == mainlineB) { 964 g2.draw(new Line2D.Double(pBL, pVL)); 965 g2.draw(new Line2D.Double(pVLtC, pKRtA)); 966 if (getTurnoutType() == TurnoutType.DOUBLE_SLIP) { 967 GeneralPath path = new GeneralPath(); 968 path.moveTo(pBR.getX(), pBR.getY()); 969 path.lineTo(pBPR.getX(), pBPR.getY()); 970 path.quadTo(pKR.getX(), pKR.getY(), pCPR.getX(), pCPR.getY()); 971 g2.draw(path); 972 } else { 973 g2.draw(new Line2D.Double(pBR, pKR)); 974 } 975 } 976 if (drawMain == mainlineC) { 977 g2.draw(new Line2D.Double(pCL, pVR)); 978 g2.draw(new Line2D.Double(pVRtB, pKRtD)); 979 if (getTurnoutType() == TurnoutType.DOUBLE_SLIP) { 980 GeneralPath path = new GeneralPath(); 981 path.moveTo(pCR.getX(), pCR.getY()); 982 path.lineTo(pCPR.getX(), pCPR.getY()); 983 path.quadTo(pKR.getX(), pKR.getY(), pBPR.getX(), pBPR.getY()); 984 g2.draw(path); 985 } else { 986 g2.draw(new Line2D.Double(pCR, pKR)); 987 } 988 } 989 if (drawMain == mainlineD) { 990 g2.draw(new Line2D.Double(pDR, pVR)); 991 g2.draw(new Line2D.Double(pVRtA, pKLtC)); 992 GeneralPath path = new GeneralPath(); 993 path.moveTo(pDL.getX(), pDL.getY()); 994 path.lineTo(pDPL.getX(), pDPL.getY()); 995 path.quadTo(pKL.getX(), pKL.getY(), pAPL.getX(), pAPL.getY()); 996 g2.draw(path); 997 } 998 999 int slipState = getSlipState(); 1000 if (slipState == STATE_AD) { 1001 if (drawMain == mainlineA) { 1002 g2.draw(new Line2D.Double(pASL, pKL)); 1003 g2.draw(new Line2D.Double(pVLP, pKLH)); 1004 } 1005 if (drawMain == mainlineB) { 1006 g2.draw(new Line2D.Double(pBPR, pKR)); 1007 g2.draw(new Line2D.Double(pVLtC, pKRH)); 1008 } 1009 if (drawMain == mainlineC) { 1010 g2.draw(new Line2D.Double(pCPR, pKR)); 1011 g2.draw(new Line2D.Double(pVRtB, pKRH)); 1012 } 1013 if (drawMain == mainlineD) { 1014 g2.draw(new Line2D.Double(pDSL, pKL)); 1015 g2.draw(new Line2D.Double(pVRP, pKLH)); 1016 } 1017 } else if (slipState == STATE_AC) { 1018 if (drawMain == mainlineA) { 1019 g2.draw(new Line2D.Double(pAPL, pKL)); 1020 g2.draw(new Line2D.Double(pVLtD, pKLH)); 1021 } 1022 if (drawMain == mainlineB) { 1023 g2.draw(new Line2D.Double(pBSR, pKR)); 1024 g2.draw(new Line2D.Double(pVLP, pKRH)); 1025 } 1026 if (drawMain == mainlineC) { 1027 g2.draw(new Line2D.Double(pCPR, pKR)); 1028 g2.draw(new Line2D.Double(pVRtB, pKRH)); 1029 } 1030 if (drawMain == mainlineD) { 1031 g2.draw(new Line2D.Double(pDSL, pKL)); 1032 g2.draw(new Line2D.Double(pVRP, pKLH)); 1033 } 1034 } else if (slipState == STATE_BD) { 1035 if (drawMain == mainlineA) { 1036 g2.draw(new Line2D.Double(pASL, pKL)); 1037 g2.draw(new Line2D.Double(pVLP, pKLH)); 1038 } 1039 if (drawMain == mainlineB) { 1040 g2.draw(new Line2D.Double(pBPR, pKR)); 1041 g2.draw(new Line2D.Double(pVLtC, pKRH)); 1042 } 1043 if (drawMain == mainlineC) { 1044 g2.draw(new Line2D.Double(pCSR, pKR)); 1045 g2.draw(new Line2D.Double(pVRP, pKRH)); 1046 } 1047 if (drawMain == mainlineD) { 1048 g2.draw(new Line2D.Double(pDPL, pKL)); 1049 g2.draw(new Line2D.Double(pVRtA, pKLH)); 1050 } 1051 } else if ((getTurnoutType() == TurnoutType.DOUBLE_SLIP) 1052 && (slipState == STATE_BC)) { 1053 if (drawMain == mainlineA) { 1054 g2.draw(new Line2D.Double(pAPL, pKL)); 1055 g2.draw(new Line2D.Double(pVLtD, pKLH)); 1056 } 1057 if (drawMain == mainlineB) { 1058 g2.draw(new Line2D.Double(pBSR, pKR)); 1059 g2.draw(new Line2D.Double(pVLP, pKRH)); 1060 } 1061 if (drawMain == mainlineC) { 1062 g2.draw(new Line2D.Double(pCSR, pKR)); 1063 g2.draw(new Line2D.Double(pVRP, pKRH)); 1064 } 1065 if (drawMain == mainlineD) { 1066 g2.draw(new Line2D.Double(pDPL, pKL)); 1067 g2.draw(new Line2D.Double(pVRtA, pKLH)); 1068 } 1069 } // DOUBLE_SLIP 1070 } // draw2 1071 1072 /** 1073 * {@inheritDoc} 1074 */ 1075 @Override 1076 protected void highlightUnconnected(Graphics2D g2, HitPointType specificType) { 1077 if (((specificType == HitPointType.NONE) || (specificType == HitPointType.SLIP_A)) 1078 && (getConnectA() == null)) { 1079 g2.fill(trackControlCircleAt(getCoordsA())); 1080 } 1081 1082 if (((specificType == HitPointType.NONE) || (specificType == HitPointType.SLIP_B)) 1083 && (getConnectB() == null)) { 1084 g2.fill(trackControlCircleAt(getCoordsB())); 1085 } 1086 1087 if (((specificType == HitPointType.NONE) || (specificType == HitPointType.SLIP_C)) 1088 && (getConnectC() == null)) { 1089 g2.fill(trackControlCircleAt(getCoordsC())); 1090 } 1091 1092 if (((specificType == HitPointType.NONE) || (specificType == HitPointType.SLIP_D)) 1093 && (getConnectD() == null)) { 1094 g2.fill(trackControlCircleAt(getCoordsD())); 1095 } 1096 } 1097 1098 @Override 1099 protected void drawTurnoutControls(Graphics2D g2) { 1100 if (!isDisabled() && !(isDisabledWhenOccupied() && isOccupied())) { 1101 int stateA = UNKNOWN; 1102 Turnout toA = getTurnout(); 1103 if (toA != null) { 1104 stateA = toA.getKnownState(); 1105 } 1106 1107 Color foregroundColor = g2.getColor(); 1108 Color backgroundColor = g2.getBackground(); 1109 1110 if (stateA == Turnout.THROWN) { 1111 g2.setColor(backgroundColor); 1112 } else if (stateA != Turnout.CLOSED) { 1113 g2.setColor(foregroundColor); 1114 } 1115 Point2D leftCircleCenter = getCoordsLeft(); 1116 if (layoutEditor.isTurnoutFillControlCircles()) { 1117 g2.fill(trackControlCircleAt(leftCircleCenter)); 1118 } else { 1119 g2.draw(trackControlCircleAt(leftCircleCenter)); 1120 } 1121 if (stateA != Turnout.CLOSED) { 1122 g2.setColor(foregroundColor); 1123 } 1124 1125 int stateB = UNKNOWN; 1126 Turnout toB = getTurnoutB(); 1127 if (toB != null) { 1128 stateB = toB.getKnownState(); 1129 } 1130 1131 if (stateB == Turnout.THROWN) { 1132 g2.setColor(backgroundColor); 1133 } else if (stateB != Turnout.CLOSED) { 1134 g2.setColor(foregroundColor); 1135 } 1136 // drawHidden left/right turnout control circles 1137 Point2D rightCircleCenter = getCoordsRight(); 1138 if (layoutEditor.isTurnoutFillControlCircles()) { 1139 g2.fill(trackControlCircleAt(rightCircleCenter)); 1140 } else { 1141 g2.draw(trackControlCircleAt(rightCircleCenter)); 1142 } 1143 if (stateB != Turnout.CLOSED) { 1144 g2.setColor(foregroundColor); 1145 } 1146 } 1147 } // drawTurnoutControls 1148 1149 public static class TurnoutState { 1150 1151 private int turnoutA = Turnout.CLOSED; 1152 private int turnoutB = Turnout.CLOSED; 1153 private JComboBox<String> turnoutABox; 1154 private JComboBox<String> turnoutBBox; 1155 1156 TurnoutState(int turnoutA, int turnoutB) { 1157 this.turnoutA = turnoutA; 1158 this.turnoutB = turnoutB; 1159 } 1160 1161 public int getTurnoutAState() { 1162 return turnoutA; 1163 } 1164 1165 public int getTurnoutBState() { 1166 return turnoutB; 1167 } 1168 1169 public void setTurnoutAState(int state) { 1170 turnoutA = state; 1171 } 1172 1173 public void setTurnoutBState(int state) { 1174 turnoutB = state; 1175 } 1176 1177 public JComboBox<String> getComboA() { 1178 if (turnoutABox == null) { 1179 String[] state = new String[]{InstanceManager.turnoutManagerInstance().getClosedText(), 1180 InstanceManager.turnoutManagerInstance().getThrownText()}; 1181 turnoutABox = new JComboBox<>(state); 1182 if (turnoutA == Turnout.THROWN) { 1183 turnoutABox.setSelectedIndex(1); 1184 } 1185 } 1186 return turnoutABox; 1187 } 1188 1189 public JComboBox<String> getComboB() { 1190 if (turnoutBBox == null) { 1191 String[] state = new String[]{InstanceManager.turnoutManagerInstance().getClosedText(), 1192 InstanceManager.turnoutManagerInstance().getThrownText()}; 1193 turnoutBBox = new JComboBox<>(state); 1194 if (turnoutB == Turnout.THROWN) { 1195 turnoutBBox.setSelectedIndex(1); 1196 } 1197 } 1198 return turnoutBBox; 1199 } 1200 1201 public int getTestTurnoutAState() { 1202 int result = Turnout.THROWN; 1203 if (turnoutABox != null) { 1204 if (turnoutABox.getSelectedIndex() == 0) { 1205 result = Turnout.CLOSED; 1206 } 1207 } 1208 return result; 1209 } 1210 1211 public int getTestTurnoutBState() { 1212 int result = Turnout.THROWN; 1213 if (turnoutBBox != null) { 1214 if (turnoutBBox.getSelectedIndex() == 0) { 1215 result = Turnout.CLOSED; 1216 } 1217 } 1218 return result; 1219 } 1220 1221 public void updateStatesFromCombo() { 1222 if ((turnoutABox != null) && (turnoutBBox != null)) { 1223 turnoutA = getTestTurnoutAState(); 1224 turnoutB = getTestTurnoutBState(); 1225 } 1226 } 1227 1228 @Override 1229 public boolean equals(Object object) { 1230 if (this == object) { 1231 return true; 1232 } 1233 if (object == null) { 1234 return false; 1235 } 1236 if (!(object instanceof TurnoutState)) { 1237 return false; 1238 } 1239 TurnoutState tso = (TurnoutState) object; 1240 1241 return ((getTurnoutAState() == tso.getTurnoutAState()) 1242 && (getTurnoutBState() == tso.getTurnoutBState())); 1243 } 1244 1245 /** 1246 * Hash on the header 1247 */ 1248 @Override 1249 public int hashCode() { 1250 int result = 7; 1251 result = (37 * result) + getTurnoutAState(); 1252 result = (37 * result) + getTurnoutBState(); 1253 1254 return result; 1255 } 1256 1257 } // class TurnoutState 1258 1259 /* 1260 this is used by ConnectivityUtil to determine the turnout state necessary to get from prevLayoutBlock ==> currLayoutBlock ==> nextLayoutBlock 1261 */ 1262 @Override 1263 protected int getConnectivityStateForLayoutBlocks( 1264 @CheckForNull LayoutBlock thisLayoutBlock, 1265 @CheckForNull LayoutBlock prevLayoutBlock, 1266 @CheckForNull LayoutBlock nextLayoutBlock, 1267 boolean suppress) { 1268 1269 return slip.getConnectivityStateForLayoutBlocks(thisLayoutBlock, 1270 prevLayoutBlock, nextLayoutBlock, 1271 suppress); 1272 } 1273 1274 /* 1275 * {@inheritDoc} 1276 */ 1277 @Override 1278 public void reCheckBlockBoundary() { 1279 slip.reCheckBlockBoundary(); 1280 } 1281 1282 /* 1283 * {@inheritDoc} 1284 */ 1285 @Override 1286 @Nonnull 1287 protected List<LayoutConnectivity> getLayoutConnectivity() { 1288 return slip.getLayoutConnectivity(); 1289 } 1290 1291 /** 1292 * {@inheritDoc} 1293 */ 1294 @Override 1295 public List<HitPointType> checkForFreeConnections() { 1296 return slip.checkForFreeConnections(); 1297 } 1298 1299 // NOTE: LayoutSlip uses the checkForNonContiguousBlocks 1300 // and collectContiguousTracksNamesInBlockNamed methods 1301 // inherited from LayoutTurnout 1302 // 1303 private final static org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(LayoutSlipView.class); 1304}