001package jmri.jmrit.display.layoutEditor.configurexml;
002
003import java.awt.geom.Point2D;
004
005import jmri.Turnout;
006import jmri.jmrit.display.layoutEditor.*;
007import org.jdom2.Attribute;
008import org.jdom2.DataConversionException;
009import org.jdom2.Element;
010
011/**
012 * This module handles configuration for display.LayoutTurnout objects for a
013 * LayoutEditor.
014 *
015 * @author David Duchamp Copyright (c) 2007
016 * @author George Warner Copyright (c) 2017-2019
017 * @author Bob Jacobsen Copyright (c) 2020
018 */
019public class LayoutTurnoutViewXml extends LayoutTrackViewXml {
020
021    static final EnumIO<LayoutTurnout.LinkType> linkEnumMap = new EnumIoNamesNumbers<>(LayoutTurnout.LinkType.class);
022    static final EnumIO<LayoutTurnout.TurnoutType> tTypeEnumMap = new EnumIoNamesNumbers<>(LayoutTurnout.TurnoutType.class);
023
024    public LayoutTurnoutViewXml() {
025    }
026
027    protected void addClass(Element element) {
028        element.setAttribute("class", "jmri.jmrit.display.layoutEditor.configurexml.LayoutTurnoutXml");
029    }
030
031    /**
032     * Default implementation for storing the contents of a LayoutTurnout
033     *
034     * @param o Object to store, of type LayoutTurnout
035     * @return Element containing the complete info
036     */
037    @Override
038    public Element store(Object o) {
039
040        LayoutTurnoutView pv = (LayoutTurnoutView) o;
041        LayoutTurnout p = pv.getLayoutTurnout();
042
043        Element element = new Element("layoutturnout");
044
045        // include attributes
046        element.setAttribute("ident", p.getName());
047        element.setAttribute("type", tTypeEnumMap.outputFromEnum(p.getTurnoutType()));
048
049        element.setAttribute("hidden", "" + (pv.isHidden() ? "yes" : "no"));
050        element.setAttribute("disabled", "" + (p.isDisabled() ? "yes" : "no"));
051        element.setAttribute("disableWhenOccupied", "" + (p.isDisabledWhenOccupied() ? "yes" : "no"));
052
053        if (p.showToolTip()) {
054            element.setAttribute("showtooltip", "yes");
055        }
056
057        element.setAttribute("continuing", "" + p.getContinuingSense());
058
059        Point2D coords = pv.getCoordsCenter();
060        element.setAttribute("xcen", "" + coords.getX());
061        element.setAttribute("ycen", "" + coords.getY());
062
063        coords = pv.getCoordsA();
064        element.setAttribute("xa", "" + coords.getX());
065        element.setAttribute("ya", "" + coords.getY());
066
067        coords = pv.getCoordsB();
068        element.setAttribute("xb", "" + coords.getX());
069        element.setAttribute("yb", "" + coords.getY());
070
071        coords = pv.getCoordsC();
072        element.setAttribute("xc", "" + coords.getX());
073        element.setAttribute("yc", "" + coords.getY());
074
075        coords = pv.getCoordsD();
076        element.setAttribute("xd", "" + coords.getX());
077        element.setAttribute("yd", "" + coords.getY());
078
079        element.setAttribute("ver", "" + p.getVersion());
080
081        addClass(element);
082
083        if (!p.getTurnoutName().isEmpty()) {
084            element.setAttribute("turnoutname", p.getTurnoutName());
085        }
086        if (!p.getSecondTurnoutName().isEmpty()) {
087            element.setAttribute("secondturnoutname", p.getSecondTurnoutName());
088            if (p.isSecondTurnoutInverted()) {
089                element.setAttribute("secondturnoutinverted", "true");
090            }
091        }
092
093        if (!p.getLinkedTurnoutName().isEmpty()) {
094            element.setAttribute("linkedturnoutname", p.getLinkedTurnoutName());
095            element.setAttribute("linktype", "" + linkEnumMap.outputFromEnum(p.getLinkType()));
096        }
097
098        if (!p.getBlockName().isEmpty()) {
099            element.setAttribute("blockname", p.getBlockName());
100        }
101        // Only save these if they're different from block A
102        if (!p.getBlockBName().isEmpty() && (!p.getBlockBName().equals(p.getBlockName()))) {
103            element.setAttribute("blockbname", p.getBlockBName());
104        }
105        if (!p.getBlockCName().isEmpty() && (!p.getBlockCName().equals(p.getBlockName()))) {
106            element.setAttribute("blockcname", p.getBlockCName());
107        }
108        if (!p.getBlockDName().isEmpty() && (!p.getBlockDName().equals(p.getBlockName()))) {
109            element.setAttribute("blockdname", p.getBlockDName());
110        }
111
112        if (p.getConnectA() != null) {
113            element.setAttribute("connectaname", ((TrackSegment) p.getConnectA()).getId());
114        }
115        if (p.getConnectB() != null) {
116            element.setAttribute("connectbname", ((TrackSegment) p.getConnectB()).getId());
117        }
118        if (p.getConnectC() != null) {
119            element.setAttribute("connectcname", ((TrackSegment) p.getConnectC()).getId());
120        }
121        if (p.getConnectD() != null) {
122            element.setAttribute("connectdname", ((TrackSegment) p.getConnectD()).getId());
123        }
124
125        if (!p.getSignalA1Name().isEmpty()) {
126            element.setAttribute("signala1name", p.getSignalA1Name());
127        }
128        if (!p.getSignalA2Name().isEmpty()) {
129            element.setAttribute("signala2name", p.getSignalA2Name());
130        }
131        if (!p.getSignalA3Name().isEmpty()) {
132            element.setAttribute("signala3name", p.getSignalA3Name());
133        }
134        if (!p.getSignalB1Name().isEmpty()) {
135            element.setAttribute("signalb1name", p.getSignalB1Name());
136        }
137        if (!p.getSignalB2Name().isEmpty()) {
138            element.setAttribute("signalb2name", p.getSignalB2Name());
139        }
140        if (!p.getSignalC1Name().isEmpty()) {
141            element.setAttribute("signalc1name", p.getSignalC1Name());
142        }
143        if (!p.getSignalC2Name().isEmpty()) {
144            element.setAttribute("signalc2name", p.getSignalC2Name());
145        }
146        if (!p.getSignalD1Name().isEmpty()) {
147            element.setAttribute("signald1name", p.getSignalD1Name());
148        }
149        if (!p.getSignalD2Name().isEmpty()) {
150            element.setAttribute("signald2name", p.getSignalD2Name());
151        }
152
153        if (!p.getSignalAMastName().isEmpty()) {
154            element.addContent(new Element("signalAMast").addContent(p.getSignalAMastName()));
155        }
156
157        if (!p.getSignalBMastName().isEmpty()) {
158            element.addContent(new Element("signalBMast").addContent(p.getSignalBMastName()));
159        }
160        if (!p.getSignalCMastName().isEmpty()) {
161            element.addContent(new Element("signalCMast").addContent(p.getSignalCMastName()));
162        }
163        if (!p.getSignalDMastName().isEmpty()) {
164            element.addContent(new Element("signalDMast").addContent(p.getSignalDMastName()));
165        }
166
167        if (!p.getSensorAName().isEmpty()) {
168            element.addContent(new Element("sensorA").addContent(p.getSensorAName()));
169        }
170
171        if (!p.getSensorBName().isEmpty()) {
172            element.addContent(new Element("sensorB").addContent(p.getSensorBName()));
173        }
174        if (!p.getSensorCName().isEmpty()) {
175            element.addContent(new Element("sensorC").addContent(p.getSensorCName()));
176        }
177        if (!p.getSensorDName().isEmpty()) {
178            element.addContent(new Element("sensorD").addContent(p.getSensorDName()));
179        }
180        storeLogixNG_Data(pv, element);
181        return element;
182    }
183
184    @Override
185    public boolean load(Element shared, Element perNode) {
186        log.error("Invalid method called");
187        return false;
188    }
189
190    /**
191     * Load, starting with the levelxing element, then all the other data
192     *
193     * @param element Top level Element to unpack.
194     * @param o       LayoutEditor as an Object
195     */
196    @Override
197    public void load(Element element, Object o) {
198        // create the objects
199        LayoutEditor p = (LayoutEditor) o;
200
201        // get center point
202        String name = element.getAttribute("ident").getValue();
203        double x = 0.0;
204        double y = 0.0;
205        LayoutTurnout.TurnoutType type = LayoutTurnout.TurnoutType.NONE;
206        try {
207            x = element.getAttribute("xcen").getFloatValue();
208            y = element.getAttribute("ycen").getFloatValue();
209            type = tTypeEnumMap.inputFromAttribute(element.getAttribute("type"));
210        } catch (org.jdom2.DataConversionException e) {
211            log.error("failed to convert layoutturnout attribute");
212        }
213
214        int version = 1;
215        try {
216            if (element.getAttribute("ver") != null) {
217                version = element.getAttribute("ver").getIntValue();
218            }
219        } catch (org.jdom2.DataConversionException e) {
220            log.error("failed to convert layoutturnout version attribute");
221        }
222
223        // create the new LayoutTurnout of the correct type
224        LayoutTurnoutView lv;
225        LayoutTurnout l;
226
227        switch(type) {
228
229            case RH_TURNOUT :
230                LayoutRHTurnout lrht = new LayoutRHTurnout(name, p, version);
231                l = lrht;
232                lv = new LayoutRHTurnoutView(lrht, new Point2D.Double(x, y), 0.0, 1.0, 1.0, p);
233                break;
234            case LH_TURNOUT :
235                LayoutLHTurnout llht = new LayoutLHTurnout(name, p, version);
236                l = llht;
237                lv = new LayoutLHTurnoutView(llht, new Point2D.Double(x, y), 0.0, 1.0, 1.0, p);
238                break;
239            case WYE_TURNOUT :
240                LayoutWye lwt = new LayoutWye(name, p, version);
241                l = lwt;
242                lv = new LayoutWyeView(lwt, new Point2D.Double(x, y), 0.0, 1.0, 1.0, p);
243                break;
244            case DOUBLE_XOVER :
245                LayoutDoubleXOver ldx = new LayoutDoubleXOver(name, p, version);
246                l = ldx;
247                lv = new LayoutDoubleXOverView(ldx, new Point2D.Double(x, y), 0.0, 1.0, 1.0, p);
248                break;
249            case RH_XOVER :
250                LayoutRHXOver lrx = new LayoutRHXOver(name, p, version);
251                l = lrx;
252                lv = new LayoutRHXOverView(lrx, new Point2D.Double(x, y), 0.0, 1.0, 1.0, p);
253                break;
254            case LH_XOVER :
255                LayoutLHXOver llx = new LayoutLHXOver(name, p, version);
256                l = llx;
257                lv = new LayoutLHXOverView(llx, new Point2D.Double(x, y), 0.0, 1.0, 1.0, p);
258                break;
259
260            case DOUBLE_SLIP :
261                LayoutDoubleSlip lds = new LayoutDoubleSlip(name, p);
262                l = lds;
263                lv = new LayoutDoubleSlipView(lds, new Point2D.Double(x, y), 0.0, p);
264                log.error("Found DOUBLE_SLIP in LayoutTrack ctor for element {}", name);
265                break;
266            case SINGLE_SLIP :
267                LayoutSingleSlip lss = new LayoutSingleSlip(name, p);
268                l = lss;
269                lv = new LayoutSingleSlipView(lss, new Point2D.Double(x, y), 0.0, p);
270                log.error("Found SINGLE_SLIP in LayoutTrack ctor for element {}", name);
271                break;
272
273            default:
274                log.error("can't create LayoutTrack {} with type {}", name, type);
275                return; // without creating
276        }
277
278        p.addLayoutTrack(l, lv);
279
280        // get remaining attributes
281        Attribute a = element.getAttribute("turnoutname");
282        if (a != null) {
283            l.setTurnout(a.getValue());
284        }
285        a = element.getAttribute("secondturnoutname");
286        if (a != null) {
287            l.setSecondTurnout(a.getValue());
288            try {
289                l.setSecondTurnoutInverted(element.getAttribute("secondturnoutinverted").getBooleanValue());
290            } catch (DataConversionException e1) {
291                log.warn("unable to convert layout turnout secondturnoutinverted attribute");
292            } catch (NullPointerException e) {  // considered normal if the attribute is not present
293            }
294        }
295
296        a = element.getAttribute("blockname");
297        if (a != null) {
298            l.tBlockAName = a.getValue();
299        }
300        a = element.getAttribute("blockbname");
301        if (a != null) {
302            l.tBlockBName = a.getValue();
303        }
304        a = element.getAttribute("blockcname");
305        if (a != null) {
306            l.tBlockCName = a.getValue();
307        }
308        a = element.getAttribute("blockdname");
309        if (a != null) {
310            l.tBlockDName = a.getValue();
311        }
312
313        a = element.getAttribute("connectaname");
314        if (a != null) {
315            l.connectAName = a.getValue();
316        }
317        a = element.getAttribute("connectbname");
318        if (a != null) {
319            l.connectBName = a.getValue();
320        }
321        a = element.getAttribute("connectcname");
322        if (a != null) {
323            l.connectCName = a.getValue();
324        }
325        a = element.getAttribute("connectdname");
326        if (a != null) {
327            l.connectDName = a.getValue();
328        }
329
330        a = element.getAttribute("signala1name");
331        if (a != null) {
332            l.setSignalA1Name(a.getValue());
333        }
334        a = element.getAttribute("signala2name");
335        if (a != null) {
336            l.setSignalA2Name(a.getValue());
337        }
338        a = element.getAttribute("signala3name");
339        if (a != null) {
340            l.setSignalA3Name(a.getValue());
341        }
342        a = element.getAttribute("signalb1name");
343        if (a != null) {
344            l.setSignalB1Name(a.getValue());
345        }
346        a = element.getAttribute("signalb2name");
347        if (a != null) {
348            l.setSignalB2Name(a.getValue());
349        }
350        a = element.getAttribute("signalc1name");
351        if (a != null) {
352            l.setSignalC1Name(a.getValue());
353        }
354        a = element.getAttribute("signalc2name");
355        if (a != null) {
356            l.setSignalC2Name(a.getValue());
357        }
358        a = element.getAttribute("signald1name");
359        if (a != null) {
360            l.setSignalD1Name(a.getValue());
361        }
362        a = element.getAttribute("signald2name");
363        if (a != null) {
364            l.setSignalD2Name(a.getValue());
365        }
366        a = element.getAttribute("linkedturnoutname");
367        if (a != null) {
368            l.linkedTurnoutName = a.getValue();
369            l.linkType = linkEnumMap.inputFromAttribute(element.getAttribute("linktype"));
370        }
371        a = element.getAttribute("continuing");
372        if (a != null) {
373            int continuing = Turnout.CLOSED;
374            try {
375                continuing = element.getAttribute("continuing").getIntValue();
376            } catch (org.jdom2.DataConversionException e) {
377                log.error("failed to convert continuingsense attribute");
378            }
379            l.setContinuingSense(continuing);
380        }
381        try {
382            l.setDisabled(element.getAttribute("disabled").getBooleanValue());
383        } catch (DataConversionException e1) {
384            log.warn("unable to convert layout turnout disabled attribute");
385        } catch (NullPointerException e) {  // considered normal if the attribute is not present
386        }
387        try {
388            l.setDisableWhenOccupied(element.getAttribute("disableWhenOccupied").getBooleanValue());
389        } catch (DataConversionException e1) {
390            log.warn("unable to convert layout turnout disableWhenOccupied attribute");
391        } catch (NullPointerException e) {  // considered normal if the attribute is not present
392        }
393        try {
394            lv.setHidden(element.getAttribute("hidden").getBooleanValue());
395        } catch (DataConversionException e1) {
396            log.warn("unable to convert layout turnout hidden attribute");
397        } catch (NullPointerException e) {  // considered normal if the attribute is not present
398        }
399
400        l.setShowToolTip(false);
401        a = element.getAttribute("showtooltip");
402        if (a != null) {
403            if ("yes".equals(a.getValue())) {
404                l.setShowToolTip(true);
405            }
406        }
407
408        if (version == 2) {
409            try {
410                x = element.getAttribute("xa").getFloatValue();
411                y = element.getAttribute("ya").getFloatValue();
412                lv.setCoordsA(new Point2D.Double(x, y));
413            } catch (org.jdom2.DataConversionException e) {
414                log.error("failed to convert layoutturnout b coords attribute");
415            } catch (java.lang.NullPointerException e) {
416                //can be ignored as panel file may not support method
417            }
418        }
419        try {
420            x = element.getAttribute("xb").getFloatValue();
421            y = element.getAttribute("yb").getFloatValue();
422            lv.setCoordsB(new Point2D.Double(x, y));
423        } catch (org.jdom2.DataConversionException e) {
424            log.error("failed to convert layoutturnout b coords attribute");
425        }
426        try {
427            x = element.getAttribute("xc").getFloatValue();
428            y = element.getAttribute("yc").getFloatValue();
429            lv.setCoordsC(new Point2D.Double(x, y));
430        } catch (org.jdom2.DataConversionException e) {
431            log.error("failed to convert layoutturnout c coords attribute");
432        }
433        if (version == 2) {
434            try {
435                x = element.getAttribute("xd").getFloatValue();
436                y = element.getAttribute("yd").getFloatValue();
437                lv.setCoordsD(new Point2D.Double(x, y));
438            } catch (org.jdom2.DataConversionException e) {
439                log.error("failed to convert layoutturnout c coords attribute");
440            } catch (java.lang.NullPointerException e) {
441                //can be ignored as panel file may not support method
442            }
443        }
444
445        l.setSignalAMast(getElement(element, "signalAMast"));
446        l.setSignalBMast(getElement(element, "signalBMast"));
447        l.setSignalCMast(getElement(element, "signalCMast"));
448        l.setSignalDMast(getElement(element, "signalDMast"));
449
450        l.setSensorA(getElement(element, "sensorA"));
451        l.setSensorB(getElement(element, "sensorB"));
452        l.setSensorC(getElement(element, "sensorC"));
453        l.setSensorD(getElement(element, "sensorD"));
454
455        loadLogixNG_Data(lv, element);
456    }
457
458    String getElement(Element el, String child) {
459        if (el.getChild(child) != null) {
460            return el.getChild(child).getText();
461        }
462        return "";
463    }
464
465    private final static org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(LayoutTurnoutViewXml.class);
466}