001package jmri.jmrit.display.layoutEditor; 002 003import java.util.ArrayList; 004import java.util.List; 005 006import javax.annotation.CheckReturnValue; 007import javax.annotation.CheckForNull; 008 009import jmri.NamedBean; 010import jmri.Sensor; 011import jmri.SignalHead; 012import jmri.SignalMast; 013import jmri.Turnout; 014 015/** 016 * A collection of tools to find various objects within the layout model(s) 017 * 018 * (temporary) Consider renaming to LayoutModelFindItems, or even merge to LayoutModels 019 * 020 * @author Dave Duchamp Copyright (c) 2004-2007 021 * @author George Warner Copyright (c) 2017-2018 022 * @author Bob Jacobsen Copyright (c) 2019-2020 023 */ 024final public class LayoutEditorFindItems { 025 026 private final LayoutModels layoutModels; 027 028 public LayoutEditorFindItems(LayoutModels models) { 029 layoutModels = models; 030 } 031 032 public TrackSegment findTrackSegmentByName(String name) { 033 if (!name.isEmpty()) { 034 for (TrackSegment t : layoutModels.getTrackSegments()) { 035 if (t.getId().equals(name)) { 036 return t; 037 } 038 } 039 } 040 return null; 041 } 042 043 public PositionablePoint findPositionablePointByName(String name) { 044 if (!name.isEmpty()) { 045 for (PositionablePoint p : layoutModels.getPositionablePoints()) { 046 if (p.getId().equals(name)) { 047 return p; 048 } 049 } 050 } 051 return null; 052 } 053 054 public PositionablePoint findPositionablePointAtTrackSegments(TrackSegment tr1, TrackSegment tr2) { 055 for (PositionablePoint p : layoutModels.getPositionablePoints()) { 056 if (((p.getConnect1() == tr1) && (p.getConnect2() == tr2)) 057 || ((p.getConnect1() == tr2) && (p.getConnect2() == tr1))) { 058 return p; 059 } 060 } 061 return null; 062 } 063 064 public PositionablePoint findPositionableLinkPoint(LayoutBlock blk1) { 065 for (PositionablePoint p : layoutModels.getPositionablePoints()) { 066 if (p.getType() == PositionablePoint.PointType.EDGE_CONNECTOR) { 067 if ((p.getConnect1() != null && p.getConnect1().getLayoutBlock() == blk1) 068 || (p.getConnect2() != null && p.getConnect2().getLayoutBlock() == blk1)) { 069 return p; 070 } 071 } 072 } 073 return null; 074 } 075 076 /** 077 * Returns an array list of track segments matching the block name. 078 * @param name block name. 079 * @return array of segments, may be null. 080 */ 081 public ArrayList<TrackSegment> findTrackSegmentByBlock(String name) { 082 if (name.isEmpty()) { 083 return null; 084 } 085 ArrayList<TrackSegment> ts = new ArrayList<>(); 086 for (TrackSegment t : layoutModels.getTrackSegments()) { 087 if (t.getBlockName().equals(name)) { 088 ts.add(t); 089 } 090 } 091 return ts; 092 } 093 094 public PositionablePoint findPositionablePointByEastBoundSignal(String signalName) { 095 for (PositionablePoint p : layoutModels.getPositionablePoints()) { 096 if (p.getEastBoundSignal().equals(signalName)) { 097 return p; 098 } 099 } 100 return null; 101 } 102 103 public PositionablePoint findPositionablePointByWestBoundSignal(String signalName) { 104 for (PositionablePoint p : layoutModels.getPositionablePoints()) { 105 if (p.getWestBoundSignal().equals(signalName)) { 106 return p; 107 } 108 } 109 return null; 110 } 111 112 public PositionablePoint findPositionablePointByWestBoundBean(NamedBean bean) { 113 if (bean instanceof SignalMast) { 114 for (PositionablePoint p : layoutModels.getPositionablePoints()) { 115 if (p.getWestBoundSignalMast() == bean) { 116 return p; 117 } 118 } 119 } else if (bean instanceof Sensor) { 120 for (PositionablePoint p : layoutModels.getPositionablePoints()) { 121 if (p.getWestBoundSensor() == bean) { 122 return p; 123 } 124 } 125 } else if (bean instanceof SignalHead) { 126 for (PositionablePoint p : layoutModels.getPositionablePoints()) { 127 if (p.getWestBoundSignal().equals(bean.getSystemName())) { 128 return p; 129 } 130 } 131 } 132 return null; 133 } 134 135 public PositionablePoint findPositionablePointByEastBoundBean(NamedBean bean) { 136 if (bean instanceof SignalMast) { 137 for (PositionablePoint p : layoutModels.getPositionablePoints()) { 138 if (p.getEastBoundSignalMast() == bean) { 139 return p; 140 } 141 } 142 } else if (bean instanceof Sensor) { 143 for (PositionablePoint p : layoutModels.getPositionablePoints()) { 144 if (p.getEastBoundSensor() == bean) { 145 return p; 146 } 147 } 148 } else if (bean instanceof SignalHead) { 149 for (PositionablePoint p : layoutModels.getPositionablePoints()) { 150 if (p.getEastBoundSignal().equals(bean.getSystemName())) { 151 return p; 152 } 153 } 154 } 155 return null; 156 } 157 158 public PositionablePoint findPositionablePointByWestBoundSignalMast(String signalMastName) { 159 for (PositionablePoint p : layoutModels.getPositionablePoints()) { 160 if (p.getWestBoundSignalMastName().equals(signalMastName)) { 161 return p; 162 } 163 } 164 return null; 165 } 166 167 public PositionablePoint findPositionablePointByBean(NamedBean bean) { 168 if (bean instanceof SignalMast) { 169 for (PositionablePoint p : layoutModels.getPositionablePoints()) { 170 if (p.getWestBoundSignalMast() == bean 171 || p.getEastBoundSignalMast() == bean) { 172 return p; 173 } 174 } 175 } else if (bean instanceof Sensor) { 176 for (PositionablePoint p : layoutModels.getPositionablePoints()) { 177 if (p.getWestBoundSensor() == bean 178 || p.getEastBoundSensor() == bean) { 179 return p; 180 } 181 } 182 } else if (bean instanceof SignalHead) { 183 for (PositionablePoint p : layoutModels.getPositionablePoints()) { 184 if (p.getEastBoundSignal().equals(bean.getSystemName()) 185 || p.getWestBoundSignal().equals(bean.getSystemName())) { 186 return p; 187 } 188 if (bean.getUserName() != null && (p.getEastBoundSignal().equals(bean.getSystemName()) 189 || p.getWestBoundSignal().equals(bean.getSystemName()))) { 190 return p; 191 } 192 } 193 } 194 return null; 195 196 } 197 198 @CheckReturnValue 199 public LayoutTurnout findLayoutTurnoutBySignalMast(String signalMastName) throws IllegalArgumentException { 200 return findLayoutTurnoutByBean(jmri.InstanceManager.getDefault(jmri.SignalMastManager.class).provideSignalMast(signalMastName)); 201 } 202 203 @CheckReturnValue 204 public LayoutTurnout findLayoutTurnoutByBean(@CheckForNull NamedBean bean) { 205 List<LayoutTurnout> layoutTurnouts = layoutModels.getLayoutTurnouts(); 206 if (bean instanceof SignalMast) { 207 for (LayoutTurnout t : layoutTurnouts) { 208 if (t.getSignalAMast() == bean 209 || t.getSignalBMast() == bean 210 || t.getSignalCMast() == bean 211 || t.getSignalDMast() == bean) { 212 return t; 213 } 214 } 215 } else if (bean instanceof Sensor) { 216 for (LayoutTurnout t : layoutTurnouts) { 217 if (t.getSensorA() == bean 218 || t.getSensorB() == bean 219 || t.getSensorC() == bean 220 || t.getSensorD() == bean) { 221 return t; 222 } 223 } 224 } else if (bean instanceof SignalHead) { 225 for (LayoutTurnout t : layoutTurnouts) { 226 if (t.getSignalA1Name().equals(bean.getSystemName()) 227 || t.getSignalA2Name().equals(bean.getSystemName()) 228 || t.getSignalA3Name().equals(bean.getSystemName())) { 229 return t; 230 } 231 232 if (t.getSignalB1Name().equals(bean.getSystemName()) 233 || t.getSignalB2Name().equals(bean.getSystemName())) { 234 return t; 235 } 236 if (t.getSignalC1Name().equals(bean.getSystemName()) 237 || t.getSignalC2Name().equals(bean.getSystemName())) { 238 return t; 239 } 240 if (t.getSignalD1Name().equals(bean.getSystemName()) 241 || t.getSignalD2Name().equals(bean.getSystemName())) { 242 return t; 243 } 244 if (bean.getUserName() != null) { 245 if (t.getSignalA1Name().equals(bean.getUserName()) 246 || t.getSignalA2Name().equals(bean.getUserName()) 247 || t.getSignalA3Name().equals(bean.getUserName())) { 248 return t; 249 } 250 251 if (t.getSignalB1Name().equals(bean.getUserName()) 252 || t.getSignalB2Name().equals(bean.getUserName())) { 253 return t; 254 } 255 if (t.getSignalC1Name().equals(bean.getUserName()) 256 || t.getSignalC2Name().equals(bean.getUserName())) { 257 return t; 258 } 259 if (t.getSignalD1Name().equals(bean.getUserName()) 260 || t.getSignalD2Name().equals(bean.getUserName())) { 261 return t; 262 } 263 } 264 } 265 } else if (bean instanceof Turnout) { 266 for (LayoutTurnout t : layoutTurnouts) { 267 if (bean.equals(t.getTurnout())) { 268 return t; 269 } 270 } 271 } 272 return null; 273 } // findLayoutTurnoutByBean 274 275 @CheckReturnValue 276 public LayoutTurnout findLayoutTurnoutBySensor(String sensorName) throws IllegalArgumentException { 277 return findLayoutTurnoutByBean(jmri.InstanceManager.sensorManagerInstance().provideSensor(sensorName)); 278 } 279 280 public LevelXing findLevelXingBySignalMast(String signalMastName) throws IllegalArgumentException { 281 return findLevelXingByBean(jmri.InstanceManager.getDefault(jmri.SignalMastManager.class).provideSignalMast(signalMastName)); 282 } 283 284 public LevelXing findLevelXingBySensor(String sensorName) throws IllegalArgumentException { 285 return findLevelXingByBean(jmri.InstanceManager.sensorManagerInstance().provideSensor(sensorName)); 286 } 287 288 public LevelXing findLevelXingByBean(NamedBean bean) { 289 List<LevelXing> levelXings = layoutModels.getLevelXings(); 290 if (bean instanceof SignalMast) { 291 for (LevelXing l : levelXings) { 292 if (l.getSignalAMast() == bean 293 || l.getSignalBMast() == bean 294 || l.getSignalCMast() == bean 295 || l.getSignalDMast() == bean) { 296 return l; 297 } 298 } 299 } else if (bean instanceof Sensor) { 300 for (LevelXing l : levelXings) { 301 if (l.getSensorA() == bean 302 || l.getSensorB() == bean 303 || l.getSensorC() == bean 304 || l.getSensorD() == bean) { 305 return l; 306 } 307 } 308 309 } else if (bean instanceof SignalHead) { 310 for (LevelXing l : levelXings) { 311 if (l.getSignalAName().equals(bean.getSystemName()) 312 || l.getSignalBName().equals(bean.getSystemName()) 313 || l.getSignalCName().equals(bean.getSystemName()) 314 || l.getSignalDName().equals(bean.getSystemName())) { 315 return l; 316 } 317 if (bean.getUserName() != null && (l.getSignalAName().equals(bean.getUserName()) 318 || l.getSignalBName().equals(bean.getUserName()) 319 || l.getSignalCName().equals(bean.getUserName()) 320 || l.getSignalDName().equals(bean.getUserName()))) { 321 return l; 322 } 323 } 324 } 325 return null; 326 } 327 328 public LayoutSlip findLayoutSlipByBean(NamedBean bean) { 329 List<LayoutSlip> layoutSlips = layoutModels.getLayoutSlips(); 330 if (bean instanceof SignalMast) { 331 for (LayoutSlip l : layoutSlips) { 332 if (l.getSignalAMast() == bean 333 || l.getSignalBMast() == bean 334 || l.getSignalCMast() == bean 335 || l.getSignalDMast() == bean) { 336 return l; 337 } 338 } 339 } else if (bean instanceof Sensor) { 340 for (LayoutSlip l : layoutSlips) { 341 if (l.getSensorA() == bean 342 || l.getSensorB() == bean 343 || l.getSensorC() == bean 344 || l.getSensorD() == bean) { 345 return l; 346 } 347 } 348 } else if (bean instanceof SignalHead) { 349 for (LayoutSlip l : layoutSlips) { 350 if (l.getSignalA1Name().equals(bean.getSystemName()) 351 || l.getSignalA2Name().equals(bean.getSystemName()) 352 || l.getSignalA3Name().equals(bean.getSystemName())) { 353 return l; 354 } 355 356 if (l.getSignalB1Name().equals(bean.getSystemName()) 357 || l.getSignalB2Name().equals(bean.getSystemName())) { 358 return l; 359 } 360 if (l.getSignalC1Name().equals(bean.getSystemName()) 361 || l.getSignalC2Name().equals(bean.getSystemName())) { 362 return l; 363 } 364 if (l.getSignalD1Name().equals(bean.getSystemName()) 365 || l.getSignalD2Name().equals(bean.getSystemName())) { 366 return l; 367 } 368 if (l.getSignalA1Name().equals(bean.getUserName()) 369 || l.getSignalA2Name().equals(bean.getUserName()) 370 || l.getSignalA3Name().equals(bean.getUserName())) { 371 return l; 372 } 373 if (bean.getUserName() != null) { 374 if (l.getSignalB1Name().equals(bean.getUserName()) 375 || l.getSignalB2Name().equals(bean.getUserName())) { 376 return l; 377 } 378 if (l.getSignalC1Name().equals(bean.getUserName()) 379 || l.getSignalC2Name().equals(bean.getUserName())) { 380 return l; 381 } 382 if (l.getSignalD1Name().equals(bean.getUserName()) 383 || l.getSignalD2Name().equals(bean.getUserName())) { 384 return l; 385 } 386 } 387 } 388 } else if (bean instanceof Turnout) { 389 for (LayoutSlip l : layoutSlips) { 390 if (bean.equals(l.getTurnout())) { 391 return l; 392 } 393 if (bean.equals(l.getTurnoutB())) { 394 return l; 395 } 396 } 397 } 398 return null; 399 } 400 401 public LayoutSlip findLayoutSlipBySignalMast(String signalMastName) throws IllegalArgumentException { 402 return findLayoutSlipByBean(jmri.InstanceManager.getDefault(jmri.SignalMastManager.class).provideSignalMast(signalMastName)); 403 } 404 405 public LayoutSlip findLayoutSlipBySensor(String sensorName) throws IllegalArgumentException { 406 return findLayoutSlipByBean(jmri.InstanceManager.sensorManagerInstance().provideSensor(sensorName)); 407 } 408 409 public PositionablePoint findPositionablePointByEastBoundSensor(String sensorName) { 410 PositionablePoint result = null; 411 for (PositionablePoint p : layoutModels.getPositionablePoints()) { 412 if (p.getEastBoundSensorName().equals(sensorName)) { 413 result = p; 414 break; 415 } 416 } 417 return result; 418 } 419 420 public PositionablePoint findPositionablePointByWestBoundSensor(String sensorName) { 421 PositionablePoint result = null; 422 for (PositionablePoint p : layoutModels.getPositionablePoints()) { 423 if (p.getWestBoundSensorName().equals(sensorName)) { 424 result = p; 425 break; 426 } 427 } 428 return result; 429 } 430 431 @CheckReturnValue 432 public LayoutTurnout findLayoutTurnoutByName(String name) { 433 LayoutTurnout result = null; 434 if ((name != null) && !name.isEmpty()) { 435 for (LayoutTurnout t : layoutModels.getLayoutTurnouts()) { 436 if (t.getName().equals(name)) { 437 result = t; 438 break; 439 } 440 } 441 } 442 return result; 443 } 444 445 @CheckReturnValue 446 public LayoutTurnout findLayoutTurnoutByTurnoutName(String turnoutName) { 447 LayoutTurnout result = null; 448 if ((turnoutName != null) && !turnoutName.isEmpty()) { 449 for (LayoutTurnout t : layoutModels.getLayoutTurnouts()) { 450 if (t.getTurnoutName().equals(turnoutName)) { 451 result = t; 452 } 453 } 454 } 455 return result; 456 } 457 458 public LevelXing findLevelXingByName(String name) { 459 LevelXing result = null; 460 if ((name != null) && !name.isEmpty()) { 461 for (LevelXing x : layoutModels.getLevelXings()) { 462 if (x.getId().equals(name)) { 463 result = x; 464 break; 465 } 466 } 467 } 468 return result; 469 } 470 471 public LayoutSlip findLayoutSlipByName(String name) { 472 LayoutSlip result = null; 473 if ((name != null) && !name.isEmpty()) { 474 for (LayoutSlip x : layoutModels.getLayoutSlips()) { 475 if (x.getName().equals(name)) { 476 result = x; 477 break; 478 } 479 } 480 } 481 return result; 482 } 483 484 public LayoutTurntable findLayoutTurntableByName(String name) { 485 LayoutTurntable result = null; 486 if ((name != null) && !name.isEmpty()) { 487 for (LayoutTurntable x : layoutModels.getLayoutTurntables()) { 488 if (x.getId().equals(name)) { 489 result = x; 490 break; 491 } 492 } 493 } 494 return result; 495 } 496 497 public LayoutShape findLayoutShapeByName(String name) { 498 LayoutShape result = null; 499 if ((name != null) && !name.isEmpty()) { 500 for (LayoutShape x : layoutModels.getLayoutShapes()) { 501 if (x.getName().equals(name)) { 502 result = x; 503 break; 504 } 505 } 506 } 507 return result; 508 } 509 510 /** 511 * find object by name 512 * 513 * @param name the name of the object that you are looking for 514 * @return object the named object 515 */ 516 // NOTE: This replacement routine for findObjectByTypeAndName (above) 517 // uses the unique name prefixes to determine what type of item to find. 518 // Currently this routine (like the one above that it replaces) is only 519 // called by the setObjects routine in TrackSegment.java however in the 520 // move toward encapsulation this routine should see a lot more usage; 521 // specifically, instead of a TON of "if (type == XXX) { findXXXByName(...)...}" 522 // code you would just call this method instead. 523 public LayoutTrack findObjectByName(String name) { 524 LayoutTrack result = null; // assume failure (pessimist!) 525 if ((name != null) && !name.isEmpty()) { 526 if (name.startsWith("TO")) { 527 result = findLayoutTurnoutByName(name); 528 } else if (name.startsWith("A") || name.startsWith("EB") || name.startsWith("EC") || name.matches("F\\d+-A-\\d+")) { 529 result = findPositionablePointByName(name); 530 } else if (name.startsWith("X")) { 531 result = findLevelXingByName(name); 532 } else if (name.startsWith("SL")) { 533 result = findLayoutSlipByName(name); 534 } else if (name.startsWith("TUR")) { 535 result = findLayoutTurntableByName(name); 536 } else if (name.startsWith("T") || name.matches("F\\d+-S-\\d+")) { // (this prefix has to go after "TO" & "TUR" prefixes above) 537 result = findTrackSegmentByName(name); 538 } else if (name.endsWith("-EB")) { //BUGFIX: a 3rd party JMRI exporter gets this one wrong. 539 result = findPositionablePointByName(name); 540 } else { 541 log.warn("findObjectByName({}): unknown type name prefix", name); 542 } 543 if (result == null) { 544 log.debug("findObjectByName({}) returned null", name); 545 } 546 } 547 return result; 548 } 549 550 /** 551 * Determine the first unused object name... 552 * 553 * @param inPrefix ...with this prefix... 554 * @param inStartIndex ...and this starting index... 555 * @return the first unused object name 556 */ 557 public String uniqueName(String inPrefix, int inStartIndex) { 558 String result; 559 for (int idx = inStartIndex; true; idx++) { 560 result = String.format("%s%d", inPrefix, idx); 561 if (inPrefix.equals("S")) { // LayoutShape? 562 if (findLayoutShapeByName(result) == null) { 563 break; 564 } 565 } else if (findObjectByName(result) == null) { 566 break; 567 } 568 } 569 return result; 570 } 571 572 /** 573 * Determine the first unused object name... 574 * 575 * @param inPrefix ...with this prefix... 576 * @return the first unused object name 577 */ 578 public String uniqueName(String inPrefix) { 579 return uniqueName(inPrefix, 1); 580 } 581 582 private final static org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(LayoutEditorFindItems.class); 583}