001package jmri.jmrit.display.layoutEditor; 002 003import java.awt.*; 004import java.awt.event.*; 005import java.awt.geom.Point2D; 006import java.awt.geom.Rectangle2D; 007import java.text.MessageFormat; 008import java.util.List; 009import java.util.*; 010 011import javax.annotation.*; 012import javax.swing.*; 013 014import jmri.*; 015import jmri.jmrit.display.EditorManager; 016import jmri.jmrit.display.layoutEditor.PositionablePoint.PointType; 017import jmri.jmrit.signalling.SignallingGuiTools; 018import jmri.util.*; 019import jmri.util.swing.JCBHandle; 020import jmri.util.swing.JmriColorChooser; 021import jmri.util.swing.JmriMouseEvent; 022 023/** 024 * MVC View component for the PositionablePoint class. 025 * 026 * @author Bob Jacobsen Copyright (c) 2020 027 * 028 * <p> 029 * Arrows and bumpers are visual, presentation aspects handled in the View. 030 */ 031public class PositionablePointView extends LayoutTrackView { 032 033 protected NamedBeanHandle<SignalHead> signalEastHeadNamed = null; // signal head for east (south) bound trains 034 protected NamedBeanHandle<SignalHead> signalWestHeadNamed = null; // signal head for west (north) bound trains 035 036 private NamedBeanHandle<SignalMast> eastBoundSignalMastNamed = null; 037 private NamedBeanHandle<SignalMast> westBoundSignalMastNamed = null; 038 /* We use a namedbeanhandle for the sensors, even though we only store the name here, 039 this is so that we can keep up with moves and changes of userNames */ 040 private NamedBeanHandle<Sensor> eastBoundSensorNamed = null; 041 private NamedBeanHandle<Sensor> westBoundSensorNamed = null; 042 043 /** 044 * constructor method. 045 * 046 * @param point the positionable point. 047 * @param c location to display the positionable point 048 * @param layoutEditor for access to tools 049 */ 050 public PositionablePointView(@Nonnull PositionablePoint point, 051 Point2D c, 052 @Nonnull LayoutEditor layoutEditor) { 053 super(point, c, layoutEditor); 054 this.positionablePoint = point; 055 } 056 057 final private PositionablePoint positionablePoint; 058 059 public PositionablePoint getPoint() { 060 return positionablePoint; 061 } 062 063 // this should only be used for debugging... 064 @Override 065 public String toString() { 066 String result = "PositionalablePoint"; 067 switch (getType()) { 068 case ANCHOR: { 069 result = "Anchor"; 070 break; 071 } 072 case END_BUMPER: { 073 result = "End Bumper"; 074 break; 075 } 076 case EDGE_CONNECTOR: { 077 result = "Edge Connector"; 078 break; 079 } 080 default: { 081 result = "Unknown type (" + getType() + ")"; 082 break; 083 } 084 } 085 return result + " '" + getName() + "'"; 086 } 087 088 /** 089 * Accessor methods 090 * 091 * @return Type enum for this Positionable Point 092 */ 093 public PointType getType() { 094 return positionablePoint.getType(); 095 } 096 097 public void setType(PointType newType) { 098 positionablePoint.setType(newType); 099 100 // (temporary) we keep this echo here until we figure out where arrow info lives 101 if (getType() != newType) { 102 switch (newType) { 103 default: 104 case ANCHOR: { 105 setTypeAnchor(); 106 break; 107 } 108 case END_BUMPER: { 109 setTypeEndBumper(); 110 break; 111 } 112 case EDGE_CONNECTOR: { 113 setTypeEdgeConnector(); 114 break; 115 } 116 } 117 layoutEditor.repaint(); 118 } 119 } 120 121 private void setTypeAnchor() { 122 setIdent(layoutEditor.getFinder().uniqueName("A", 1)); 123 124 // type = PointType.ANCHOR; 125 positionablePoint.setTypeAnchor(); 126 127 if (getConnect1() != null) { 128 TrackSegmentView ctv1 = layoutEditor.getTrackSegmentView(getConnect1()); 129 if (getConnect1().getConnect1() == positionablePoint) { 130 ctv1.setArrowEndStart(false); 131 ctv1.setBumperEndStart(false); 132 } 133 if (getConnect1().getConnect2() == positionablePoint) { 134 ctv1.setArrowEndStop(false); 135 ctv1.setBumperEndStop(false); 136 } 137 } 138 if (getConnect2() != null) { 139 TrackSegmentView ctv2 = layoutEditor.getTrackSegmentView(getConnect2()); 140 if (getConnect2().getConnect1() == positionablePoint) { 141 ctv2.setArrowEndStart(false); 142 ctv2.setBumperEndStart(false); 143 } 144 if (getConnect2().getConnect2() == positionablePoint) { 145 ctv2.setArrowEndStop(false); 146 ctv2.setBumperEndStop(false); 147 } 148 } 149 } 150 151 private void setTypeEndBumper() { 152 setIdent(layoutEditor.getFinder().uniqueName("EB", 1)); 153 154 // type = PointType.END_BUMPER; 155 positionablePoint.setTypeEndBumper(); 156 157 if (getConnect1() != null) { 158 TrackSegmentView ctv1 = layoutEditor.getTrackSegmentView(getConnect1()); 159 if (getConnect1().getConnect1() == positionablePoint) { 160 ctv1.setArrowEndStart(false); 161 ctv1.setBumperEndStart(true); 162 } 163 if (getConnect1().getConnect2() == positionablePoint) { 164 ctv1.setArrowEndStop(false); 165 ctv1.setBumperEndStop(true); 166 } 167 } 168 } 169 170 private void setTypeEdgeConnector() { 171 setIdent(layoutEditor.getFinder().uniqueName("EC", 1)); 172 173 // type = PointType.EDGE_CONNECTOR; 174 positionablePoint.setTypeEdgeConnector(); 175 176 if (getConnect1() != null) { 177 TrackSegmentView ctv1 = layoutEditor.getTrackSegmentView(getConnect1()); 178 if (getConnect1().getConnect1() == positionablePoint) { 179 ctv1.setBumperEndStart(false); 180 } 181 if (getConnect1().getConnect2() == positionablePoint) { 182 ctv1.setBumperEndStop(false); 183 } 184 } 185 } 186 187 public TrackSegment getConnect1() { 188 return positionablePoint.getConnect1(); 189 } 190 191 public TrackSegment getConnect2() { 192 return positionablePoint.getConnect2(); 193 } 194 195 public String getLinkedEditorName() { 196 return positionablePoint.getLinkedEditorName(); 197 } 198 199 public LayoutEditor getLinkedEditor() { 200 return positionablePoint.getLinkedEditor(); 201 } 202 203 public PositionablePoint getLinkedPoint() { 204 return positionablePoint.getLinkedPoint(); 205 } 206 207 public void removeLinkedPoint() { 208 positionablePoint.removeLinkedPoint(); 209 } 210 211 public String getLinkedPointId() { 212 return positionablePoint.getLinkedPointId(); 213 } 214 215 public void setLinkedPoint(PositionablePoint p) { 216 positionablePoint.setLinkedPoint(p); 217 } 218 219 /** 220 * {@inheritDoc} 221 */ 222 @Override 223 public void scaleCoords(double xFactor, double yFactor) { 224 Point2D factor = new Point2D.Double(xFactor, yFactor); 225 super.setCoordsCenter(MathUtil.granulize(MathUtil.multiply(getCoordsCenter(), factor), 1.0)); 226 } 227 228 /** 229 * {@inheritDoc} 230 */ 231 @Override 232 public void translateCoords(double xFactor, double yFactor) { 233 Point2D factor = new Point2D.Double(xFactor, yFactor); 234 super.setCoordsCenter(MathUtil.add(getCoordsCenter(), factor)); 235 } 236 237 /** 238 * {@inheritDoc} 239 */ 240 @Override 241 public void rotateCoords(double angleDEG) { 242 //can't really rotate a point... so... 243 //nothing to see here... move along... 244 } 245 246 /** 247 * @return the bounds of this positional point 248 */ 249 @Override 250 public Rectangle2D getBounds() { 251 Point2D c = getCoordsCenter(); 252 //Note: empty bounds don't draw... 253 // so now I'm making them 0.5 bigger in all directions (1 pixel total) 254 return new Rectangle2D.Double(c.getX() - 0.5, c.getY() - 0.5, 1.0, 1.0); 255 } 256 257 @CheckReturnValue 258 @Nonnull 259 public String getEastBoundSignal() { 260 SignalHead h = getEastBoundSignalHead(); 261 if (h != null) { 262 return h.getDisplayName(); 263 } 264 return ""; 265 } 266 267 @CheckForNull 268 @CheckReturnValue 269 public SignalHead getEastBoundSignalHead() { 270 if (getType() == PointType.EDGE_CONNECTOR) { 271 int dir = getConnect1Dir(); 272 if (dir == Path.EAST || dir == Path.SOUTH || dir == Path.SOUTH_EAST) { 273 if (signalEastHeadNamed != null) { 274 return signalEastHeadNamed.getBean(); 275 } 276 return null; 277 } else if (getLinkedPoint() != null) { 278 // Do some checks to find where the connection is here. 279 int linkDir = getLinkedPoint().getConnect1Dir(); 280 if (linkDir == Path.SOUTH || linkDir == Path.EAST || linkDir == Path.SOUTH_EAST) { 281 return getLinkedPoint().getEastBoundSignalHead(); 282 } 283 } 284 } 285 286 if (signalEastHeadNamed != null) { 287 return signalEastHeadNamed.getBean(); 288 } 289 return null; 290 } 291 292 public void setEastBoundSignal(String signalName) { 293 if (getType() == PointType.EDGE_CONNECTOR) { 294 int dir = getConnect1Dir(); 295 if (dir == Path.EAST || dir == Path.SOUTH || dir == Path.SOUTH_EAST) { 296 setEastBoundSignalName(signalName); 297 } else if (getLinkedPoint() != null) { 298 int linkDir = getLinkedPoint().getConnect1Dir(); 299 if (linkDir == Path.SOUTH || linkDir == Path.EAST || linkDir == Path.SOUTH_EAST) { 300 getLinkedPoint().setEastBoundSignal(signalName); 301 } else { 302 setEastBoundSignalName(signalName); 303 } 304 } else { 305 setEastBoundSignalName(signalName); 306 } 307 } else { 308 setEastBoundSignalName(signalName); 309 } 310 } 311 312 private void setEastBoundSignalName(@CheckForNull String signalHead) { 313 if (signalHead == null || signalHead.isEmpty()) { 314 signalEastHeadNamed = null; 315 return; 316 } 317 318 SignalHead head = InstanceManager.getDefault(jmri.SignalHeadManager.class).getSignalHead(signalHead); 319 if (head != null) { 320 signalEastHeadNamed = InstanceManager.getDefault(jmri.NamedBeanHandleManager.class).getNamedBeanHandle(signalHead, head); 321 } else { 322 signalEastHeadNamed = null; 323 } 324 } 325 326 @CheckReturnValue 327 @Nonnull 328 public String getWestBoundSignal() { 329 SignalHead h = getWestBoundSignalHead(); 330 if (h != null) { 331 return h.getDisplayName(); 332 } 333 return ""; 334 } 335 336 @CheckForNull 337 @CheckReturnValue 338 public SignalHead getWestBoundSignalHead() { 339 if (getType() == PointType.EDGE_CONNECTOR) { 340 int dir = getConnect1Dir(); 341 if (dir == Path.WEST || dir == Path.NORTH || dir == Path.NORTH_WEST) { 342 if (signalWestHeadNamed != null) { 343 return signalWestHeadNamed.getBean(); 344 } 345 return null; 346 } else if (getLinkedPoint() != null) { 347 // Do some checks to find where the connection is here. 348 int linkDir = getLinkedPoint().getConnect1Dir(); 349 if (linkDir == Path.WEST || linkDir == Path.NORTH || linkDir == Path.NORTH_WEST) { 350 return getLinkedPoint().getWestBoundSignalHead(); 351 } 352 } 353 } 354 355 if (signalWestHeadNamed != null) { 356 return signalWestHeadNamed.getBean(); 357 } 358 return null; 359 } 360 361 public void setWestBoundSignal(String signalName) { 362 if (getType() == PointType.EDGE_CONNECTOR) { 363 int dir = getConnect1Dir(); 364 if (dir == Path.WEST || dir == Path.NORTH || dir == Path.NORTH_WEST) { 365 setWestBoundSignalName(signalName); 366 } else if (getLinkedPoint() != null) { 367 int linkDir = getLinkedPoint().getConnect1Dir(); 368 if (linkDir == Path.WEST || linkDir == Path.NORTH || linkDir == Path.NORTH_WEST) { 369 getLinkedPoint().setWestBoundSignal(signalName); 370 } else { 371 setWestBoundSignalName(signalName); 372 } 373 } else { 374 setWestBoundSignalName(signalName); 375 } 376 } else { 377 setWestBoundSignalName(signalName); 378 } 379 } 380 381 private void setWestBoundSignalName(@CheckForNull String signalHead) { 382 if (signalHead == null || signalHead.isEmpty()) { 383 signalWestHeadNamed = null; 384 return; 385 } 386 387 SignalHead head = InstanceManager.getDefault(jmri.SignalHeadManager.class).getSignalHead(signalHead); 388 if (head != null) { 389 signalWestHeadNamed = InstanceManager.getDefault(jmri.NamedBeanHandleManager.class).getNamedBeanHandle(signalHead, head); 390 } else { 391 signalWestHeadNamed = null; 392 } 393 } 394 395 @CheckReturnValue 396 @Nonnull 397 public String getEastBoundSensorName() { 398 if (eastBoundSensorNamed != null) { 399 return eastBoundSensorNamed.getName(); 400 } 401 return ""; 402 } 403 404 @CheckReturnValue 405 public Sensor getEastBoundSensor() { 406 if (eastBoundSensorNamed != null) { 407 return eastBoundSensorNamed.getBean(); 408 } 409 return null; 410 } 411 412 public void setEastBoundSensor(String sensorName) { 413 if (sensorName == null || sensorName.isEmpty()) { 414 eastBoundSensorNamed = null; 415 return; 416 } 417 418 try { 419 Sensor sensor = InstanceManager.sensorManagerInstance().provideSensor(sensorName); 420 eastBoundSensorNamed = jmri.InstanceManager.getDefault(jmri.NamedBeanHandleManager.class).getNamedBeanHandle(sensorName, sensor); 421 } catch (IllegalArgumentException ex) { 422 eastBoundSensorNamed = null; 423 } 424 } 425 426 @CheckReturnValue 427 @Nonnull 428 public String getWestBoundSensorName() { 429 if (westBoundSensorNamed != null) { 430 return westBoundSensorNamed.getName(); 431 } 432 return ""; 433 } 434 435 @CheckReturnValue 436 public Sensor getWestBoundSensor() { 437 if (westBoundSensorNamed != null) { 438 return westBoundSensorNamed.getBean(); 439 } 440 return null; 441 } 442 443 public void setWestBoundSensor(String sensorName) { 444 if (sensorName == null || sensorName.isEmpty()) { 445 westBoundSensorNamed = null; 446 return; 447 } 448 try { 449 Sensor sensor = InstanceManager.sensorManagerInstance().provideSensor(sensorName); 450 westBoundSensorNamed = jmri.InstanceManager.getDefault(jmri.NamedBeanHandleManager.class).getNamedBeanHandle(sensorName, sensor); 451 } catch (IllegalArgumentException ex) { 452 westBoundSensorNamed = null; 453 } 454 } 455 456 @CheckReturnValue 457 @Nonnull 458 public String getEastBoundSignalMastName() { 459 if (getEastBoundSignalMastNamed() != null) { 460 return getEastBoundSignalMastNamed().getName(); 461 } 462 return ""; 463 } 464 465 @CheckReturnValue 466 public SignalMast getEastBoundSignalMast() { 467 if (getEastBoundSignalMastNamed() != null) { 468 return getEastBoundSignalMastNamed().getBean(); 469 } 470 return null; 471 } 472 473 @CheckReturnValue 474 private NamedBeanHandle<SignalMast> getEastBoundSignalMastNamed() { 475 if (getType() == PointType.EDGE_CONNECTOR) { 476 int dir = getConnect1Dir(); 477 if (dir == Path.SOUTH || dir == Path.EAST || dir == Path.SOUTH_EAST) { 478 return eastBoundSignalMastNamed; 479 } else if (getLinkedPoint() != null) { 480 int linkDir = getLinkedPoint().getConnect1Dir(); 481 if (linkDir == Path.SOUTH || linkDir == Path.EAST || linkDir == Path.SOUTH_EAST) { 482 return getLinkedPoint().getEastBoundSignalMastNamed(); 483 } 484 } 485 } 486 return eastBoundSignalMastNamed; 487 } 488 489 public void setEastBoundSignalMast(String signalMast) { 490 SignalMast mast = null; 491 if (signalMast != null && !signalMast.isEmpty()) { 492 mast = InstanceManager.getDefault(jmri.SignalMastManager.class).getSignalMast(signalMast); 493 if (mast == null) { 494 log.error("{}.setEastBoundSignalMast({}); Unable to find Signal Mast", 495 getName(), signalMast); 496 return; 497 } 498 } else { 499 eastBoundSignalMastNamed = null; 500 return; 501 } 502 if (getType() == PointType.EDGE_CONNECTOR) { 503 int dir = getConnect1Dir(); 504 if (dir == Path.EAST || dir == Path.SOUTH || dir == Path.SOUTH_EAST) { 505 eastBoundSignalMastNamed = InstanceManager.getDefault(jmri.NamedBeanHandleManager.class).getNamedBeanHandle(signalMast, mast); 506 } else if (getLinkedPoint() != null) { 507 int linkDir = getLinkedPoint().getConnect1Dir(); 508 if (linkDir == Path.SOUTH || linkDir == Path.EAST || linkDir == Path.SOUTH_EAST) { 509 getLinkedPoint().setEastBoundSignalMast(signalMast); 510 } else { 511 eastBoundSignalMastNamed = InstanceManager.getDefault(jmri.NamedBeanHandleManager.class).getNamedBeanHandle(signalMast, mast); 512 } 513 } else { 514 eastBoundSignalMastNamed = InstanceManager.getDefault(jmri.NamedBeanHandleManager.class).getNamedBeanHandle(signalMast, mast); 515 } 516 } else { 517 eastBoundSignalMastNamed = InstanceManager.getDefault(jmri.NamedBeanHandleManager.class).getNamedBeanHandle(signalMast, mast); 518 } 519 } 520 521 @CheckReturnValue 522 @Nonnull 523 public String getWestBoundSignalMastName() { 524 if (getWestBoundSignalMastNamed() != null) { 525 return getWestBoundSignalMastNamed().getName(); 526 } 527 return ""; 528 } 529 530 @CheckReturnValue 531 public SignalMast getWestBoundSignalMast() { 532 if (getWestBoundSignalMastNamed() != null) { 533 return getWestBoundSignalMastNamed().getBean(); 534 } 535 return null; 536 } 537 538 @CheckReturnValue 539 private NamedBeanHandle<SignalMast> getWestBoundSignalMastNamed() { 540 if (getType() == PointType.EDGE_CONNECTOR) { 541 int dir = getConnect1Dir(); 542 if (dir == Path.WEST || dir == Path.NORTH || dir == Path.NORTH_WEST) { 543 return westBoundSignalMastNamed; 544 } else if (getLinkedPoint() != null) { 545 int linkDir = getLinkedPoint().getConnect1Dir(); 546 if (linkDir == Path.WEST || linkDir == Path.NORTH || linkDir == Path.NORTH_WEST) { 547 return getLinkedPoint().getWestBoundSignalMastNamed(); 548 } 549 } 550 } 551 return westBoundSignalMastNamed; 552 } 553 554 public void setWestBoundSignalMast(String signalMast) { 555 SignalMast mast = null; 556 if (signalMast != null && !signalMast.isEmpty()) { 557 mast = InstanceManager.getDefault(jmri.SignalMastManager.class).getSignalMast(signalMast); 558 if (mast == null) { 559 log.error("{}.setWestBoundSignalMast({}); Unable to find Signal Mast", 560 getName(), signalMast); 561 return; 562 } 563 } else { 564 westBoundSignalMastNamed = null; 565 return; 566 } 567 if (getType() == PointType.EDGE_CONNECTOR) { 568 int dir = getConnect1Dir(); 569 if (dir == Path.WEST || dir == Path.NORTH || dir == Path.NORTH_WEST) { 570 westBoundSignalMastNamed = InstanceManager.getDefault(jmri.NamedBeanHandleManager.class).getNamedBeanHandle(signalMast, mast); 571 } else if (getLinkedPoint() != null) { 572 int linkDir = getLinkedPoint().getConnect1Dir(); 573 if (linkDir == Path.WEST || linkDir == Path.NORTH || linkDir == Path.NORTH_WEST) { 574 getLinkedPoint().setWestBoundSignalMast(signalMast); 575 } else { 576 westBoundSignalMastNamed = InstanceManager.getDefault(jmri.NamedBeanHandleManager.class).getNamedBeanHandle(signalMast, mast); 577 } 578 } else { 579 westBoundSignalMastNamed = InstanceManager.getDefault(jmri.NamedBeanHandleManager.class).getNamedBeanHandle(signalMast, mast); 580 } 581 } else { 582 westBoundSignalMastNamed = InstanceManager.getDefault(jmri.NamedBeanHandleManager.class).getNamedBeanHandle(signalMast, mast); 583 } 584 } 585 586 public void removeBeanReference(jmri.NamedBean nb) { 587 if (nb == null) { 588 return; 589 } 590 if (nb instanceof SignalMast) { 591 if (nb.equals(getWestBoundSignalMast())) { 592 setWestBoundSignalMast(null); 593 } else if (nb.equals(getEastBoundSignalMast())) { 594 setEastBoundSignalMast(null); 595 } 596 } else if (nb instanceof Sensor) { 597 if (nb.equals(getWestBoundSensor())) { 598 setWestBoundSignalMast(null); 599 } else if (nb.equals(getEastBoundSensor())) { 600 setEastBoundSignalMast(null); 601 } 602 } else if (nb instanceof jmri.SignalHead) { 603 if (nb.equals(getWestBoundSignalHead())) { 604 setWestBoundSignal(null); 605 } 606 if (nb.equals(getEastBoundSignalHead())) { 607 setEastBoundSignal(null); 608 } 609 610 } 611 } 612 613 // initialization instance variables (used when loading a LayoutEditor) 614 public String trackSegment1Name = ""; 615 public String trackSegment2Name = ""; 616 617 /** 618 * setup a connection to a track 619 * 620 * @param track the track we want to connect to 621 * @return true if successful 622 */ 623 public boolean setTrackConnection(@Nonnull TrackSegment track) { 624 return replaceTrackConnection(null, track); 625 } 626 627 /** 628 * remove a connection to a track 629 * 630 * @param track the track we want to disconnect from 631 * @return true if successful 632 */ 633 public boolean removeTrackConnection(@Nonnull TrackSegment track) { 634 return replaceTrackConnection(track, null); 635 } 636 637 /** 638 * replace old track connection with new track connection 639 * 640 * @param oldTrack the old track connection 641 * @param newTrack the new track connection 642 * @return true if successful 643 */ 644 public boolean replaceTrackConnection(@CheckForNull TrackSegment oldTrack, @CheckForNull TrackSegment newTrack) { 645 boolean result = false; // assume failure (pessimist!) 646 // trying to replace old track with null? 647 if (newTrack == null) { 648 // (yes) remove old connection 649 if (oldTrack != null) { 650 result = true; // assume success (optimist!) 651 if (getConnect1() == oldTrack) { 652 positionablePoint.setConnect1(null); // disconnect getConnect1() 653 reCheckBlockBoundary(); 654 removeLinkedPoint(); 655 positionablePoint.setConnect1(getConnect2()); // Move getConnect2() to getConnect1() 656 positionablePoint.setConnect2Actual(null); // disconnect getConnect2() 657 } else if (getConnect2() == oldTrack) { 658 positionablePoint.setConnect2Actual(null); 659 reCheckBlockBoundary(); 660 } else { 661 result = false; // didn't find old connection 662 } 663 } else { 664 result = false; // can't replace null with null 665 } 666 if (!result) { 667 log.error("{}.replaceTrackConnection({}, {}); Attempt to remove non-existant track connection", 668 getName(), (oldTrack == null) ? "null" : oldTrack.getName(), "null"); 669 } 670 } else // already connected to newTrack? 671 if ((getConnect1() != newTrack) && (getConnect2() != newTrack)) { 672 // (no) find a connection we can connect to 673 result = true; // assume success (optimist!) 674 if (getConnect1() == oldTrack) { 675 positionablePoint.setConnect1(newTrack); 676 } else if ((getType() == PointType.ANCHOR) && (getConnect2() == oldTrack)) { 677 positionablePoint.setConnect2Actual(newTrack); 678 if (getConnect1().getLayoutBlock() == getConnect2().getLayoutBlock()) { 679 westBoundSignalMastNamed = null; 680 eastBoundSignalMastNamed = null; 681 setWestBoundSensor(""); 682 setEastBoundSensor(""); 683 } 684 } else { 685 log.error("{}.replaceTrackConnection({}, {}); Attempt to assign more than allowed number of connections", 686 getName(), (oldTrack == null) ? "null" : oldTrack.getName(), newTrack.getName()); 687 result = false; 688 } 689 } else { 690 log.warn("{}.replaceTrackConnection({}, {}); Already connected", 691 getName(), (oldTrack == null) ? "null" : oldTrack.getName(), newTrack.getName()); 692 result = false; 693 } 694 return result; 695 } // replaceTrackConnection 696 697 void removeSML(SignalMast signalMast) { 698 if (signalMast == null) { 699 return; 700 } 701 if (jmri.InstanceManager.getDefault(LayoutBlockManager.class 702 ).isAdvancedRoutingEnabled() && InstanceManager.getDefault(jmri.SignalMastLogicManager.class 703 ).isSignalMastUsed(signalMast)) { 704 SignallingGuiTools.removeSignalMastLogic( 705 null, signalMast); 706 } 707 } 708 709 protected int maxWidth() { 710 return 5; 711 } 712 713 protected int maxHeight() { 714 return 5; 715 } 716 // cursor location reference for this move (relative to object) 717 int xClick = 0; 718 int yClick = 0; 719 720 public void mousePressed(JmriMouseEvent e) { 721 // remember where we are 722 xClick = e.getX(); 723 yClick = e.getY(); 724 // if (debug) log.debug("Pressed: "+where(e)); 725 if (e.isPopupTrigger()) { 726 showPopup(e); 727 } 728 } 729 730 public void mouseReleased(JmriMouseEvent e) { 731 // if (debug) log.debug("Release: "+where(e)); 732 if (e.isPopupTrigger()) { 733 showPopup(e); 734 } 735 } 736 737 public void mouseClicked(JmriMouseEvent e) { 738 if (e.isPopupTrigger()) { 739 showPopup(e); 740 } 741 } 742 743 private JPopupMenu popup = null; 744 745 /** 746 * {@inheritDoc} 747 */ 748 @Override 749 @Nonnull 750 protected JPopupMenu showPopup(@Nonnull JmriMouseEvent mouseEvent) { 751 if (popup != null) { 752 popup.removeAll(); 753 } else { 754 popup = new JPopupMenu(); 755 } 756 757 boolean blockBoundary = false; 758 boolean addSensorsAndSignalMasksMenuItemsFlag = false; 759 JMenuItem jmi = null; 760 switch (getType()) { 761 case ANCHOR: 762 jmi = popup.add(Bundle.getMessage("MakeLabel", Bundle.getMessage("Anchor")) + getName()); 763 jmi.setEnabled(false); 764 765 LayoutBlock block1 = null; 766 if (getConnect1() != null) { 767 block1 = getConnect1().getLayoutBlock(); 768 } 769 LayoutBlock block2 = block1; 770 if (getConnect2() != null) { 771 block2 = getConnect2().getLayoutBlock(); 772 } 773 if ((block1 != null) && (block1 == block2)) { 774 jmi = popup.add(Bundle.getMessage("MakeLabel", Bundle.getMessage("BeanNameBlock")) + block1.getDisplayName()); 775 } else if ((block1 != null) && (block2 != null) && (block1 != block2)) { 776 jmi = popup.add(Bundle.getMessage("BlockDivider")); 777 jmi.setEnabled(false); 778 jmi = popup.add(Bundle.getMessage("MakeLabel", Bundle.getMessage("Block_ID", 1)) + block1.getDisplayName()); 779 jmi.setEnabled(false); 780 jmi = popup.add(Bundle.getMessage("MakeLabel", Bundle.getMessage("Block_ID", 2)) + block2.getDisplayName()); 781 jmi.setEnabled(false); 782 blockBoundary = true; 783 } 784 jmi.setEnabled(false); 785 break; 786 case END_BUMPER: 787 jmi = popup.add(Bundle.getMessage("MakeLabel", Bundle.getMessage("EndBumper")) + getName()); 788 jmi.setEnabled(false); 789 790 LayoutBlock blockEnd = null; 791 if (getConnect1() != null) { 792 blockEnd = getConnect1().getLayoutBlock(); 793 } 794 if (blockEnd != null) { 795 jmi = popup.add(Bundle.getMessage("MakeLabel", Bundle.getMessage("BlockID")) + blockEnd.getDisplayName()); 796 jmi.setEnabled(false); 797 addSensorsAndSignalMasksMenuItemsFlag = true; 798 } 799 break; 800 case EDGE_CONNECTOR: 801 jmi = popup.add(Bundle.getMessage("MakeLabel", Bundle.getMessage("EdgeConnector")) + getName()); 802 jmi.setEnabled(false); 803 804 if (getLinkedEditor() != null) { 805 String linkName = getLinkedEditorName() + ":" + getLinkedPointId(); 806 jmi = popup.add(Bundle.getMessage("LinkedToX", linkName)); 807 } else { 808 jmi = popup.add(Bundle.getMessage("EdgeNotLinked")); 809 } 810 jmi.setEnabled(false); 811 812 block1 = null; 813 if (getConnect1() != null) { 814 block1 = getConnect1().getLayoutBlock(); 815 } 816 block2 = block1; 817 if (getLinkedPoint() != null) { 818 if (getLinkedPoint().getConnect1() != null) { 819 block2 = getLinkedPoint().getConnect1().getLayoutBlock(); 820 } 821 } 822 if ((block1 != null) && (block1 == block2)) { 823 jmi = popup.add(Bundle.getMessage("MakeLabel", Bundle.getMessage("BeanNameBlock")) + block1.getDisplayName()); 824 } else if ((block1 != null) && (block2 != null) && (block1 != block2)) { 825 jmi = popup.add(Bundle.getMessage("BlockDivider")); 826 jmi.setEnabled(false); 827 jmi = popup.add(Bundle.getMessage("MakeLabel", Bundle.getMessage("Block_ID", 1)) + block1.getDisplayName()); 828 jmi.setEnabled(false); 829 jmi = popup.add(Bundle.getMessage("MakeLabel", Bundle.getMessage("Block_ID", 2)) + block2.getDisplayName()); 830 jmi.setEnabled(false); 831 blockBoundary = true; 832 } 833 break; 834 default: 835 break; 836 } 837 838 // if there are any track connections 839 if ((getConnect1() != null) || (getConnect2() != null)) { 840 JMenu connectionsMenu = new JMenu(Bundle.getMessage("Connections")); // there is no pane opening (which is what ... implies) 841 if (getConnect1() != null) { 842 connectionsMenu.add(new AbstractAction(Bundle.getMessage("MakeLabel", "1") + getConnect1().getName()) { 843 @Override 844 public void actionPerformed(ActionEvent e) { 845 LayoutEditorFindItems lf = layoutEditor.getFinder(); 846 LayoutTrack lt = lf.findObjectByName(getConnect1().getName()); 847 // this shouldn't ever be null... however... 848 if (lt != null) { 849 LayoutTrackView ltv = layoutEditor.getLayoutTrackView(lt); 850 layoutEditor.setSelectionRect(ltv.getBounds()); 851 ltv.showPopup(); 852 } 853 } 854 }); 855 } 856 if (getConnect2() != null) { 857 connectionsMenu.add(new AbstractAction(Bundle.getMessage("MakeLabel", "2") + getConnect2().getName()) { 858 @Override 859 public void actionPerformed(ActionEvent e) { 860 LayoutEditorFindItems lf = layoutEditor.getFinder(); 861 LayoutTrack lt = lf.findObjectByName(getConnect2().getName()); 862 // this shouldn't ever be null... however... 863 if (lt != null) { 864 LayoutTrackView ltv = layoutEditor.getLayoutTrackView(lt); 865 layoutEditor.setSelectionRect(ltv.getBounds()); 866 ltv.showPopup(); 867 } 868 } 869 }); 870 } 871 popup.add(connectionsMenu); 872 } 873 874 if (getConnect1() != null) { 875 // 876 // decorations menu 877 // 878 popup.add(new JSeparator(JSeparator.HORIZONTAL)); 879 880 JMenu decorationsMenu = new JMenu(Bundle.getMessage("DecorationMenuTitle")); 881 decorationsMenu.setToolTipText(Bundle.getMessage("DecorationMenuToolTip")); 882 popup.add(decorationsMenu); 883 884 JCheckBoxMenuItem jcbmi; 885 TrackSegmentView ctv1 = layoutEditor.getTrackSegmentView(getConnect1()); 886 887 if (getType() == PointType.EDGE_CONNECTOR) { 888 JMenu arrowsMenu = new JMenu(Bundle.getMessage("ArrowsMenuTitle")); 889 decorationsMenu.setToolTipText(Bundle.getMessage("ArrowsMenuToolTip")); 890 decorationsMenu.add(arrowsMenu); 891 892 JMenu arrowsCountMenu = new JMenu(Bundle.getMessage("DecorationStyleMenuTitle")); 893 arrowsCountMenu.setToolTipText(Bundle.getMessage("DecorationStyleMenuToolTip")); 894 arrowsMenu.add(arrowsCountMenu); 895 896 jcbmi = new JCheckBoxMenuItem(Bundle.getMessage("DecorationNoneMenuItemTitle")); 897 arrowsCountMenu.add(jcbmi); 898 jcbmi.setToolTipText(Bundle.getMessage("DecorationNoneMenuItemToolTip")); 899 jcbmi.addActionListener((java.awt.event.ActionEvent e3) -> { 900 if (getConnect1().getConnect1() == positionablePoint) { 901 ctv1.setArrowEndStart(false); 902 } 903 if (getConnect1().getConnect2() == positionablePoint) { 904 ctv1.setArrowEndStop(false); 905 } 906 if (!ctv1.isArrowEndStart() && !ctv1.isArrowEndStop()) { 907 ctv1.setArrowStyle(0); 908 } 909 }); 910 boolean etherEnd = ((getConnect1().getConnect1() == positionablePoint) && ctv1.isArrowEndStart()) 911 || ((getConnect1().getConnect2() == positionablePoint) && ctv1.isArrowEndStop()); 912 913 jcbmi.setSelected((ctv1.getArrowStyle() == 0) || !etherEnd); 914 915 // configure the arrows 916 for (int i = 1; i < NUM_ARROW_TYPES; i++) { 917 jcbmi = loadArrowImageToJCBItem(i, arrowsCountMenu); 918 final int n = i; 919 jcbmi.addActionListener((java.awt.event.ActionEvent e3) -> { 920 if (getConnect1().getConnect1() == positionablePoint) { 921 ctv1.setArrowEndStart(true); 922 } 923 if (getConnect1().getConnect2() == positionablePoint) { 924 ctv1.setArrowEndStop(true); 925 } 926 ctv1.setArrowStyle(n); 927 }); 928 jcbmi.setSelected((ctv1.getArrowStyle() == i) && etherEnd); 929 } 930 931 JMenu arrowsDirMenu = new JMenu(Bundle.getMessage("ArrowsDirectionMenuTitle")); 932 arrowsDirMenu.setToolTipText(Bundle.getMessage("ArrowsDirectionMenuToolTip")); 933 arrowsMenu.add(arrowsDirMenu); 934 935 jcbmi = new JCheckBoxMenuItem(Bundle.getMessage("DecorationNoneMenuItemTitle")); 936 arrowsDirMenu.add(jcbmi); 937 jcbmi.setToolTipText(Bundle.getMessage("DecorationNoneMenuItemToolTip")); 938 jcbmi.addActionListener((java.awt.event.ActionEvent e3) -> { 939 TrackSegmentView ctv = layoutEditor.getTrackSegmentView(getConnect1()); 940 ctv.setArrowDirIn(false); 941 ctv.setArrowDirOut(false); 942 }); 943 jcbmi.setSelected(!ctv1.isArrowDirIn() && !ctv1.isArrowDirOut()); 944 945 jcbmi = new JCheckBoxMenuItem(Bundle.getMessage("ArrowsDirectionInMenuItemTitle")); 946 arrowsDirMenu.add(jcbmi); 947 jcbmi.setToolTipText(Bundle.getMessage("ArrowsDirectionInMenuItemToolTip")); 948 jcbmi.addActionListener((java.awt.event.ActionEvent e3) -> { 949 TrackSegmentView ctv = layoutEditor.getTrackSegmentView(getConnect1()); 950 ctv.setArrowDirIn(true); 951 ctv.setArrowDirOut(false); 952 }); 953 jcbmi.setSelected(ctv1.isArrowDirIn() && !ctv1.isArrowDirOut()); 954 955 jcbmi = new JCheckBoxMenuItem(Bundle.getMessage("ArrowsDirectionOutMenuItemTitle")); 956 arrowsDirMenu.add(jcbmi); 957 jcbmi.setToolTipText(Bundle.getMessage("ArrowsDirectionOutMenuItemToolTip")); 958 jcbmi.addActionListener((java.awt.event.ActionEvent e3) -> { 959 TrackSegmentView ctv = layoutEditor.getTrackSegmentView(getConnect1()); 960 ctv.setArrowDirOut(true); 961 ctv.setArrowDirIn(false); 962 }); 963 jcbmi.setSelected(!ctv1.isArrowDirIn() && ctv1.isArrowDirOut()); 964 965 jcbmi = new JCheckBoxMenuItem(Bundle.getMessage("ArrowsDirectionBothMenuItemTitle")); 966 arrowsDirMenu.add(jcbmi); 967 jcbmi.setToolTipText(Bundle.getMessage("ArrowsDirectionBothMenuItemToolTip")); 968 jcbmi.addActionListener((java.awt.event.ActionEvent e3) -> { 969 TrackSegmentView ctv = layoutEditor.getTrackSegmentView(getConnect1()); 970 ctv.setArrowDirIn(true); 971 ctv.setArrowDirOut(true); 972 }); 973 jcbmi.setSelected(ctv1.isArrowDirIn() && ctv1.isArrowDirOut()); 974 975 jmi = arrowsMenu.add(new JMenuItem(Bundle.getMessage("DecorationColorMenuItemTitle"))); 976 jmi.setToolTipText(Bundle.getMessage("DecorationColorMenuItemToolTip")); 977 jmi.addActionListener((java.awt.event.ActionEvent e3) -> { 978 TrackSegmentView ctv = layoutEditor.getTrackSegmentView(getConnect1()); 979 Color newColor = JmriColorChooser.showDialog(null, "Choose a color", ctv.getArrowColor()); 980 if ((newColor != null) && !newColor.equals(ctv.getArrowColor())) { 981 ctv.setArrowColor(newColor); 982 } 983 }); 984 jmi.setForeground(ctv1.getArrowColor()); 985 jmi.setBackground(ColorUtil.contrast(ctv1.getArrowColor())); 986 987 jmi = arrowsMenu.add(new JMenuItem(Bundle.getMessage("MakeLabel", 988 Bundle.getMessage("DecorationLineWidthMenuItemTitle")) + ctv1.getArrowLineWidth())); 989 jmi.setToolTipText(Bundle.getMessage("DecorationLineWidthMenuItemToolTip")); 990 jmi.addActionListener((java.awt.event.ActionEvent e3) -> { 991 TrackSegmentView ctv = layoutEditor.getTrackSegmentView(getConnect1()); 992 //prompt for arrow line width 993 int newValue = QuickPromptUtil.promptForInt(layoutEditor, 994 Bundle.getMessage("DecorationLineWidthMenuItemTitle"), 995 Bundle.getMessage("DecorationLineWidthMenuItemTitle"), 996 ctv.getArrowLineWidth()); 997 ctv.setArrowLineWidth(newValue); 998 }); 999 1000 jmi = arrowsMenu.add(new JMenuItem(Bundle.getMessage("MakeLabel", 1001 Bundle.getMessage("DecorationLengthMenuItemTitle")) + ctv1.getArrowLength())); 1002 jmi.setToolTipText(Bundle.getMessage("DecorationLengthMenuItemToolTip")); 1003 jmi.addActionListener((java.awt.event.ActionEvent e3) -> { 1004 TrackSegmentView ctv = layoutEditor.getTrackSegmentView(getConnect1()); 1005 //prompt for arrow length 1006 int newValue = QuickPromptUtil.promptForInt(layoutEditor, 1007 Bundle.getMessage("DecorationLengthMenuItemTitle"), 1008 Bundle.getMessage("DecorationLengthMenuItemTitle"), 1009 ctv.getArrowLength()); 1010 ctv.setArrowLength(newValue); 1011 }); 1012 1013 jmi = arrowsMenu.add(new JMenuItem(Bundle.getMessage("MakeLabel", 1014 Bundle.getMessage("DecorationGapMenuItemTitle")) + ctv1.getArrowGap())); 1015 jmi.setToolTipText(Bundle.getMessage("DecorationGapMenuItemToolTip")); 1016 jmi.addActionListener((java.awt.event.ActionEvent e3) -> { 1017 TrackSegmentView ctv = layoutEditor.getTrackSegmentView(getConnect1()); 1018 //prompt for arrow gap 1019 int newValue = QuickPromptUtil.promptForInt(layoutEditor, 1020 Bundle.getMessage("DecorationGapMenuItemTitle"), 1021 Bundle.getMessage("DecorationGapMenuItemTitle"), 1022 ctv.getArrowGap()); 1023 ctv.setArrowGap(newValue); 1024 }); 1025 } else { 1026 1027 JMenu endBumperMenu = new JMenu(Bundle.getMessage("EndBumperMenuTitle")); 1028 decorationsMenu.setToolTipText(Bundle.getMessage("EndBumperMenuToolTip")); 1029 decorationsMenu.add(endBumperMenu); 1030 1031 JCheckBoxMenuItem enableCheckBoxMenuItem = new JCheckBoxMenuItem(Bundle.getMessage("EndBumperEnableMenuItemTitle")); 1032 enableCheckBoxMenuItem.setToolTipText(Bundle.getMessage("EndBumperEnableMenuItemToolTip")); 1033 1034 endBumperMenu.add(enableCheckBoxMenuItem); 1035 enableCheckBoxMenuItem.addActionListener((java.awt.event.ActionEvent e3) -> { 1036 TrackSegmentView ctv = layoutEditor.getTrackSegmentView(getConnect1()); 1037 if (getConnect1().getConnect1() == positionablePoint) { 1038 ctv.setBumperEndStart(enableCheckBoxMenuItem.isSelected()); 1039 } 1040 if (getConnect1().getConnect2() == positionablePoint) { 1041 ctv.setBumperEndStop(enableCheckBoxMenuItem.isSelected()); 1042 } 1043 }); 1044 if (getConnect1().getConnect1() == positionablePoint) { 1045 enableCheckBoxMenuItem.setSelected(ctv1.isBumperEndStart()); 1046 } 1047 if (getConnect1().getConnect2() == positionablePoint) { 1048 enableCheckBoxMenuItem.setSelected(ctv1.isBumperEndStop()); 1049 } 1050 1051 jmi = endBumperMenu.add(new JMenuItem(Bundle.getMessage("DecorationColorMenuItemTitle"))); 1052 jmi.setToolTipText(Bundle.getMessage("DecorationColorMenuItemToolTip")); 1053 jmi.addActionListener((java.awt.event.ActionEvent e3) -> { 1054 TrackSegmentView ctv = layoutEditor.getTrackSegmentView(getConnect1()); 1055 Color newColor = JmriColorChooser.showDialog(null, "Choose a color", ctv.getBumperColor()); 1056 if ((newColor != null) && !newColor.equals(ctv.getBumperColor())) { 1057 ctv.setBumperColor(newColor); 1058 } 1059 }); 1060 jmi.setForeground(ctv1.getBumperColor()); 1061 jmi.setBackground(ColorUtil.contrast(ctv1.getBumperColor())); 1062 1063 jmi = endBumperMenu.add(new JMenuItem(Bundle.getMessage("MakeLabel", 1064 Bundle.getMessage("DecorationLineWidthMenuItemTitle")) + ctv1.getBumperLineWidth())); 1065 jmi.setToolTipText(Bundle.getMessage("DecorationLineWidthMenuItemToolTip")); 1066 jmi.addActionListener((java.awt.event.ActionEvent e3) -> { 1067 TrackSegmentView ctv = layoutEditor.getTrackSegmentView(getConnect1()); 1068 //prompt for width 1069 int newValue = QuickPromptUtil.promptForInteger(layoutEditor, 1070 Bundle.getMessage("DecorationLineWidthMenuItemTitle"), 1071 Bundle.getMessage("DecorationLineWidthMenuItemTitle"), 1072 ctv.getBumperLineWidth(), t -> { 1073 if (t < 0 || t > TrackSegmentView.MAX_BUMPER_WIDTH) { 1074 throw new IllegalArgumentException( 1075 Bundle.getMessage("DecorationLengthMenuItemRange", TrackSegmentView.MAX_BUMPER_WIDTH)); 1076 } 1077 return true; 1078 }); 1079 ctv.setBumperLineWidth(newValue); 1080 }); 1081 1082 jmi = endBumperMenu.add(new JMenuItem(Bundle.getMessage("MakeLabel", 1083 Bundle.getMessage("DecorationLengthMenuItemTitle")) + ctv1.getBumperLength())); 1084 jmi.setToolTipText(Bundle.getMessage("DecorationLengthMenuItemToolTip")); 1085 jmi.addActionListener((java.awt.event.ActionEvent e3) -> { 1086 TrackSegmentView ctv = layoutEditor.getTrackSegmentView(getConnect1()); 1087 //prompt for length 1088 int newValue = QuickPromptUtil.promptForInteger(layoutEditor, 1089 Bundle.getMessage("DecorationLengthMenuItemTitle"), 1090 Bundle.getMessage("DecorationLengthMenuItemTitle"), 1091 ctv.getBumperLength(), t -> { 1092 if (t < 0 || t > TrackSegmentView.MAX_BUMPER_LENGTH) { 1093 throw new IllegalArgumentException( 1094 Bundle.getMessage("DecorationLengthMenuItemRange", TrackSegmentView.MAX_BUMPER_LENGTH)); 1095 } 1096 return true; 1097 }); 1098 ctv.setBumperLength(newValue); 1099 }); 1100 } // if (getType() == EDGE_CONNECTOR) 1101 } // if (getConnect1() != null) 1102 1103 popup.add(new JSeparator(JSeparator.HORIZONTAL)); 1104 1105 if (getType() == PointType.ANCHOR) { 1106 if (blockBoundary) { 1107 jmi = popup.add(new JMenuItem(Bundle.getMessage("CanNotMergeAtBlockBoundary"))); 1108 jmi.setEnabled(false); 1109 } else if ((getConnect1() != null) && (getConnect2() != null)) { 1110 jmi = popup.add(new AbstractAction(Bundle.getMessage("MergeAdjacentTracks")) { 1111 @Override 1112 public void actionPerformed(ActionEvent e) { 1113 PositionablePoint pp_this = positionablePoint; 1114 // if I'm fully connected... 1115 if ((getConnect1() != null) && (getConnect2() != null)) { 1116 // who is my connection 2 connected to (that's not me)? 1117 LayoutTrack newConnect2 = null; 1118 HitPointType newType2 = HitPointType.TRACK; 1119 if (getConnect2().getConnect1() == pp_this) { 1120 newConnect2 = getConnect2().getConnect2(); 1121 newType2 = getConnect2().type2; 1122 } else if (getConnect2().getConnect2() == pp_this) { 1123 newConnect2 = getConnect2().getConnect1(); 1124 newType2 = getConnect2().type1; 1125 } else { 1126 //this should never happen however... 1127 log.error("Join: wrong getConnect2() error."); 1128 } 1129 1130 // connect the other connection to my connection 2 to my connection 1 1131 if (newConnect2 == null) { 1132 // (this should NEVER happen... however...) 1133 log.error("Merge: no 'other' connection to getConnect2()."); 1134 } else { 1135 if (newConnect2 instanceof PositionablePoint) { 1136 PositionablePoint pp = (PositionablePoint) newConnect2; 1137 pp.replaceTrackConnection(getConnect2(), getConnect1()); 1138 } else { 1139 layoutEditor.setLink(newConnect2, newType2, getConnect1(), HitPointType.TRACK); 1140 } 1141 // connect the track at my getConnect1() to the newConnect2 1142 if (getConnect1().getConnect1() == pp_this) { 1143 getConnect1().setNewConnect1(newConnect2, newType2); 1144 } else if (getConnect1().getConnect2() == pp_this) { 1145 getConnect1().setNewConnect2(newConnect2, newType2); 1146 } else { 1147 // (this should NEVER happen... however...) 1148 log.error("Merge: no connection to connection 1."); 1149 } 1150 } 1151 1152 // remove connection 2 from selection information 1153 if (layoutEditor.selectedObject == getConnect2()) { 1154 layoutEditor.selectedObject = null; 1155 } 1156 if (layoutEditor.prevSelectedObject == getConnect2()) { 1157 layoutEditor.prevSelectedObject = null; 1158 } 1159 1160 // remove connection 2 from the layoutEditor's list of layout tracks 1161 layoutEditor.removeLayoutTrackAndRedraw(getConnect2()); 1162 1163 // update affected block 1164 LayoutBlock block = getConnect2().getLayoutBlock(); 1165 if (block != null) { 1166 //decrement Block use count 1167 block.decrementUse(); 1168 layoutEditor.getLEAuxTools().setBlockConnectivityChanged(); 1169 block.updatePaths(); 1170 } 1171 getConnect2().remove(); 1172 positionablePoint.setConnect2Actual(null); 1173 1174 //remove this PositionablePoint from selection information 1175 if (layoutEditor.selectedObject == pp_this) { 1176 layoutEditor.selectedObject = null; 1177 } 1178 if (layoutEditor.prevSelectedObject == pp_this) { 1179 layoutEditor.prevSelectedObject = null; 1180 } 1181 clearPossibleSelection(); 1182 1183 // remove this PositionablePoint and PositionablePointView from the layoutEditor's list of layout tracks 1184 layoutEditor.removeLayoutTrackAndRedraw(pp_this); 1185 pp_this.remove(); 1186 dispose(); 1187 1188 layoutEditor.setDirty(); 1189 layoutEditor.redrawPanel(); 1190 } else { 1191 // (this should NEVER happen... however...) 1192 log.error("Merge: missing connection(s)."); 1193 } 1194 } 1195 }); 1196 } 1197 } 1198 1199 popup.add(new AbstractAction(Bundle.getMessage("ButtonDelete")) { 1200 @Override 1201 public void actionPerformed(ActionEvent e 1202 ) { 1203 if (canRemove() && removeInlineLogixNG() 1204 && layoutEditor.removePositionablePoint(positionablePoint)) { 1205 // user is serious about removing this point from the panel 1206 clearPossibleSelection(); 1207 remove(); 1208 dispose(); 1209 } 1210 } 1211 }); 1212 1213 JMenu lineType = new JMenu(Bundle.getMessage("ChangeTo")); 1214 jmi = lineType.add(new JCheckBoxMenuItem(new AbstractAction(Bundle.getMessage("Anchor")) { 1215 @Override 1216 public void actionPerformed(ActionEvent e) { 1217 setTypeAnchor(); 1218 } 1219 })); 1220 1221 jmi.setSelected(getType() == PointType.ANCHOR); 1222 1223 // you can't change it to an anchor if it has a 2nd connection 1224 // TODO: add error dialog if you try? 1225 if ((getType() == PointType.EDGE_CONNECTOR) && (getConnect2() != null)) { 1226 jmi.setEnabled(false); 1227 } 1228 1229 jmi = lineType.add(new JCheckBoxMenuItem(new AbstractAction(Bundle.getMessage("EndBumper")) { 1230 @Override 1231 public void actionPerformed(ActionEvent e) { 1232 setTypeEndBumper(); 1233 } 1234 })); 1235 1236 jmi.setSelected(getType() == PointType.END_BUMPER); 1237 1238 jmi = lineType.add(new JCheckBoxMenuItem(new AbstractAction(Bundle.getMessage("EdgeConnector")) { 1239 @Override 1240 public void actionPerformed(ActionEvent e) { 1241 setTypeEdgeConnector(); 1242 } 1243 })); 1244 1245 jmi.setSelected(getType() == PointType.EDGE_CONNECTOR); 1246 1247 popup.add(lineType); 1248 1249 if (!blockBoundary && getType() == PointType.EDGE_CONNECTOR) { 1250 popup.add(new JSeparator(JSeparator.HORIZONTAL)); 1251 popup.add(new AbstractAction(Bundle.getMessage("EdgeEditLink")) { 1252 @Override 1253 public void actionPerformed(ActionEvent e) { 1254 setLink(); 1255 } 1256 }); 1257 } 1258 1259 if (blockBoundary) { 1260 popup.add(new JSeparator(JSeparator.HORIZONTAL)); 1261 if (getType() == PointType.EDGE_CONNECTOR) { 1262 popup.add(new AbstractAction(Bundle.getMessage("EdgeEditLink")) { 1263 @Override 1264 public void actionPerformed(ActionEvent e) { 1265 setLink(); 1266 } 1267 }); 1268 popup.add(new AbstractAction(Bundle.getMessage("SetSignals")) { 1269 @Override 1270 public void actionPerformed(ActionEvent e) { 1271 // bring up signals at edge connector tool dialog 1272 layoutEditor.getLETools().setSignalsAtBlockBoundaryFromMenu(positionablePoint, 1273 getLayoutEditorToolBarPanel().signalIconEditor, 1274 getLayoutEditorToolBarPanel().signalFrame); 1275 } 1276 }); 1277 } else { 1278 AbstractAction ssaa = new AbstractAction(Bundle.getMessage("SetSignals")) { 1279 @Override 1280 public void actionPerformed(ActionEvent e) { 1281 // bring up signals at level crossing tool dialog 1282 layoutEditor.getLETools().setSignalsAtBlockBoundaryFromMenu(positionablePoint, 1283 getLayoutEditorToolBarPanel().signalIconEditor, 1284 getLayoutEditorToolBarPanel().signalFrame); 1285 } 1286 }; 1287 1288 JMenu jm = new JMenu(Bundle.getMessage("SignalHeads")); 1289 if (layoutEditor.getLETools().addBlockBoundarySignalHeadInfoToMenu(positionablePoint, jm)) { 1290 jm.add(ssaa); 1291 popup.add(jm); 1292 } else { 1293 popup.add(ssaa); 1294 } 1295 } 1296 addSensorsAndSignalMasksMenuItemsFlag = true; 1297 } 1298 if (addSensorsAndSignalMasksMenuItemsFlag) { 1299 popup.add(new AbstractAction(Bundle.getMessage("SetSignalMasts")) { 1300 @Override 1301 public void actionPerformed(ActionEvent event) { 1302 // bring up signals at block boundary tool dialog 1303 layoutEditor.getLETools().setSignalMastsAtBlockBoundaryFromMenu(positionablePoint); 1304 } 1305 }); 1306 popup.add(new AbstractAction(Bundle.getMessage("SetSensors")) { 1307 @Override 1308 public void actionPerformed(ActionEvent event) { 1309 // bring up signals at block boundary tool dialog 1310 layoutEditor.getLETools().setSensorsAtBlockBoundaryFromMenu(positionablePoint, 1311 getLayoutEditorToolBarPanel().sensorIconEditor, 1312 getLayoutEditorToolBarPanel().sensorFrame); 1313 } 1314 }); 1315 } 1316 1317 layoutEditor.setShowAlignmentMenu(popup); 1318 1319 addCommonPopupItems(mouseEvent, popup); 1320 1321 popup.show(mouseEvent.getComponent(), mouseEvent.getX(), mouseEvent.getY()); 1322 1323 return popup; 1324 } // showPopup 1325 1326 /** 1327 * If an anchor point is selected via a track segment connection, it will be 1328 * in the track selection list. When the merge or delete finishes, draw can 1329 * no longer find the object resulting in a Java exception. 1330 * <p> 1331 * If the anchor point is in the track selection list, the selection groups 1332 * are cleared. 1333 */ 1334 private void clearPossibleSelection() { 1335 if (layoutEditor.getLayoutTrackSelection().contains(positionablePoint)) { 1336 layoutEditor.clearSelectionGroups(); 1337 } 1338 } 1339 1340 /** 1341 * {@inheritDoc} 1342 */ 1343 @Override 1344 public boolean canRemove() { 1345 List<String> itemList = new ArrayList<>(); 1346 // A has two track segments, EB has one, EC has one plus optional link 1347 1348 TrackSegment ts1 = getConnect1(); 1349 TrackSegment ts2 = getConnect2(); 1350 1351 if (ts1 != null) { 1352 itemList.addAll(getSegmentReferences(ts1)); 1353 } 1354 if (ts2 != null) { 1355 for (String item : getSegmentReferences(ts2)) { 1356 // Do not add duplicates 1357 if (!itemList.contains(item)) { 1358 itemList.add(item); 1359 } 1360 } 1361 } 1362 1363 if (!itemList.isEmpty()) { 1364 String typeName = ""; 1365 switch (getType()) { 1366 case ANCHOR: 1367 typeName = "Anchor"; // NOI18N 1368 break; 1369 case END_BUMPER: 1370 typeName = "EndBumper"; // NOI18N 1371 break; 1372 case EDGE_CONNECTOR: 1373 typeName = "EdgeConnector"; // NOI18N 1374 break; 1375 default: 1376 typeName = "Unknown type (" + getType() + ")"; // NOI18N 1377 break; 1378 } 1379 displayRemoveWarningDialog(itemList, typeName); 1380 } 1381 return itemList.isEmpty(); 1382 } 1383 1384 /** 1385 * Build a list of sensors, signal heads, and signal masts attached to a 1386 * connection point. 1387 * 1388 * @param ts The track segment to be checked. 1389 * @return a list of bean reference names. 1390 */ 1391 public ArrayList<String> getSegmentReferences(TrackSegment ts) { 1392 ArrayList<String> items = new ArrayList<>(); 1393 1394 HitPointType type1 = ts.getType1(); 1395 LayoutTrack conn1 = ts.getConnect1(); 1396 items.addAll(ts.getPointReferences(type1, conn1)); 1397 1398 HitPointType type2 = ts.getType2(); 1399 LayoutTrack conn2 = ts.getConnect2(); 1400 items.addAll(ts.getPointReferences(type2, conn2)); 1401 1402 return items; 1403 } 1404 1405 /** 1406 * Clean up when this object is no longer needed. Should not be called while 1407 * the object is still displayed; see remove() 1408 */ 1409 void dispose() { 1410 if (popup != null) { 1411 popup.removeAll(); 1412 } 1413 popup = null; 1414 removeLinkedPoint(); 1415 } 1416 1417 /** 1418 * Removes this object from display and persistence 1419 */ 1420 private void remove() { 1421 // remove from persistence by flagging inactive 1422 active = false; 1423 } 1424 1425 private boolean active = true; 1426 1427 /** 1428 * @return "active" true means that the object is still displayed, and 1429 * should be stored. 1430 */ 1431 protected boolean isActive() { 1432 return active; 1433 } 1434 1435 protected int getConnect1Dir() { 1436 int result = Path.NONE; 1437 1438 TrackSegment ts1 = getConnect1(); 1439 if (ts1 != null) { 1440 Point2D p1; 1441 if (ts1.getConnect1() == positionablePoint) { 1442 p1 = layoutEditor.getCoords(ts1.getConnect2(), ts1.getType2()); 1443 } else { 1444 p1 = layoutEditor.getCoords(ts1.getConnect1(), ts1.getType1()); 1445 } 1446 result = Path.computeDirection(getCoordsCenter(), p1); 1447 } 1448 return result; 1449 } 1450 1451 JDialog editLink = null; 1452 JComboBox<String> linkPointsBox; 1453 JComboBox<JCBHandle<LayoutEditor>> editorCombo; // Stores with LayoutEditor or "None" 1454 1455 void setLink() { 1456 if (getConnect1() == null || getConnect1().getLayoutBlock() == null) { 1457 log.error("{}.setLink(); Can not set link until we have a connecting track with a block assigned", getName()); 1458 return; 1459 } 1460 editLink = new JDialog(); 1461 editLink.setTitle(Bundle.getMessage("EdgeEditLinkFrom", getConnect1().getLayoutBlock().getDisplayName())); 1462 1463 JPanel container = new JPanel(); 1464 container.setLayout(new BorderLayout()); 1465 1466 JButton done = new JButton(Bundle.getMessage("ButtonDone")); 1467 done.addActionListener((ActionEvent a) -> updateLink()); 1468 1469 container.add(getLinkPanel(), BorderLayout.NORTH); 1470 container.add(done, BorderLayout.SOUTH); 1471 container.revalidate(); 1472 1473 editLink.add(container); 1474 1475 // make this button the default button (return or enter activates) 1476 JRootPane rootPane = SwingUtilities.getRootPane(done); 1477 rootPane.setDefaultButton(done); 1478 1479 editLink.pack(); 1480 editLink.setModal(false); 1481 editLink.setVisible(true); 1482 } 1483 1484 private ArrayList<PositionablePoint> pointList; 1485 1486 public JPanel getLinkPanel() { 1487 editorCombo = new JComboBox<>(); 1488 Set<LayoutEditor> panels = InstanceManager.getDefault(EditorManager.class) 1489 .getAll(LayoutEditor.class); 1490 editorCombo.addItem(new JCBHandle<>("None")); 1491 //if (panels.contains(layoutEditor)) { 1492 // panels.remove(layoutEditor); 1493 //} 1494 for (LayoutEditor p : panels) { 1495 JCBHandle<LayoutEditor> h = new JCBHandle<>(p); 1496 editorCombo.addItem(h); 1497 if (p == getLinkedEditor()) { 1498 editorCombo.setSelectedItem(h); 1499 } 1500 } 1501 1502 ActionListener selectPanelListener = (ActionEvent a) -> updatePointBox(); 1503 1504 editorCombo.addActionListener(selectPanelListener); 1505 JPanel selectorPanel = new JPanel(); 1506 selectorPanel.add(new JLabel(Bundle.getMessage("SelectPanel"))); 1507 selectorPanel.add(editorCombo); 1508 linkPointsBox = new JComboBox<>(); 1509 updatePointBox(); 1510 selectorPanel.add(new JLabel(Bundle.getMessage("ConnectingTo"))); 1511 selectorPanel.add(linkPointsBox); 1512 return selectorPanel; 1513 } 1514 1515 void updatePointBox() { 1516 linkPointsBox.removeAllItems(); 1517 pointList = new ArrayList<>(); 1518 if (editorCombo.getSelectedIndex() == 0) { 1519 linkPointsBox.setEnabled(false); 1520 return; 1521 } 1522 1523 linkPointsBox.setEnabled(true); 1524 LayoutEditor le = editorCombo.getItemAt(editorCombo.getSelectedIndex()).item(); 1525 for (PositionablePoint p : le.getPositionablePoints()) { 1526 if (p.getType() == PointType.EDGE_CONNECTOR) { 1527 if (p.getLinkedPoint() == positionablePoint) { 1528 pointList.add(p); 1529 linkPointsBox.addItem(p.getName()); 1530 linkPointsBox.setSelectedItem(p.getName()); 1531 } else if (p.getLinkedPoint() == null) { 1532 if (p != positionablePoint) { 1533 if (p.getConnect1() != null && p.getConnect1().getLayoutBlock() != null) { 1534 if (p.getConnect1().getLayoutBlock() != getConnect1().getLayoutBlock()) { 1535 pointList.add(p); 1536 linkPointsBox.addItem(p.getName()); 1537 } 1538 } 1539 } 1540 } 1541 } 1542 } 1543 editLink.pack(); 1544 } // updatePointBox 1545 1546 public void updateLink() { 1547 if (editorCombo.getSelectedIndex() == 0 || linkPointsBox.getSelectedIndex() == -1) { 1548 if (getLinkedPoint() != null && getConnect2() != null) { 1549 String removeremote = null; 1550 String removelocal = null; 1551 if (getConnect1Dir() == Path.EAST || getConnect1Dir() == Path.SOUTH) { 1552 removeremote = getLinkedPoint().getEastBoundSignal(); 1553 removelocal = getWestBoundSignal(); 1554 getLinkedPoint().setEastBoundSignal(""); 1555 } else { 1556 removeremote = getLinkedPoint().getWestBoundSignal(); 1557 removelocal = getEastBoundSignal(); 1558 getLinkedPoint().setWestBoundSignal(""); 1559 1560 } 1561 // removelocal and removeremote have been set here. 1562 if (!removeremote.isEmpty()) { 1563 jmri.SignalHead sh = InstanceManager.getDefault(jmri.SignalHeadManager.class 1564 ).getSignalHead(removeremote); 1565 getLinkedEditor().removeSignalHead(sh); 1566 jmri.jmrit.blockboss.BlockBossLogic.getStoppedObject(removeremote); 1567 1568 } 1569 if (!removelocal.isEmpty()) { 1570 jmri.SignalHead sh = InstanceManager.getDefault(jmri.SignalHeadManager.class 1571 ).getSignalHead(removelocal); 1572 layoutEditor.removeSignalHead(sh); 1573 jmri.jmrit.blockboss.BlockBossLogic.getStoppedObject(removelocal); 1574 } 1575 } 1576 setLinkedPoint(null); 1577 } else { 1578 setLinkedPoint(pointList.get(linkPointsBox.getSelectedIndex())); 1579 } 1580 editLink.setVisible(false); 1581 1582 } 1583 1584 /** 1585 * {@inheritDoc} 1586 */ 1587 @Override 1588 protected HitPointType findHitPointType(Point2D hitPoint, boolean useRectangles, boolean requireUnconnected) { 1589 HitPointType result = HitPointType.NONE; // assume point not on connection 1590 //note: optimization here: instead of creating rectangles for all the 1591 // points to check below, we create a rectangle for the test point 1592 // and test if the points below are in that rectangle instead. 1593 Rectangle2D r = layoutEditor.layoutEditorControlCircleRectAt(hitPoint); 1594 Point2D p, minPoint = MathUtil.zeroPoint2D; 1595 1596 double circleRadius = LayoutEditor.SIZE * layoutEditor.getTurnoutCircleSize(); 1597 double distance, minDistance = Float.POSITIVE_INFINITY; 1598 1599 if (!requireUnconnected || (getConnect1() == null) 1600 || ((getType() == PointType.ANCHOR) && (getConnect2() == null))) { 1601 // test point control rectangle 1602 p = getCoordsCenter(); 1603 distance = MathUtil.distance(p, hitPoint); 1604 if (distance < minDistance) { 1605 minDistance = distance; 1606 minPoint = p; 1607 result = HitPointType.POS_POINT; 1608 } 1609 } 1610 if ((useRectangles && !r.contains(minPoint)) 1611 || (!useRectangles && (minDistance > circleRadius))) { 1612 result = HitPointType.NONE; 1613 } 1614 return result; 1615 } // findHitPointType 1616 1617 /** 1618 * return the coordinates for a specified connection type 1619 * 1620 * @param connectionType the connection type 1621 * @return the coordinates for the specified connection type 1622 */ 1623 @Override 1624 public Point2D getCoordsForConnectionType(HitPointType connectionType) { 1625 Point2D result = getCoordsCenter(); 1626 if (connectionType != HitPointType.POS_POINT) { 1627 log.error("{}.getCoordsForConnectionType({}); Invalid Connection Type", 1628 getName(), connectionType); //I18IN 1629 } 1630 return result; 1631 } 1632 1633 /** 1634 * {@inheritDoc} 1635 */ 1636 @Override 1637 public LayoutTrack getConnection(HitPointType connectionType) throws jmri.JmriException { 1638 LayoutTrack result = null; 1639 if (connectionType == HitPointType.POS_POINT) { 1640 result = getConnect1(); 1641 if (null == result) { 1642 result = getConnect2(); 1643 } 1644 } else { 1645 String errString = MessageFormat.format("{0}.getConnection({1}); Invalid Connection Type", 1646 getName(), connectionType); //I18IN 1647 log.error("will throw {}", errString); 1648 throw new jmri.JmriException(errString); 1649 } 1650 return result; 1651 } 1652 1653 /** 1654 * {@inheritDoc} 1655 */ 1656 @Override 1657 public void setConnection(HitPointType connectionType, LayoutTrack o, HitPointType type) throws jmri.JmriException { 1658 if ((type != HitPointType.TRACK) && (type != HitPointType.NONE)) { 1659 String errString = MessageFormat.format("{0}.setConnection({1}, {2}, {3}); unexpected type", 1660 getName(), connectionType, (o == null) ? "null" : o.getName(), type); //I18IN 1661 log.error("will throw {}", errString); //I18IN 1662 throw new jmri.JmriException(errString); 1663 } 1664 if (connectionType != HitPointType.POS_POINT) { 1665 String errString = MessageFormat.format("{0}.setConnection({1}, {2}, {3}); Invalid Connection Type", 1666 getName(), connectionType, (o == null) ? "null" : o.getName(), type); //I18IN 1667 log.error("will throw {}", errString); //I18IN 1668 throw new jmri.JmriException(errString); 1669 } 1670 } 1671 1672 /** 1673 * return true if this connection type is disconnected 1674 * 1675 * @param connectionType the connection type to test 1676 * @return true if the connection for this connection type is free 1677 */ 1678 @Override 1679 public boolean isDisconnected(HitPointType connectionType) { 1680 boolean result = false; 1681 if (connectionType == HitPointType.POS_POINT) { 1682 result = ((getConnect1() == null) || (getConnect2() == null)); 1683 } else { 1684 log.error("{}.isDisconnected({}); Invalid Connection Type", 1685 getName(), connectionType); //I18IN 1686 } 1687 return result; 1688 } 1689 1690 /** 1691 * Draw track decorations. 1692 * <p> 1693 * This type of track has none, so this method is empty. 1694 */ 1695 @Override 1696 protected void drawDecorations(Graphics2D g2) { 1697 log.trace("PositionablePointView::drawDecorations"); 1698 } 1699 1700 /** 1701 * {@inheritDoc} 1702 */ 1703 @Override 1704 protected void draw1(Graphics2D g2, boolean isMain, boolean isBlock) { 1705 //nothing to do here... move along... 1706 log.trace("PositionablePointView::draw1"); 1707 } // draw1 1708 1709 /** 1710 * {@inheritDoc} 1711 */ 1712 @Override 1713 protected void draw2(Graphics2D g2, boolean isMain, float railDisplacement) { 1714 //nothing to do here... move along... 1715 log.trace("PositionablePointView::draw2"); 1716 } 1717 1718 /** 1719 * {@inheritDoc} 1720 */ 1721 @Override 1722 protected void highlightUnconnected(Graphics2D g2, HitPointType specificType) { 1723 log.trace("PositionablePointView::highlightUnconnected"); 1724 if ((specificType == HitPointType.NONE) || (specificType == HitPointType.POS_POINT)) { 1725 if ((getConnect1() == null) 1726 || ((getType() == PointType.ANCHOR) && (getConnect2() == null))) { 1727 g2.fill(trackControlCircleAt(getCoordsCenter())); 1728 } 1729 } 1730 } 1731 1732 /** 1733 * {@inheritDoc} 1734 */ 1735 @Override 1736 protected void drawEditControls(Graphics2D g2) { 1737 log.trace("PositionablePointView::drawEditControls c1:{} c2:{} {}", getConnect1(), getConnect2(), getType()); 1738 TrackSegment ts1 = getConnect1(); 1739 if (ts1 == null) { 1740 g2.setColor(Color.red); 1741 } else { 1742 TrackSegment ts2 = null; 1743 if (getType() == PointType.ANCHOR) { 1744 ts2 = getConnect2(); 1745 } else if (getType() == PointType.EDGE_CONNECTOR) { 1746 if (getLinkedPoint() != null) { 1747 ts2 = getLinkedPoint().getConnect1(); 1748 } 1749 } 1750 if ((getType() != PointType.END_BUMPER) && (ts2 == null)) { 1751 g2.setColor(Color.yellow); 1752 } else { 1753 g2.setColor(Color.green); 1754 } 1755 } 1756 log.trace(" at {} in {} draw {}", 1757 getCoordsCenter(), g2.getColor(), 1758 layoutEditor.layoutEditorControlRectAt(getCoordsCenter())); 1759 1760 g2.draw(layoutEditor.layoutEditorControlRectAt(getCoordsCenter())); 1761 } // drawEditControls 1762 1763 /** 1764 * {@inheritDoc} 1765 */ 1766 @Override 1767 protected void drawTurnoutControls(Graphics2D g2) { 1768 log.trace("PositionablePointView::drawTurnoutControls"); 1769 // PositionablePoints don't have turnout controls... 1770 // nothing to see here... move along... 1771 } 1772 1773 /** 1774 * {@inheritDoc} 1775 */ 1776 @Override 1777 public void reCheckBlockBoundary() { 1778 if (getType() == PointType.END_BUMPER) { 1779 return; 1780 } 1781 if (getConnect1() == null && getConnect2() == null) { 1782 //This is no longer a block boundary, therefore will remove signal masts and sensors if present 1783 if (westBoundSignalMastNamed != null) { 1784 removeSML(getWestBoundSignalMast()); 1785 } 1786 if (eastBoundSignalMastNamed != null) { 1787 removeSML(getEastBoundSignalMast()); 1788 } 1789 westBoundSignalMastNamed = null; 1790 eastBoundSignalMastNamed = null; 1791 setWestBoundSensor(""); 1792 setEastBoundSensor(""); 1793 //TODO: May want to look at a method to remove the assigned mast 1794 //from the panel and potentially any SignalMast logics generated 1795 } else if (getConnect1() == null || getConnect2() == null) { 1796 //could still be in the process of rebuilding the point details 1797 } else if (getConnect1().getLayoutBlock() == getConnect2().getLayoutBlock()) { 1798 //We are no longer a block bounardy 1799 if (westBoundSignalMastNamed != null) { 1800 removeSML(getWestBoundSignalMast()); 1801 } 1802 if (eastBoundSignalMastNamed != null) { 1803 removeSML(getEastBoundSignalMast()); 1804 } 1805 westBoundSignalMastNamed = null; 1806 eastBoundSignalMastNamed = null; 1807 setWestBoundSensor(""); 1808 setEastBoundSensor(""); 1809 //TODO: May want to look at a method to remove the assigned mast 1810 //from the panel and potentially any SignalMast logics generated 1811 } 1812 } // reCheckBlockBoundary 1813 1814 /** 1815 * {@inheritDoc} 1816 */ 1817 @Override 1818 protected List<LayoutConnectivity> getLayoutConnectivity() { 1819 return positionablePoint.getLayoutConnectivity(); 1820 } 1821 1822 /** 1823 * {@inheritDoc} 1824 */ 1825 @Override 1826 public List<HitPointType> checkForFreeConnections() { 1827 List<HitPointType> result = new ArrayList<>(); 1828 1829 if ((getConnect1() == null) 1830 || ((getType() == PointType.ANCHOR) && (getConnect2() == null))) { 1831 result.add(HitPointType.POS_POINT); 1832 } 1833 return result; 1834 } 1835 1836 /** 1837 * {@inheritDoc} 1838 */ 1839 @Override 1840 public boolean checkForUnAssignedBlocks() { 1841 // Positionable Points don't have blocks so... 1842 // nothing to see here... move along... 1843 return true; 1844 } 1845 1846 /** 1847 * {@inheritDoc} 1848 */ 1849 @Override 1850 public void checkForNonContiguousBlocks( 1851 @Nonnull HashMap<String, List<Set<String>>> blockNamesToTrackNameSetsMap) { 1852 /* 1853 * For each (non-null) blocks of this track do: 1854 * #1) If it's got an entry in the blockNamesToTrackNameSetMap then 1855 * #2) If this track is not in one of the TrackNameSets for this block 1856 * #3) add a new set (with this block/track) to 1857 * blockNamesToTrackNameSetMap and 1858 * #4) check all the connections in this 1859 * block (by calling the 2nd method below) 1860 * <p> 1861 * Basically, we're maintaining contiguous track sets for each block found 1862 * (in blockNamesToTrackNameSetMap) 1863 */ 1864 //check the 1st connection points block 1865 TrackSegment ts1 = getConnect1(); 1866 String blk1 = null; 1867 List<Set<String>> TrackNameSets = null; 1868 Set<String> TrackNameSet = null; // assume not found (pessimist!) 1869 1870 // this should never be null... but just in case... 1871 if (ts1 != null) { 1872 blk1 = ts1.getBlockName(); 1873 if (!blk1.isEmpty()) { 1874 TrackNameSets = blockNamesToTrackNameSetsMap.get(blk1); 1875 if (TrackNameSets != null) { // (#1) 1876 for (Set<String> checkTrackNameSet : TrackNameSets) { 1877 if (checkTrackNameSet.contains(getName())) { // (#2) 1878 TrackNameSet = checkTrackNameSet; 1879 break; 1880 } 1881 } 1882 } else { // (#3) 1883 log.debug("*New block (''{}'') trackNameSets", blk1); 1884 TrackNameSets = new ArrayList<>(); 1885 blockNamesToTrackNameSetsMap.put(blk1, TrackNameSets); 1886 } 1887 if (TrackNameSet == null) { 1888 TrackNameSet = new LinkedHashSet<>(); 1889 log.debug("* Add track ''{}'' to trackNameSet for block ''{}''", getName(), blk1); 1890 TrackNameSet.add(getName()); 1891 TrackNameSets.add(TrackNameSet); 1892 } 1893 if (getConnect1() != null) { // (#4) 1894 getConnect1().collectContiguousTracksNamesInBlockNamed(blk1, TrackNameSet); 1895 } 1896 } 1897 } 1898 1899 if (getType() == PointType.ANCHOR) { 1900 //check the 2nd connection points block 1901 TrackSegment ts2 = getConnect2(); 1902 // this should never be null... but just in case... 1903 if (ts2 != null) { 1904 String blk2 = ts2.getBlockName(); 1905 if (!blk2.isEmpty()) { 1906 TrackNameSet = null; // assume not found (pessimist!) 1907 TrackNameSets = blockNamesToTrackNameSetsMap.get(blk2); 1908 if (TrackNameSets != null) { // (#1) 1909 for (Set<String> checkTrackNameSet : TrackNameSets) { 1910 if (checkTrackNameSet.contains(getName())) { // (#2) 1911 TrackNameSet = checkTrackNameSet; 1912 break; 1913 } 1914 } 1915 } else { // (#3) 1916 log.debug("*New block (''{}'') trackNameSets", blk2); 1917 TrackNameSets = new ArrayList<>(); 1918 blockNamesToTrackNameSetsMap.put(blk2, TrackNameSets); 1919 } 1920 if (TrackNameSet == null) { 1921 TrackNameSet = new LinkedHashSet<>(); 1922 log.debug("* Add track ''{}'' to TrackNameSet for block ''{}''", getName(), blk2); 1923 TrackNameSets.add(TrackNameSet); 1924 TrackNameSet.add(getName()); 1925 } 1926 if (getConnect2() != null) { // (#4) 1927 getConnect2().collectContiguousTracksNamesInBlockNamed(blk2, TrackNameSet); 1928 } 1929 } 1930 } 1931 } 1932 } // collectContiguousTracksNamesInBlockNamed 1933 1934 /** 1935 * {@inheritDoc} 1936 */ 1937 @Override 1938 public void collectContiguousTracksNamesInBlockNamed(@Nonnull String blockName, 1939 @Nonnull Set<String> TrackNameSet) { 1940 if (!TrackNameSet.contains(getName())) { 1941 TrackSegment ts1 = getConnect1(); 1942 // this should never be null... but just in case... 1943 if (ts1 != null) { 1944 String blk1 = ts1.getBlockName(); 1945 // is this the blockName we're looking for? 1946 if (blk1.equals(blockName)) { 1947 // if we are added to the TrackNameSet 1948 if (TrackNameSet.add(getName())) { 1949 log.debug("* Add track ''{}''for block ''{}''", getName(), blockName); 1950 } 1951 // this should never be null... but just in case... 1952 if (getConnect1() != null) { 1953 getConnect1().collectContiguousTracksNamesInBlockNamed(blockName, TrackNameSet); 1954 } 1955 } 1956 } 1957 if (getType() == PointType.ANCHOR) { 1958 TrackSegment ts2 = getConnect2(); 1959 // this should never be null... but just in case... 1960 if (ts2 != null) { 1961 String blk2 = ts2.getBlockName(); 1962 // is this the blockName we're looking for? 1963 if (blk2.equals(blockName)) { 1964 // if we are added to the TrackNameSet 1965 if (TrackNameSet.add(getName())) { 1966 log.debug("* Add track ''{}''for block ''{}''", getName(), blockName); 1967 } 1968 // this should never be null... but just in case... 1969 if (getConnect2() != null) { 1970 // it's time to play... flood your neighbour! 1971 getConnect2().collectContiguousTracksNamesInBlockNamed(blockName, TrackNameSet); 1972 } 1973 } 1974 } 1975 } 1976 } 1977 } 1978 1979 /** 1980 * {@inheritDoc} 1981 */ 1982 @Override 1983 public void setAllLayoutBlocks(LayoutBlock layoutBlock) { 1984 // positionable points don't have blocks... 1985 // nothing to see here, move along... 1986 } 1987 1988 private final static org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(PositionablePointView.class); 1989}