001package jmri.jmrit.display.layoutEditor;
002
003import java.awt.Color;
004import java.awt.Graphics2D;
005import java.awt.event.ActionEvent;
006import java.awt.event.MouseEvent;
007import java.awt.geom.*;
008import static java.lang.Float.POSITIVE_INFINITY;
009import static java.lang.Math.PI;
010import java.util.*;
011
012import javax.annotation.CheckForNull;
013import javax.annotation.Nonnull;
014import javax.swing.*;
015
016import jmri.*;
017import jmri.jmrit.display.layoutEditor.LevelXing.Geometry;
018import jmri.jmrit.display.layoutEditor.blockRoutingTable.LayoutBlockRouteTableAction;
019import jmri.util.MathUtil;
020
021/**
022 * MVC View component for the LevelXing class
023 *
024 * @author Bob Jacobsen  Copyright (c) 2020
025 * 
026 */
027public class LevelXingView extends LayoutTrackView {
028
029    /**
030     * Constructor method.
031     * @param xing the level crossing.
032     * @param layoutEditor for access to tools
033     */
034    public LevelXingView(@Nonnull LevelXing xing, @Nonnull LayoutEditor layoutEditor) {
035        super(xing, layoutEditor);
036
037        this.xing = xing;
038        editor = new jmri.jmrit.display.layoutEditor.LayoutEditorDialogs.LevelXingEditor(layoutEditor);
039    }
040        
041    /**
042     * constructor method
043     * @param xing the level crossing.
044     * @param c display location
045     * @param layoutEditor for access to tools
046     */
047    public LevelXingView(@Nonnull LevelXing xing, @Nonnull Point2D c, @Nonnull LayoutEditor layoutEditor) {
048        super(xing, c, layoutEditor);
049
050        this.xing = xing;
051        editor = new jmri.jmrit.display.layoutEditor.LayoutEditorDialogs.LevelXingEditor(layoutEditor);
052    }
053
054    private Point2D dispA = new Point2D.Double(-20.0, 0.0);
055    private Point2D dispB = new Point2D.Double(-14.0, 14.0);
056
057    // temporary reference to the Editor that will eventually be part of View
058    private final jmri.jmrit.display.layoutEditor.LayoutEditorDialogs.LevelXingEditor editor;
059
060    final private LevelXing xing;
061
062    // temporary?
063    @Nonnull
064    public LevelXing getLevelXing() { return xing; }
065    
066    // this should only be used for debugging
067    @Override
068    public String toString() {
069        return "LevelXing " + getName();
070    }
071
072    /*
073    * Accessor methods
074     */
075    @Nonnull
076    public String getBlockNameAC() {
077        return xing.getBlockNameAC();
078    }
079
080    @Nonnull
081    public String getBlockNameBD() {
082        return xing.getBlockNameBD();
083    }
084
085    public SignalHead getSignalHead(Geometry loc) {
086        return xing.getSignalHead(loc);
087    }
088
089    public SignalMast getSignalMast(Geometry loc) {
090        return xing.getSignalMast(loc);
091    }
092
093    public Sensor getSensor(Geometry loc) {
094        return xing.getSensor(loc);
095    }
096
097    @Nonnull
098    public String getSignalAName() {
099        return xing.getSignalAName();
100    }
101
102    public void setSignalAName(String signalHead) {
103        xing.setSignalAName(signalHead);
104    }
105
106    @Nonnull
107    public String getSignalBName() {
108        return xing.getSignalBName();
109    }
110
111    public void setSignalBName(String signalHead) {
112        xing.setSignalBName(signalHead);
113    }
114
115    @Nonnull
116    public String getSignalCName() {
117        return xing.getSignalCName();
118    }
119
120    public void setSignalCName(String signalHead) {
121        xing.setSignalCName(signalHead);
122    }
123
124    @Nonnull
125    public String getSignalDName() {
126        return xing.getSignalDName();
127    }
128
129    public void setSignalDName(String signalHead) {
130        xing.setSignalDName(signalHead);
131    }
132
133    public void removeBeanReference(jmri.NamedBean nb) {
134        xing.removeBeanReference(nb);
135    }
136
137    public String getSignalAMastName() {
138        return xing.getSignalAMastName();
139    }
140
141    public SignalMast getSignalAMast() {
142        return xing.getSignalAMast();
143    }
144
145    public void setSignalAMast(String signalMast) {
146        xing.setSignalAMast(signalMast);
147    }
148
149    public String getSignalBMastName() {
150        return xing.getSignalBMastName();
151    }
152
153    public SignalMast getSignalBMast() {
154        return xing.getSignalBMast();
155    }
156
157    public void setSignalBMast(String signalMast) {
158        xing.setSignalBMast(signalMast);
159    }
160
161    public String getSignalCMastName() {
162        return xing.getSignalCMastName();
163    }
164
165    public SignalMast getSignalCMast() {
166        return xing.getSignalCMast();
167    }
168
169    public void setSignalCMast(String signalMast) {
170        xing.setSignalCMast(signalMast);
171    }
172
173    public String getSignalDMastName() {
174        return xing.getSignalDMastName();
175    }
176
177    public SignalMast getSignalDMast() {
178        return xing.getSignalDMast();
179    }
180
181    public void setSignalDMast(String signalMast) {
182        xing.setSignalDMast(signalMast);
183    }
184
185    public String getSensorAName() {
186        return xing.getSensorAName();
187    }
188
189    public Sensor getSensorA() {
190        return xing.getSensorA();
191    }
192
193    public void setSensorAName(String sensorName) {
194        xing.setSensorAName(sensorName);
195    }
196
197    public String getSensorBName() {
198        return xing.getSensorBName();
199    }
200
201    public Sensor getSensorB() {
202        return xing.getSensorB();
203    }
204
205    public void setSensorBName(String sensorName) {
206        xing.setSensorBName(sensorName);
207    }
208
209    public String getSensorCName() {
210        return xing.getSensorCName();
211    }
212
213    public Sensor getSensorC() {
214        return xing.getSensorC();
215    }
216
217    public void setSensorCName(String sensorName) {
218        xing.setSensorCName(sensorName);
219    }
220
221    public String getSensorDName() {
222        return xing.getSensorDName();
223    }
224
225    public Sensor getSensorD() {
226        return xing.getSensorD();
227    }
228
229    public void setSensorDName(String sensorName) {
230        xing.setSensorDName(sensorName);
231    }
232
233    /**
234     * {@inheritDoc}
235     */
236    @Override
237    public LayoutTrack getConnection(HitPointType connectionType) throws jmri.JmriException {
238        return xing.getConnection(connectionType);
239    }
240
241    /**
242     * {@inheritDoc}
243     */
244    @Override
245    public void setConnection(HitPointType connectionType, LayoutTrack o, HitPointType type) throws jmri.JmriException {
246        xing.setConnection(connectionType, o, type);
247    }
248
249    public LayoutTrack getConnectA() {
250        return xing.getConnectA();
251    }
252
253    public LayoutTrack getConnectB() {
254        return xing.getConnectB();
255    }
256
257    public LayoutTrack getConnectC() {
258        return xing.getConnectC();
259    }
260
261    public LayoutTrack getConnectD() {
262        return xing.getConnectD();
263    }
264
265    public void setConnectA(LayoutTrack o, HitPointType type) {
266        xing.setConnectA(o, type);
267    }
268
269    public void setConnectB(LayoutTrack o, HitPointType type) {
270        xing.setConnectB(o, type);
271    }
272
273    public void setConnectC(LayoutTrack o, HitPointType type) {
274        xing.setConnectC(o, type);
275    }
276
277    public void setConnectD(LayoutTrack o, HitPointType type) {
278        xing.setConnectD(o, type);
279    }
280
281    public LayoutBlock getLayoutBlockAC() {
282        return xing.getLayoutBlockAC();
283    }
284
285    public LayoutBlock getLayoutBlockBD() {
286        return xing.getLayoutBlockBD();
287    }
288
289
290
291    public Point2D getCoordsA() {
292        return MathUtil.add(getCoordsCenter(), dispA);
293    }
294
295    public Point2D getCoordsB() {
296        return MathUtil.add(getCoordsCenter(), dispB);
297    }
298
299    public Point2D getCoordsC() {
300        return MathUtil.subtract(getCoordsCenter(), dispA);
301    }
302
303    public Point2D getCoordsD() {
304        return MathUtil.subtract(getCoordsCenter(), dispB);
305    }
306
307    /**
308     * Get the coordinates for a specified connection type.
309     *
310     * @param connectionType the connection type
311     * @return the coordinates for the specified connection type
312     */
313    @Override
314    public Point2D getCoordsForConnectionType(HitPointType connectionType) {
315        Point2D result = getCoordsCenter();
316        switch (connectionType) {
317            case LEVEL_XING_CENTER:
318                break;
319            case LEVEL_XING_A:
320                result = getCoordsA();
321                break;
322            case LEVEL_XING_B:
323                result = getCoordsB();
324                break;
325            case LEVEL_XING_C:
326                result = getCoordsC();
327                break;
328            case LEVEL_XING_D:
329                result = getCoordsD();
330                break;
331            default:
332                log.error("{}.getCoordsForConnectionType({}); Invalid connection type ",
333                        getName(), connectionType); //I18IN
334        }
335        return result;
336    }
337
338    /**
339     * @return the bounds of this crossing
340     */
341    @Override
342    public Rectangle2D getBounds() {
343        Rectangle2D result;
344
345        Point2D pointA = getCoordsA();
346        result = new Rectangle2D.Double(pointA.getX(), pointA.getY(), 0, 0);
347        result.add(getCoordsB());
348        result.add(getCoordsC());
349        result.add(getCoordsD());
350        return result;
351    }
352
353    /**
354     * Add Layout Blocks.
355     */
356//     @SuppressFBWarnings(value = "NP_NULL_ON_SOME_PATH_FROM_RETURN_VALUE", justification = "Null is accepted as a valid value")
357//     public void setLayoutBlockAC(LayoutBlock newLayoutBlock) {
358//         LayoutBlock blockAC = getLayoutBlockAC();
359//         LayoutBlock blockBD = getLayoutBlockBD();
360//         if (blockAC != newLayoutBlock) {
361//             // block 1 has changed, if old block exists, decrement use
362//             if ((blockAC != null) && (blockAC != blockBD)) {
363//                 blockAC.decrementUse();
364//             }
365//             blockAC = newLayoutBlock;
366//             if (newLayoutBlock != null) {
367//                 namedLayoutBlockAC = InstanceManager.getDefault(jmri.NamedBeanHandleManager.class).getNamedBeanHandle(newLayoutBlock.getUserName(), newLayoutBlock);
368//             } else {
369//                 namedLayoutBlockAC = null;
370//             }
371// 
372//             // decrement use if block was previously counted
373//             if ((blockAC != null) && (blockAC == blockBD)) {
374//                 blockAC.decrementUse();
375//             }
376//         }
377//     }
378
379//     @SuppressFBWarnings(value = "NP_NULL_ON_SOME_PATH_FROM_RETURN_VALUE", justification = "Null is accepted as a valid value")
380//     public void setLayoutBlockBD(LayoutBlock newLayoutBlock) {
381//         LayoutBlock blockAC = getLayoutBlockAC();
382//         LayoutBlock blockBD = getLayoutBlockBD();
383//         if (blockBD != newLayoutBlock) {
384//             // block 1 has changed, if old block exists, decrement use
385//             if ((blockBD != null) && (blockBD != blockAC)) {
386//                 blockBD.decrementUse();
387//             }
388//             blockBD = newLayoutBlock;
389//             if (newLayoutBlock != null) {
390//                 namedLayoutBlockBD = InstanceManager.getDefault(jmri.NamedBeanHandleManager.class).getNamedBeanHandle(newLayoutBlock.getUserName(), newLayoutBlock);
391//             } else {
392//                 namedLayoutBlockBD = null;
393//             }
394//             // decrement use if block was previously counted
395//             if ((blockBD != null) && (blockBD == blockAC)) {
396//                 blockBD.decrementUse();
397//             }
398//         }
399// 
400//     }
401// 
402//     public void updateBlockInfo() {
403//         LayoutBlock blockAC = getLayoutBlockAC();
404//         LayoutBlock blockBD = getLayoutBlockBD();
405//         LayoutBlock b1 = null;
406//         LayoutBlock b2 = null;
407//         if (blockAC != null) {
408//             blockAC.updatePaths();
409//         }
410//         if (connectA != null) {
411//             b1 = ((TrackSegment) connectA).getLayoutBlock();
412//             if ((b1 != null) && (b1 != blockAC)) {
413//                 b1.updatePaths();
414//             }
415//         }
416//         if (connectC != null) {
417//             b2 = ((TrackSegment) connectC).getLayoutBlock();
418//             if ((b2 != null) && (b2 != blockAC) && (b2 != b1)) {
419//                 b2.updatePaths();
420//             }
421//         }
422//         if (blockBD != null) {
423//             blockBD.updatePaths();
424//         }
425//         if (connectB != null) {
426//             b1 = ((TrackSegment) connectB).getLayoutBlock();
427//             if ((b1 != null) && (b1 != blockBD)) {
428//                 b1.updatePaths();
429//             }
430//         }
431//         if (connectD != null) {
432//             b2 = ((TrackSegment) connectD).getLayoutBlock();
433//             if ((b2 != null) && (b2 != blockBD) && (b2 != b1)) {
434//                 b2.updatePaths();
435//             }
436//         }
437//         reCheckBlockBoundary();
438//     }
439// 
440//     void removeSML(SignalMast signalMast) {
441//         if (signalMast == null) {
442//             return;
443//         }
444//         if (jmri.InstanceManager.getDefault(LayoutBlockManager.class).isAdvancedRoutingEnabled() && InstanceManager.getDefault(jmri.SignalMastLogicManager.class).isSignalMastUsed(signalMast)) {
445//             SignallingGuiTools.removeSignalMastLogic(null, signalMast);
446//         }
447//     }
448
449    /**
450     * Test if mainline track or not.
451     *
452     * @return true if either connecting track segment is mainline; Defaults to
453     *         not mainline if connecting track segments are missing
454     */
455    public boolean isMainlineAC() {
456        return xing.isMainlineAC();
457    }
458
459    public boolean isMainlineBD() {
460        return xing.isMainlineBD();
461    }
462
463    /*
464    * Modify coordinates methods.
465     */
466    public void setCoordsA(Point2D p) {
467        dispA = MathUtil.subtract(p, getCoordsCenter());
468    }
469
470    public void setCoordsB(Point2D p) {
471        dispB = MathUtil.subtract(p, getCoordsCenter());
472    }
473
474    public void setCoordsC(Point2D p) {
475        dispA = MathUtil.subtract(getCoordsCenter(), p);
476    }
477
478    public void setCoordsD(Point2D p) {
479        dispB = MathUtil.subtract(getCoordsCenter(), p);
480    }
481
482    /**
483     * {@inheritDoc}
484     */
485    @Override
486    public void scaleCoords(double xFactor, double yFactor) {
487        Point2D factor = new Point2D.Double(xFactor, yFactor);
488        super.setCoordsCenter(MathUtil.granulize(MathUtil.multiply(getCoordsCenter(), factor), 1.0));
489        dispA = MathUtil.granulize(MathUtil.multiply(dispA, factor), 1.0);
490        dispB = MathUtil.granulize(MathUtil.multiply(dispB, factor), 1.0);
491    }
492
493    /**
494     * {@inheritDoc}
495     */
496    @Override
497    public void translateCoords(double xFactor, double yFactor) {
498        Point2D factor = new Point2D.Double(xFactor, yFactor);
499        super.setCoordsCenter(MathUtil.add(getCoordsCenter(), factor));
500    }
501
502    /**
503     * {@inheritDoc}
504     */
505    @Override
506    public void rotateCoords(double angleDEG) {
507        // rotate coordinates
508        double rotRAD = Math.toRadians(angleDEG);
509        double sineRot = Math.sin(rotRAD);
510        double cosineRot = Math.cos(rotRAD);
511
512        // rotate displacements around origin {0, 0}
513        Point2D center_temp = getCoordsCenter();
514        super.setCoordsCenter(MathUtil.zeroPoint2D);
515        dispA = rotatePoint(dispA, sineRot, cosineRot);
516        dispB = rotatePoint(dispB, sineRot, cosineRot);
517        super.setCoordsCenter(center_temp);
518
519    }
520
521    /**
522     * {@inheritDoc}
523     */
524    @Override
525    protected HitPointType findHitPointType(Point2D hitPoint, boolean useRectangles, boolean requireUnconnected) {
526        HitPointType result = HitPointType.NONE;  // assume point not on connection
527        //note: optimization here: instead of creating rectangles for all the
528        // points to check below, we create a rectangle for the test point
529        // and test if the points below are in that rectangle instead.
530        Rectangle2D r = trackControlCircleRectAt(hitPoint);
531        Point2D p, minPoint = MathUtil.zeroPoint2D;
532
533        double circleRadius = LayoutEditor.SIZE * layoutEditor.getTurnoutCircleSize();
534        double distance, minDistance = POSITIVE_INFINITY;
535
536        //check the center point
537        if (!requireUnconnected) {
538            p = getCoordsCenter();
539            distance = MathUtil.distance(p, hitPoint);
540            if (distance < minDistance) {
541                minDistance = distance;
542                minPoint = p;
543                result = HitPointType.LEVEL_XING_CENTER;
544            }
545        }
546
547        //check the A connection point
548        if (!requireUnconnected || (getConnectA() == null)) {
549            p = getCoordsA();
550            distance = MathUtil.distance(p, hitPoint);
551            if (distance < minDistance) {
552                minDistance = distance;
553                minPoint = p;
554                result = HitPointType.LEVEL_XING_A;
555            }
556        }
557
558        //check the B connection point
559        if (!requireUnconnected || (getConnectB() == null)) {
560            p = getCoordsB();
561            distance = MathUtil.distance(p, hitPoint);
562            if (distance < minDistance) {
563                minDistance = distance;
564                minPoint = p;
565                result = HitPointType.LEVEL_XING_B;
566            }
567        }
568
569        //check the C connection point
570        if (!requireUnconnected || (getConnectC() == null)) {
571            p = getCoordsC();
572            distance = MathUtil.distance(p, hitPoint);
573            if (distance < minDistance) {
574                minDistance = distance;
575                minPoint = p;
576                result = HitPointType.LEVEL_XING_C;
577            }
578        }
579
580        //check the D connection point
581        if (!requireUnconnected || (getConnectD() == null)) {
582            p = getCoordsD();
583            distance = MathUtil.distance(p, hitPoint);
584            if (distance < minDistance) {
585                minDistance = distance;
586                minPoint = p;
587                result = HitPointType.LEVEL_XING_D;
588            }
589        }
590        if ((useRectangles && !r.contains(minPoint))
591                || (!useRectangles && (minDistance > circleRadius))) {
592            result = HitPointType.NONE;
593        }
594        return result;
595    }   // findHitPointType
596
597    // initialization instance variables (used when loading a LayoutEditor)
598//     public String connectAName = "";
599//     public String connectBName = "";
600//     public String connectCName = "";
601//     public String connectDName = "";
602// 
603//     public String tLayoutBlockNameAC = "";
604//     public String tLayoutBlockNameBD = "";
605
606    /**
607     * {@inheritDoc}
608     */
609    @Override
610    public boolean canRemove() {
611        return xing.canRemove();
612    }
613
614//     *
615//      * Build a list of sensors, signal heads, and signal masts attached to a
616//      * level crossing point.
617//      *
618//      * @param pointName Specify the point (A-D) or all (All) points.
619//      * @return a list of bean reference names.
620//      */
621//     public ArrayList<String> getBeanReferences(String pointName) {
622//         ArrayList<String> references = new ArrayList<>();
623//         if (pointName.equals("A") || pointName.equals("All")) {  // NOI18N
624//             if (!getSignalAMastName().isEmpty()) {
625//                 references.add(getSignalAMastName());
626//             }
627//             if (!getSensorAName().isEmpty()) {
628//                 references.add(getSensorAName());
629//             }
630//             if (!getSignalAName().isEmpty()) {
631//                 references.add(getSignalAName());
632//             }
633//         }
634//         if (pointName.equals("B") || pointName.equals("All")) {  // NOI18N
635//             if (!getSignalBMastName().isEmpty()) {
636//                 references.add(getSignalBMastName());
637//             }
638//             if (!getSensorBName().isEmpty()) {
639//                 references.add(getSensorBName());
640//             }
641//             if (!getSignalBName().isEmpty()) {
642//                 references.add(getSignalBName());
643//             }
644//         }
645//         if (pointName.equals("C") || pointName.equals("All")) {  // NOI18N
646//             if (!getSignalCMastName().isEmpty()) {
647//                 references.add(getSignalCMastName());
648//             }
649//             if (!getSensorCName().isEmpty()) {
650//                 references.add(getSensorCName());
651//             }
652//             if (!getSignalCName().isEmpty()) {
653//                 references.add(getSignalCName());
654//             }
655//         }
656//         if (pointName.equals("D") || pointName.equals("All")) {  // NOI18N
657//             if (!getSignalDMastName().isEmpty()) {
658//                 references.add(getSignalDMastName());
659//             }
660//             if (!getSensorDName().isEmpty()) {
661//                 references.add(getSensorDName());
662//             }
663//             if (!getSignalDName().isEmpty()) {
664//                 references.add(getSignalDName());
665//             }
666//         }
667//         return references;
668//     }
669
670    JPopupMenu popup = null;
671
672    /**
673     * {@inheritDoc}
674     */
675    @Override
676    @Nonnull
677    protected JPopupMenu showPopup(@CheckForNull MouseEvent mouseEvent) {
678        if (popup != null) {
679            popup.removeAll();
680        } else {
681            popup = new JPopupMenu();
682        }
683        if (layoutEditor.isEditable()) {
684            JMenuItem jmi = popup.add(Bundle.getMessage("MakeLabel", Bundle.getMessage("LevelCrossing")) + getName());
685            jmi.setEnabled(false);
686
687            boolean blockACAssigned = false;
688            boolean blockBDAssigned = false;
689            if (getLayoutBlockAC() == null) {
690                jmi = popup.add(Bundle.getMessage("NoBlockX", "AC"));
691            } else {
692                jmi = popup.add(Bundle.getMessage("MakeLabel", Bundle.getMessage("Block_ID", "AC")) + getLayoutBlockAC().getDisplayName());
693                blockACAssigned = true;
694            }
695            jmi.setEnabled(false);
696
697            if (getLayoutBlockBD() == null) {
698                jmi = popup.add(Bundle.getMessage("NoBlockX", "BD"));
699            } else {
700                jmi = popup.add(Bundle.getMessage("MakeLabel", Bundle.getMessage("Block_ID", "BD")) + getLayoutBlockBD().getDisplayName());
701                blockBDAssigned = true;
702            }
703            jmi.setEnabled(false);
704
705            // if there are any track connections
706            if ((getConnectA() != null) || (getConnectB() != null)
707                    || (getConnectC() != null) || (getConnectD() != null)) {
708                JMenu connectionsMenu = new JMenu(Bundle.getMessage("Connections")); // there is no pane opening (which is what ... implies)
709                if (getConnectA() != null) {
710                    connectionsMenu.add(new AbstractAction(Bundle.getMessage("MakeLabel", "A") + getConnectA().getName()) {
711                        @Override
712                        public void actionPerformed(ActionEvent e) {
713                            LayoutEditorFindItems lf = layoutEditor.getFinder();
714                            LayoutTrack lt = lf.findObjectByName(getConnectA().getName());
715                            // this shouldn't ever be null... however...
716                            if (lt != null) {
717                                LayoutTrackView ltv = layoutEditor.getLayoutTrackView(lt);
718                                layoutEditor.setSelectionRect(ltv.getBounds());
719                                ltv.showPopup();
720                            }
721                        }
722                    });
723                }
724                if (getConnectB() != null) {
725                    connectionsMenu.add(new AbstractAction(Bundle.getMessage("MakeLabel", "B") + getConnectB().getName()) {
726                        @Override
727                        public void actionPerformed(ActionEvent e) {
728                            LayoutEditorFindItems lf = layoutEditor.getFinder();
729                            LayoutTrack lt = lf.findObjectByName(getConnectB().getName());
730                            // this shouldn't ever be null... however...
731                            if (lt != null) {
732                                LayoutTrackView ltv = layoutEditor.getLayoutTrackView(lt);
733                                layoutEditor.setSelectionRect(ltv.getBounds());
734                                ltv.showPopup();
735                            }
736                        }
737                    });
738                }
739                if (getConnectC() != null) {
740                    connectionsMenu.add(new AbstractAction(Bundle.getMessage("MakeLabel", "C") + getConnectC().getName()) {
741                        @Override
742                        public void actionPerformed(ActionEvent e) {
743                            LayoutEditorFindItems lf = layoutEditor.getFinder();
744                            LayoutTrack lt = lf.findObjectByName(getConnectC().getName());
745                            // this shouldn't ever be null... however...
746                            if (lt != null) {
747                                LayoutTrackView ltv = layoutEditor.getLayoutTrackView(lt);
748                                layoutEditor.setSelectionRect(ltv.getBounds());
749                                ltv.showPopup();
750                            }
751                        }
752                    });
753                }
754                if (getConnectD() != null) {
755                    connectionsMenu.add(new AbstractAction(Bundle.getMessage("MakeLabel", "D") + getConnectD().getName()) {
756                        @Override
757                        public void actionPerformed(ActionEvent e) {
758                            LayoutEditorFindItems lf = layoutEditor.getFinder();
759                            LayoutTrack lt = lf.findObjectByName(getConnectD().getName());
760                            // this shouldn't ever be null... however...
761                            if (lt != null) {
762                                LayoutTrackView ltv = layoutEditor.getLayoutTrackView(lt);
763                                layoutEditor.setSelectionRect(ltv.getBounds());
764                                ltv.showPopup();
765                            }
766                        }
767                    });
768                }
769                popup.add(connectionsMenu);
770            }
771
772            popup.add(new JSeparator(JSeparator.HORIZONTAL));
773
774            JCheckBoxMenuItem hiddenCheckBoxMenuItem = new JCheckBoxMenuItem(Bundle.getMessage("Hidden"));
775            hiddenCheckBoxMenuItem.setSelected(isHidden());
776            popup.add(hiddenCheckBoxMenuItem);
777            hiddenCheckBoxMenuItem.addActionListener((java.awt.event.ActionEvent e3) -> setHidden(hiddenCheckBoxMenuItem.isSelected()));
778
779            popup.add(new AbstractAction(Bundle.getMessage("ButtonEdit")) {
780                @Override
781                public void actionPerformed(ActionEvent e) {
782                    editor.editLayoutTrack(LevelXingView.this);
783                }
784            });
785            popup.add(new AbstractAction(Bundle.getMessage("ButtonDelete")) {
786                @Override
787                public void actionPerformed(ActionEvent e) {
788                    if (canRemove() && layoutEditor.removeLevelXing(xing)) {
789                        // Returned true if user did not cancel
790                        xing.remove();
791                        dispose();
792                    }
793                }
794            });
795            if (blockACAssigned && blockBDAssigned) {
796                AbstractAction ssaa = new AbstractAction(Bundle.getMessage("SetSignals")) {
797                    @Override
798                    public void actionPerformed(ActionEvent e) {
799                        // bring up signals at level crossing tool dialog
800                        LayoutEditorToolBarPanel letbp = getLayoutEditorToolBarPanel();
801                        layoutEditor.getLETools().
802                                setSignalsAtLevelXingFromMenu(xing,
803                                        letbp.signalIconEditor,
804                                        letbp.signalFrame);
805                    }
806                };
807                JMenu jm = new JMenu(Bundle.getMessage("SignalHeads"));
808                if (layoutEditor.getLETools().
809                        addLevelXingSignalHeadInfoToMenu(xing, jm)) {
810                    jm.add(ssaa);
811                    popup.add(jm);
812                } else {
813                    popup.add(ssaa);
814                }
815            }
816
817            final String[] boundaryBetween = xing.getBlockBoundaries();
818            boolean blockBoundaries = false;
819            if (jmri.InstanceManager.getDefault(LayoutBlockManager.class).isAdvancedRoutingEnabled()) {
820                if (blockACAssigned && !blockBDAssigned) {
821                    popup.add(new AbstractAction(Bundle.getMessage("ViewBlockRouting")) {
822                        @Override
823                        public void actionPerformed(ActionEvent e) {
824                            AbstractAction routeTableAction = new LayoutBlockRouteTableAction("ViewRouting", getLayoutBlockAC());
825                            routeTableAction.actionPerformed(e);
826                        }
827                    });
828                } else if (!blockACAssigned && blockBDAssigned) {
829                    popup.add(new AbstractAction(Bundle.getMessage("ViewBlockRouting")) {
830                        @Override
831                        public void actionPerformed(ActionEvent e) {
832                            AbstractAction routeTableAction = new LayoutBlockRouteTableAction("ViewRouting", getLayoutBlockBD());
833                            routeTableAction.actionPerformed(e);
834                        }
835                    });
836                } else if (blockACAssigned && blockBDAssigned) {
837                    JMenu viewRouting = new JMenu(Bundle.getMessage("ViewBlockRouting"));
838                    viewRouting.add(new AbstractAction(getLayoutBlockAC().getDisplayName()) {
839                        @Override
840                        public void actionPerformed(ActionEvent e) {
841                            AbstractAction routeTableAction = new LayoutBlockRouteTableAction(getLayoutBlockAC().getDisplayName(), getLayoutBlockAC());
842                            routeTableAction.actionPerformed(e);
843                        }
844                    });
845
846                    viewRouting.add(new AbstractAction(getLayoutBlockBD().getDisplayName()) {
847                        @Override
848                        public void actionPerformed(ActionEvent e) {
849                            AbstractAction routeTableAction = new LayoutBlockRouteTableAction(getLayoutBlockBD().getDisplayName(), getLayoutBlockBD());
850                            routeTableAction.actionPerformed(e);
851                        }
852                    });
853
854                    popup.add(viewRouting);
855                }
856            }
857
858            for (int i = 0; i < 4; i++) {
859                if (boundaryBetween[i] != null) {
860                    blockBoundaries = true;
861                }
862            }
863            if (blockBoundaries) {
864                popup.add(new AbstractAction(Bundle.getMessage("SetSignalMasts")) {
865                    @Override
866                    public void actionPerformed(ActionEvent e) {
867                        LayoutEditorToolBarPanel letbp = getLayoutEditorToolBarPanel();
868                        layoutEditor.getLETools().
869                                setSignalMastsAtLevelXingFromMenu(
870                                        xing, boundaryBetween,
871                                        letbp.signalFrame);
872                    }
873                });
874                popup.add(new AbstractAction(Bundle.getMessage("SetSensors")) {
875                    @Override
876                    public void actionPerformed(ActionEvent e) {
877                        LayoutEditorToolBarPanel letbp = getLayoutEditorToolBarPanel();
878                        layoutEditor.getLETools().setSensorsAtLevelXingFromMenu(
879                                xing, boundaryBetween,
880                                letbp.sensorIconEditor,
881                                letbp.sensorFrame);
882                    }
883                });
884            }
885
886            layoutEditor.setShowAlignmentMenu(popup);
887            popup.show(mouseEvent.getComponent(), mouseEvent.getX(), mouseEvent.getY());
888        } else if (!viewAdditionalMenu.isEmpty()) {
889            setAdditionalViewPopUpMenu(popup);
890            popup.show(mouseEvent.getComponent(), mouseEvent.getX(), mouseEvent.getY());
891        }
892        return popup;
893    }   // showPopup
894
895//     public String[] getBlockBoundaries() {
896//         final String[] boundaryBetween = new String[4];
897// 
898//         String blockNameAC = getBlockNameAC();
899//         String blockNameBD = getBlockNameBD();
900// 
901//         LayoutBlock blockAC = getLayoutBlockAC();
902//         LayoutBlock blockBD = getLayoutBlockAC();
903// 
904//         if (!blockNameAC.isEmpty() && (blockAC != null)) {
905//             if ((connectA instanceof TrackSegment) && (((TrackSegment) connectA).getLayoutBlock() != blockAC)) {
906//                 try {
907//                     boundaryBetween[0] = (((TrackSegment) connectA).getLayoutBlock().getDisplayName() + " - " + blockAC.getDisplayName());
908//                 } catch (java.lang.NullPointerException e) {
909//                     //Can be considered normal if tracksegement hasn't yet been allocated a block
910//                     log.debug("TrackSegement at connection A doesn't contain a layout block");
911//                 }
912//             }
913//             if ((connectC instanceof TrackSegment) && (((TrackSegment) connectC).getLayoutBlock() != blockAC)) {
914//                 try {
915//                     boundaryBetween[2] = (((TrackSegment) connectC).getLayoutBlock().getDisplayName() + " - " + blockAC.getDisplayName());
916//                 } catch (java.lang.NullPointerException e) {
917//                     //Can be considered normal if tracksegement hasn't yet been allocated a block
918//                     log.debug("TrackSegement at connection C doesn't contain a layout block");
919//                 }
920//             }
921//         }
922//         if (!blockNameBD.isEmpty() && (blockBD != null)) {
923//             if ((connectB instanceof TrackSegment) && (((TrackSegment) connectB).getLayoutBlock() != blockBD)) {
924//                 try {
925//                     boundaryBetween[1] = (((TrackSegment) connectB).getLayoutBlock().getDisplayName() + " - " + blockBD.getDisplayName());
926//                 } catch (java.lang.NullPointerException e) {
927//                     //Can be considered normal if tracksegement hasn't yet been allocated a block
928//                     log.debug("TrackSegement at connection B doesn't contain a layout block");
929//                 }
930//             }
931//             if ((connectD instanceof TrackSegment) && (((TrackSegment) connectD).getLayoutBlock() != blockBD)) {
932//                 try {
933//                     boundaryBetween[3] = (((TrackSegment) connectD).getLayoutBlock().getDisplayName() + " - " + blockBD.getDisplayName());
934//                 } catch (java.lang.NullPointerException e) {
935//                     //Can be considered normal if tracksegement hasn't yet been allocated a block
936//                     log.debug("TrackSegement at connection D doesn't contain a layout block");
937//                 }
938//             }
939//         }
940//         return boundaryBetween;
941//     }
942
943    /**
944     * Clean up when this object is no longer needed. Should not be called while
945     * the object is still displayed; see remove().
946     */
947    public void dispose() {
948        if (popup != null) {
949            popup.removeAll();
950        }
951        popup = null;
952    }
953
954    /**
955     * Remove this object from display and persistance.
956     */
957//     public void remove() {
958//         // remove from persistance by flagging inactive
959//         active = false;
960//     }
961// 
962//     boolean active = true;
963// 
964//     *
965//      * "active" means that the object is still displayed, and should be stored.
966//      */
967//     public boolean isActive() {
968//         return active;
969//     }
970
971//     ArrayList<SignalMast> sml = new ArrayList<>();
972// 
973//     public void addSignalMastLogic(SignalMast sm) {
974//         if (sml.contains(sm)) {
975//             return;
976//         }
977//         if (sml.isEmpty()) {
978//             sml.add(sm);
979//             return;
980//         }
981//         SignalMastLogic sl = InstanceManager.getDefault(jmri.SignalMastLogicManager.class).getSignalMastLogic(sm);
982//         for (SignalMast signalMast : sml) {
983//             SignalMastLogic s = InstanceManager.getDefault(SignalMastLogicManager.class).getSignalMastLogic(signalMast);
984//             if (s != null) {
985//                 s.setConflictingLogic(sm, xing);
986//             }
987//             sl.setConflictingLogic(signalMast, xing);
988//         }
989//         sml.add(sm);
990//     }
991// 
992//     public void removeSignalMastLogic(SignalMast sm) {
993//         if (!sml.contains(sm)) {
994//             return;
995//         }
996//         sml.remove(sm);
997//         if (sml.isEmpty()) {
998//             return;
999//         }
1000//         for (int i = 0; i < sml.size(); i++) {
1001//             SignalMastLogic s = InstanceManager.getDefault(jmri.SignalMastLogicManager.class).getSignalMastLogic(sm);
1002//             if (s != null) {
1003//                 s.removeConflictingLogic(sm, xing);
1004//             }
1005//         }
1006//     }
1007
1008    ArrayList<JMenuItem> editAdditionalMenu = new ArrayList<>(0);
1009    ArrayList<JMenuItem> viewAdditionalMenu = new ArrayList<>(0);
1010
1011    public void addEditPopUpMenu(JMenuItem menu) {
1012        if (!editAdditionalMenu.contains(menu)) {
1013            editAdditionalMenu.add(menu);
1014        }
1015    }
1016
1017    public void addViewPopUpMenu(JMenuItem menu) {
1018        if (!viewAdditionalMenu.contains(menu)) {
1019            viewAdditionalMenu.add(menu);
1020        }
1021    }
1022
1023    public void setAdditionalEditPopUpMenu(JPopupMenu popup) {
1024        if (editAdditionalMenu.isEmpty()) {
1025            return;
1026        }
1027        popup.addSeparator();
1028        for (JMenuItem mi : editAdditionalMenu) {
1029            popup.add(mi);
1030        }
1031    }
1032
1033    public void setAdditionalViewPopUpMenu(JPopupMenu popup) {
1034        if (viewAdditionalMenu.isEmpty()) {
1035            return;
1036        }
1037        popup.addSeparator();
1038        for (JMenuItem mi : viewAdditionalMenu) {
1039            popup.add(mi);
1040        }
1041    }
1042
1043    /**
1044     * Draw track decorations.
1045     * 
1046     * This type of track has none, so this method is empty.
1047     */
1048    @Override
1049    protected void drawDecorations(Graphics2D g2) {}
1050
1051    /**
1052     * Draw this level crossing.
1053     *
1054     * @param g2 the graphics port to draw to
1055     */
1056    @Override
1057    protected void draw1(Graphics2D g2, boolean isMain, boolean isBlock) {
1058        if (isMain == isMainlineAC()) {
1059            if (isBlock) {
1060                setColorForTrackBlock(g2, getLayoutBlockAC());
1061            }
1062            g2.draw(new Line2D.Double(getCoordsA(), getCoordsC()));
1063        }
1064        if (isMain == isMainlineBD()) {
1065            if (isBlock) {
1066                setColorForTrackBlock(g2, getLayoutBlockBD());
1067            }
1068            g2.draw(new Line2D.Double(getCoordsB(), getCoordsD()));
1069        }
1070    }
1071
1072    /**
1073     * {@inheritDoc}
1074     */
1075    @Override
1076    protected void draw2(Graphics2D g2, boolean isMain, float railDisplacement) {
1077        Point2D pA = getCoordsA();
1078        Point2D pB = getCoordsB();
1079        Point2D pC = getCoordsC();
1080        Point2D pD = getCoordsD();
1081        Point2D pM = getCoordsCenter();
1082
1083        Point2D vAC = MathUtil.normalize(MathUtil.subtract(pC, pA), railDisplacement);
1084        double dirAC_DEG = MathUtil.computeAngleDEG(pA, pC);
1085        Point2D vACo = MathUtil.orthogonal(vAC);
1086        Point2D pAL = MathUtil.subtract(pA, vACo);
1087        Point2D pAR = MathUtil.add(pA, vACo);
1088        Point2D pCL = MathUtil.subtract(pC, vACo);
1089        Point2D pCR = MathUtil.add(pC, vACo);
1090
1091        Point2D vBD = MathUtil.normalize(MathUtil.subtract(pD, pB), railDisplacement);
1092        double dirBD_DEG = MathUtil.computeAngleDEG(pB, pD);
1093        Point2D vBDo = MathUtil.orthogonal(vBD);
1094        Point2D pBL = MathUtil.subtract(pB, vBDo);
1095        Point2D pBR = MathUtil.add(pB, vBDo);
1096        Point2D pDL = MathUtil.subtract(pD, vBDo);
1097        Point2D pDR = MathUtil.add(pD, vBDo);
1098
1099        double deltaDEG = MathUtil.absDiffAngleDEG(dirAC_DEG, dirBD_DEG);
1100        double deltaRAD = Math.toRadians(deltaDEG);
1101
1102        double hypotK = railDisplacement / Math.cos((PI - deltaRAD) / 2.0);
1103        double hypotV = railDisplacement / Math.cos(deltaRAD / 2.0);
1104
1105        log.debug("dir AC: {}, BD: {}, diff: {}", dirAC_DEG, dirBD_DEG, deltaDEG);
1106
1107        Point2D vDisK = MathUtil.normalize(MathUtil.add(vAC, vBD), hypotK);
1108        Point2D vDisV = MathUtil.normalize(MathUtil.orthogonal(vDisK), hypotV);
1109        Point2D pKL = MathUtil.subtract(pM, vDisK);
1110        Point2D pKR = MathUtil.add(pM, vDisK);
1111        Point2D pVL = MathUtil.subtract(pM, vDisV);
1112        Point2D pVR = MathUtil.add(pM, vDisV);
1113
1114        if (isMain == isMainlineAC()) {
1115            // this is the *2.0 vector (rail gap) for the AC diamond parts
1116            Point2D vAC2 = MathUtil.normalize(vAC, 2.0);
1117            // KL toward C, VR toward A, VL toward C and KR toward A
1118            Point2D pKLtC = MathUtil.add(pKL, vAC2);
1119            Point2D pVRtA = MathUtil.subtract(pVR, vAC2);
1120            Point2D pVLtC = MathUtil.add(pVL, vAC2);
1121            Point2D pKRtA = MathUtil.subtract(pKR, vAC2);
1122
1123            // draw right AC rail: AR====KL == VR====CR
1124            g2.draw(new Line2D.Double(pAR, pKL));
1125            g2.draw(new Line2D.Double(pKLtC, pVRtA));
1126            g2.draw(new Line2D.Double(pVR, pCR));
1127
1128            // draw left AC rail: AL====VL == KR====CL
1129            g2.draw(new Line2D.Double(pAL, pVL));
1130            g2.draw(new Line2D.Double(pVLtC, pKRtA));
1131            g2.draw(new Line2D.Double(pKR, pCL));
1132        }
1133        if (isMain == isMainlineBD()) {
1134            // this is the *2.0 vector (rail gap) for the BD diamond parts
1135            Point2D vBD2 = MathUtil.normalize(vBD, 2.0);
1136            // VR toward D, KR toward B, KL toward D and VL toward B
1137            Point2D pVRtD = MathUtil.add(pVR, vBD2);
1138            Point2D pKRtB = MathUtil.subtract(pKR, vBD2);
1139            Point2D pKLtD = MathUtil.add(pKL, vBD2);
1140            Point2D pVLtB = MathUtil.subtract(pVL, vBD2);
1141
1142            // draw right BD rail: BR====VR == KR====DR
1143            g2.draw(new Line2D.Double(pBR, pVR));
1144            g2.draw(new Line2D.Double(pVRtD, pKRtB));
1145            g2.draw(new Line2D.Double(pKR, pDR));
1146
1147            // draw left BD rail: BL====KL == VL====DL
1148            g2.draw(new Line2D.Double(pBL, pKL));
1149            g2.draw(new Line2D.Double(pKLtD, pVLtB));
1150            g2.draw(new Line2D.Double(pVL, pDL));
1151        }
1152    }
1153
1154    /**
1155     * {@inheritDoc}
1156     */
1157    @Override
1158    protected void highlightUnconnected(Graphics2D g2, HitPointType specificType) {
1159        if (((specificType == HitPointType.NONE) || (specificType == HitPointType.LEVEL_XING_A))
1160                && (getConnectA() == null)) {
1161            g2.fill(trackControlCircleAt(getCoordsA()));
1162        }
1163
1164        if (((specificType == HitPointType.NONE) || (specificType == HitPointType.LEVEL_XING_B))
1165                && (getConnectB() == null)) {
1166            g2.fill(trackControlCircleAt(getCoordsB()));
1167        }
1168
1169        if (((specificType == HitPointType.NONE) || (specificType == HitPointType.LEVEL_XING_C))
1170                && (getConnectC() == null)) {
1171            g2.fill(trackControlCircleAt(getCoordsC()));
1172        }
1173
1174        if (((specificType == HitPointType.NONE) || (specificType == HitPointType.LEVEL_XING_D))
1175                && (getConnectD() == null)) {
1176            g2.fill(trackControlCircleAt(getCoordsD()));
1177        }
1178    }
1179
1180    @Override
1181    protected void drawEditControls(Graphics2D g2) {
1182        g2.setColor(layoutEditor.getDefaultTrackColorColor());
1183        g2.draw(trackEditControlCircleAt(getCoordsCenter()));
1184
1185        if (getConnectA() == null) {
1186            g2.setColor(Color.magenta);
1187        } else {
1188            g2.setColor(Color.blue);
1189        }
1190        g2.draw(layoutEditor.layoutEditorControlRectAt(getCoordsA()));
1191
1192        if (getConnectB() == null) {
1193            g2.setColor(Color.red);
1194        } else {
1195            g2.setColor(Color.green);
1196        }
1197        g2.draw(layoutEditor.layoutEditorControlRectAt(getCoordsB()));
1198
1199        if (getConnectC() == null) {
1200            g2.setColor(Color.red);
1201        } else {
1202            g2.setColor(Color.green);
1203        }
1204        g2.draw(layoutEditor.layoutEditorControlRectAt(getCoordsC()));
1205
1206        if (getConnectD() == null) {
1207            g2.setColor(Color.red);
1208        } else {
1209            g2.setColor(Color.green);
1210        }
1211        g2.draw(layoutEditor.layoutEditorControlRectAt(getCoordsD()));
1212    }
1213
1214    @Override
1215    protected void drawTurnoutControls(Graphics2D g2) {
1216        // LevelXings don't have turnout controls...
1217        // nothing to see here... move along...
1218    }
1219
1220    /*
1221    * {@inheritDoc}
1222     */
1223    @Override
1224    public void reCheckBlockBoundary() {
1225        // nothing to see here... move along...
1226    }
1227
1228    /*
1229    * {@inheritDoc} temporary
1230     */
1231    @Override
1232    protected ArrayList<LayoutConnectivity> getLayoutConnectivity() {
1233        // nothing to see here... move along...
1234        return null;
1235    }
1236
1237    /**
1238     * {@inheritDoc}
1239     */
1240     @Override
1241     public List<HitPointType> checkForFreeConnections() {
1242        throw new IllegalArgumentException("should have called Object instead of view temporary");
1243//         List<HitPointType> result = new ArrayList<>();
1244// 
1245//         //check the A connection point
1246//         if (getConnectA() == null) {
1247//             result.add(HitPointType.LEVEL_XING_A);
1248//         }
1249// 
1250//         //check the B connection point
1251//         if (getConnectB() == null) {
1252//             result.add(HitPointType.LEVEL_XING_B);
1253//         }
1254// 
1255//         //check the C connection point
1256//         if (getConnectC() == null) {
1257//             result.add(HitPointType.LEVEL_XING_C);
1258//         }
1259// 
1260//         //check the D connection point
1261//         if (getConnectD() == null) {
1262//             result.add(HitPointType.LEVEL_XING_D);
1263//         }
1264//         return result;
1265     }
1266
1267    /**
1268     * {@inheritDoc}
1269     */
1270    @Override
1271    public boolean checkForUnAssignedBlocks() {
1272//         return ((getLayoutBlockAC() != null) && (getLayoutBlockBD() != null));
1273        throw new IllegalArgumentException("should have called Object instead of View temporary");
1274   }
1275
1276    /**
1277     * {@inheritDoc}
1278     */
1279    @Override
1280    public void checkForNonContiguousBlocks(
1281            @Nonnull HashMap<String, List<Set<String>>> blockNamesToTrackNameSetsMap) {
1282        throw new IllegalArgumentException("should have called Object instead of View temporary");
1283
1284        /*
1285        * For each (non-null) blocks of this track do:
1286        * #1) If it's got an entry in the blockNamesToTrackNameSetMap then
1287        * #2) If this track is already in the TrackNameSet for this block
1288        *     then return (done!)
1289        * #3) else add a new set (with this block/track) to
1290        *     blockNamesToTrackNameSetMap and check all the connections in this
1291        *     block (by calling the 2nd method below)
1292        * <p>
1293        *     Basically, we're maintaining contiguous track sets for each block found
1294        *     (in blockNamesToTrackNameSetMap)
1295         */
1296
1297        // We're only using a map here because it's convient to
1298        // use it to pair up blocks and connections
1299//         Map<LayoutTrack, String> blocksAndTracksMap = new HashMap<>();
1300//         if ((getLayoutBlockAC() != null) && (connectA != null)) {
1301//             blocksAndTracksMap.put(connectA, getLayoutBlockAC().getDisplayName());
1302//         }
1303//         if ((getLayoutBlockAC() != null) && (connectC != null)) {
1304//             blocksAndTracksMap.put(connectC, getLayoutBlockAC().getDisplayName());
1305//         }
1306//         if ((getLayoutBlockBD() != null) && (connectB != null)) {
1307//             blocksAndTracksMap.put(connectB, getLayoutBlockBD().getDisplayName());
1308//         }
1309//         if ((getLayoutBlockBD() != null) && (connectD != null)) {
1310//             blocksAndTracksMap.put(connectD, getLayoutBlockBD().getDisplayName());
1311//         }
1312// 
1313//         List<Set<String>> TrackNameSets = null;
1314//         Set<String> TrackNameSet = null;
1315//         for (Map.Entry<LayoutTrack, String> entry : blocksAndTracksMap.entrySet()) {
1316//             LayoutTrack theConnect = entry.getKey();
1317//             String theBlockName = entry.getValue();
1318// 
1319//             TrackNameSet = null;    // assume not found (pessimist!)
1320//             TrackNameSets = blockNamesToTrackNameSetsMap.get(theBlockName);
1321//             if (TrackNameSets != null) { // (#1)
1322//                 for (Set<String> checkTrackNameSet : TrackNameSets) {
1323//                     if (checkTrackNameSet.contains(getName())) { // (#2)
1324//                         TrackNameSet = checkTrackNameSet;
1325//                         break;
1326//                     }
1327//                 }
1328//             } else {    // (#3)
1329//                 log.debug("*New block ('{}') trackNameSets", theBlockName);
1330//                 TrackNameSets = new ArrayList<>();
1331//                 blockNamesToTrackNameSetsMap.put(theBlockName, TrackNameSets);
1332//             }
1333//             if (TrackNameSet == null) {
1334//                 TrackNameSet = new LinkedHashSet<>();
1335//                 TrackNameSets.add(TrackNameSet);
1336//             }
1337//             if (TrackNameSet.add(getName())) {
1338//                 log.debug("*    Add track ''{}'' to trackNameSet for block ''{}''", getName(), theBlockName);
1339//             }
1340//             theConnect.collectContiguousTracksNamesInBlockNamed(theBlockName, TrackNameSet);
1341//         }
1342    }   // collectContiguousTracksNamesInBlockNamed
1343
1344    /**
1345     * {@inheritDoc}
1346     */
1347     @Override
1348     public void collectContiguousTracksNamesInBlockNamed(@Nonnull String blockName,
1349            @Nonnull Set<String> TrackNameSet) {
1350        throw new IllegalArgumentException("should have called Object instead of View temporary");
1351//         if (!TrackNameSet.contains(getName())) {
1352//             // check all the matching blocks in this track and...
1353//             //  #1) add us to TrackNameSet and...
1354//             //  #2) flood them
1355//             //check the AC blockName
1356//             if (getBlockNameAC().equals(blockName)) {
1357//                 // if we are added to the TrackNameSet
1358//                 if (TrackNameSet.add(getName())) {
1359//                     log.debug("*    Add track ''{}'for block ''{}''", getName(), blockName);
1360//                 }
1361//                 // it's time to play... flood your neighbours!
1362//                 if (connectA != null) {
1363//                     connectA.collectContiguousTracksNamesInBlockNamed(blockName, TrackNameSet);
1364//                 }
1365//                 if (connectC != null) {
1366//                     connectC.collectContiguousTracksNamesInBlockNamed(blockName, TrackNameSet);
1367//                 }
1368//             }
1369//             //check the BD blockName
1370//             if (getBlockNameBD().equals(blockName)) {
1371//                 // if we are added to the TrackNameSet
1372//                 if (TrackNameSet.add(getName())) {
1373//                     log.debug("*    Add track ''{}''for block ''{}''", getName(), blockName);
1374//                 }
1375//                 // it's time to play... flood your neighbours!
1376//                 if (connectB != null) {
1377//                     connectB.collectContiguousTracksNamesInBlockNamed(blockName, TrackNameSet);
1378//                 }
1379//                 if (connectD != null) {
1380//                     connectD.collectContiguousTracksNamesInBlockNamed(blockName, TrackNameSet);
1381//                 }
1382//             }
1383//         }
1384    }
1385
1386    /**
1387     * {@inheritDoc}
1388     */
1389     @Override
1390     public void setAllLayoutBlocks(LayoutBlock layoutBlock) {
1391        throw new IllegalArgumentException("should have called Object instead of View temporary");
1392//         setLayoutBlockAC(layoutBlock);
1393//         setLayoutBlockBD(layoutBlock);
1394     }
1395
1396    private final static org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(LevelXingView.class);
1397}