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