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