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