001package jmri.jmrit.display.layoutEditor.configurexml;
002
003import java.awt.geom.Point2D;
004import jmri.jmrit.display.layoutEditor.*;
005import org.jdom2.Attribute;
006import org.jdom2.DataConversionException;
007import org.jdom2.Element;
008
009/**
010 * This module handles configuration for display.LayoutSlipView objects for a
011 * LayoutEditor.
012 *
013 * @author David Duchamp Copyright (c) 2007
014 * @author George Warner Copyright (c) 2017-2018
015 * @author Bob Jacobsen Copyright (c) 2020
016 */
017public class LayoutSlipViewXml extends LayoutTrackViewXml {
018
019    public LayoutSlipViewXml() {
020    }
021
022    final static EnumIO<LayoutSlip.TurnoutType> tTypeEnumMap = new EnumIoNamesNumbers<>(LayoutSlip.TurnoutType.class);
023
024    protected void addClass(Element element) {
025        element.setAttribute("class", "jmri.jmrit.display.layoutEditor.configurexml.LayoutSlipXml");
026    }
027
028    /**
029     * Default implementation for storing the contents of a LayoutSlip
030     *
031     * @param o Object to store, of type LayoutSlip
032     * @return Element containing the complete info
033     */
034    @Override
035    public Element store(Object o) {
036
037        LayoutSlipView pv = (LayoutSlipView) o;
038        LayoutSlip p = pv.getSlip();
039
040        Element element = new Element("layoutSlip");
041
042        // include attributes
043        element.setAttribute("ident", p.getName());
044        element.setAttribute("slipType", tTypeEnumMap.outputFromEnum(p.getTurnoutType()));
045
046        element.setAttribute("hidden", "" + (pv.isHidden() ? "yes" : "no"));
047        element.setAttribute("disabled", "" + (p.isDisabled() ? "yes" : "no"));
048        element.setAttribute("disableWhenOccupied", "" + (p.isDisabledWhenOccupied() ? "yes" : "no"));
049
050        if (p.showToolTip()) {
051            element.setAttribute("showtooltip", "yes");
052        }
053
054        Point2D coords = pv.getCoordsCenter();
055        element.setAttribute("xcen", "" + coords.getX());
056        element.setAttribute("ycen", "" + coords.getY());
057        coords = pv.getCoordsA();
058        element.setAttribute("xa", "" + coords.getX());
059        element.setAttribute("ya", "" + coords.getY());
060        coords = pv.getCoordsB();
061        element.setAttribute("xb", "" + coords.getX());
062        element.setAttribute("yb", "" + coords.getY());
063
064        if (!p.getTurnoutName().isEmpty()) {
065            element.addContent(new Element("turnout").addContent(p.getTurnoutName()));
066        }
067
068        if (!p.getTurnoutBName().isEmpty()) {
069            element.addContent(new Element("turnoutB").addContent(p.getTurnoutBName()));
070        }
071
072        if (!p.getBlockName().isEmpty()) {
073            element.setAttribute("blockname", p.getBlockName());
074        }
075        // Only save these if they're different from block A
076        if (!p.getBlockBName().isEmpty() && (!p.getBlockBName().equals(p.getBlockName()))) {
077            element.setAttribute("blockbname", p.getBlockBName());
078        }
079        if (!p.getBlockCName().isEmpty() && (!p.getBlockCName().equals(p.getBlockName()))) {
080            element.setAttribute("blockcname", p.getBlockCName());
081        }
082        if (!p.getBlockDName().isEmpty() && (!p.getBlockDName().equals(p.getBlockName()))) {
083            element.setAttribute("blockdname", p.getBlockDName());
084        }
085
086        if (p.getConnectA() != null) {
087            element.setAttribute("connectaname", ((TrackSegment) p.getConnectA()).getId());
088        }
089        if (p.getConnectB() != null) {
090            element.setAttribute("connectbname", ((TrackSegment) p.getConnectB()).getId());
091        }
092        if (p.getConnectC() != null) {
093            element.setAttribute("connectcname", ((TrackSegment) p.getConnectC()).getId());
094        }
095        if (p.getConnectD() != null) {
096            element.setAttribute("connectdname", ((TrackSegment) p.getConnectD()).getId());
097        }
098
099        if (!p.getSignalA1Name().isEmpty()) {
100            element.addContent(new Element("signala1name").addContent(p.getSignalA1Name()));
101        }
102        if (!p.getSignalB1Name().isEmpty()) {
103            element.addContent(new Element("signalb1name").addContent(p.getSignalB1Name()));
104        }
105        if (!p.getSignalC1Name().isEmpty()) {
106            element.addContent(new Element("signalc1name").addContent(p.getSignalC1Name()));
107        }
108        if (!p.getSignalD1Name().isEmpty()) {
109            element.addContent(new Element("signald1name").addContent(p.getSignalD1Name()));
110        }
111        if (!p.getSignalA2Name().isEmpty()) {
112            element.addContent(new Element("signala2name").addContent(p.getSignalA2Name()));
113        }
114        if (!p.getSignalB2Name().isEmpty()) {
115            element.addContent(new Element("signalb2name").addContent(p.getSignalB2Name()));
116        }
117        if (!p.getSignalC2Name().isEmpty()) {
118            element.addContent(new Element("signalc2name").addContent(p.getSignalC2Name()));
119        }
120        if (!p.getSignalD2Name().isEmpty()) {
121            element.addContent(new Element("signald2name").addContent(p.getSignalD2Name()));
122        }
123
124        if (!p.getSignalAMastName().isEmpty()) {
125            element.addContent(new Element("signalAMast").addContent(p.getSignalAMastName()));
126        }
127
128        if (!p.getSignalBMastName().isEmpty()) {
129            element.addContent(new Element("signalBMast").addContent(p.getSignalBMastName()));
130        }
131        if (!p.getSignalCMastName().isEmpty()) {
132            element.addContent(new Element("signalCMast").addContent(p.getSignalCMastName()));
133        }
134        if (!p.getSignalDMastName().isEmpty()) {
135            element.addContent(new Element("signalDMast").addContent(p.getSignalDMastName()));
136        }
137
138        if (!p.getSensorAName().isEmpty()) {
139            element.addContent(new Element("sensorA").addContent(p.getSensorAName()));
140        }
141
142        if (!p.getSensorBName().isEmpty()) {
143            element.addContent(new Element("sensorB").addContent(p.getSensorBName()));
144        }
145        if (!p.getSensorCName().isEmpty()) {
146            element.addContent(new Element("sensorC").addContent(p.getSensorCName()));
147        }
148        if (!p.getSensorDName().isEmpty()) {
149            element.addContent(new Element("sensorD").addContent(p.getSensorDName()));
150        }
151
152        Element states = new Element("states");
153        Element state = new Element("A-C");
154        state.addContent(new Element("turnout").addContent("" + p.getTurnoutState(LayoutSlip.STATE_AC)));
155        state.addContent(new Element("turnoutB").addContent("" + p.getTurnoutBState(LayoutSlip.STATE_AC)));
156        states.addContent(state);
157
158        state = new Element("A-D");
159        state.addContent(new Element("turnout").addContent("" + p.getTurnoutState(LayoutSlip.STATE_AD)));
160        state.addContent(new Element("turnoutB").addContent("" + p.getTurnoutBState(LayoutSlip.STATE_AD)));
161        states.addContent(state);
162
163        state = new Element("B-D");
164        state.addContent(new Element("turnout").addContent("" + p.getTurnoutState(LayoutSlip.STATE_BD)));
165        state.addContent(new Element("turnoutB").addContent("" + p.getTurnoutBState(LayoutSlip.STATE_BD)));
166        states.addContent(state);
167
168        if (p.getSlipType() == LayoutSlip.TurnoutType.DOUBLE_SLIP) {
169            state = new Element("B-C");
170            state.addContent(new Element("turnout").addContent("" + p.getTurnoutState(LayoutSlip.STATE_BC)));
171            state.addContent(new Element("turnoutB").addContent("" + p.getTurnoutBState(LayoutSlip.STATE_BC)));
172            states.addContent(state);
173        }
174        element.addContent(states);
175        storeLogixNG_Data(pv, element);
176        addClass(element);
177        return element;
178    }
179
180    @Override
181    public boolean load(Element shared, Element perNode) {
182        log.error("Invalid method called");
183        return false;
184    }
185
186    /**
187     * Load, starting with the LayoutSlip element, then all the other data
188     *
189     * @param element Top level Element to unpack.
190     * @param o       LayoutEditor as an Object
191     */
192    @Override
193    public void load(Element element, Object o) {
194        // create the objects
195        LayoutEditor p = (LayoutEditor) o;
196
197        // get center point
198        String name = element.getAttribute("ident").getValue();
199        double x = 0.0;
200        double y = 0.0;
201        try {
202            x = element.getAttribute("xcen").getFloatValue();
203            y = element.getAttribute("ycen").getFloatValue();
204        } catch (org.jdom2.DataConversionException e) {
205            log.error("failed to convert layoutslip center  attribute");
206        }
207
208        LayoutSlip.TurnoutType type =
209                tTypeEnumMap.inputFromAttribute(element.getAttribute("slipType"));
210
211        // create the new LayoutSlip
212        LayoutSlip l;
213        LayoutSlipView lv;
214
215        switch(type) {
216            case DOUBLE_SLIP :
217                LayoutDoubleSlip lds = new LayoutDoubleSlip(name, p);
218                l = lds;
219                lv = new LayoutDoubleSlipView(lds, new Point2D.Double(x, y), 0.0, p);
220                break;
221            case SINGLE_SLIP :
222                LayoutSingleSlip lss = new LayoutSingleSlip(name, p);
223                l = lss;
224                lv = new LayoutSingleSlipView(lss, new Point2D.Double(x, y), 0.0, p);
225                break;
226            default:
227                log.error("can't create slip {} with type {}", name, type);
228                return; // without creating
229        }
230
231        p.addLayoutTrack(l, lv);
232
233        // get remaining attributes
234        l.setTurnout(getElement(element, "turnout"));
235        l.setTurnoutB(getElement(element, "turnoutB"));
236
237        Attribute a = element.getAttribute("blockname");
238        if (a != null) {
239            l.tBlockAName = a.getValue();
240        }
241        a = element.getAttribute("blockbname");
242        if (a != null) {
243            l.tBlockBName = a.getValue();
244        }
245        a = element.getAttribute("blockcname");
246        if (a != null) {
247            l.tBlockCName = a.getValue();
248        }
249        a = element.getAttribute("blockdname");
250        if (a != null) {
251            l.tBlockDName = a.getValue();
252        }
253
254        a = element.getAttribute("connectaname");
255        if (a != null) {
256            l.connectAName = a.getValue();
257        }
258        a = element.getAttribute("connectbname");
259        if (a != null) {
260            l.connectBName = a.getValue();
261        }
262        a = element.getAttribute("connectcname");
263        if (a != null) {
264            l.connectCName = a.getValue();
265        }
266        a = element.getAttribute("connectdname");
267        if (a != null) {
268            l.connectDName = a.getValue();
269        }
270
271        l.setSignalA1Name(getElement(element, "signala1name"));
272        l.setSignalB1Name(getElement(element, "signalb1name"));
273        l.setSignalC1Name(getElement(element, "signalc1name"));
274        l.setSignalD1Name(getElement(element, "signald1name"));
275
276        l.setSignalA2Name(getElement(element, "signala2name"));
277        l.setSignalB2Name(getElement(element, "signalb2name"));
278        l.setSignalC2Name(getElement(element, "signalc2name"));
279        l.setSignalD2Name(getElement(element, "signald2name"));
280
281        try {
282            l.setDisabled(element.getAttribute("disabled").getBooleanValue());
283        } catch (DataConversionException e1) {
284            log.warn("unable to convert layout turnout disabled attribute");
285        } catch (NullPointerException e) {  // considered normal if the attribute is not present
286        }
287        try {
288            l.setDisableWhenOccupied(element.getAttribute("disableWhenOccupied").getBooleanValue());
289        } catch (DataConversionException e1) {
290            log.warn("unable to convert layout turnout disableWhenOccupied attribute");
291        } catch (NullPointerException e) {  // considered normal if the attribute is not present
292        }
293        try {
294            lv.setHidden(element.getAttribute("hidden").getBooleanValue());
295        } catch (DataConversionException e1) {
296            log.warn("unable to convert layout turnout hidden attribute");
297        } catch (NullPointerException e) {  // considered normal if the attribute is not present
298        }
299
300        l.setShowToolTip(false);
301        a = element.getAttribute("showtooltip");
302        if (a != null) {
303            if ("yes".equals(a.getValue())) {
304                l.setShowToolTip(true);
305            }
306        }
307
308        try {
309            x = element.getAttribute("xa").getFloatValue();
310            y = element.getAttribute("ya").getFloatValue();
311            lv.setCoordsA(new Point2D.Double(x, y));
312        } catch (org.jdom2.DataConversionException e) {
313            log.error("failed to convert LayoutSlip a coords attribute");
314        }
315        try {
316            x = element.getAttribute("xb").getFloatValue();
317            y = element.getAttribute("yb").getFloatValue();
318            lv.setCoordsB(new Point2D.Double(x, y));
319        } catch (org.jdom2.DataConversionException e) {
320            log.error("failed to convert LayoutSlip b coords attribute");
321        }
322
323        l.setSignalAMast(getElement(element, "signalAMast"));
324        l.setSignalBMast(getElement(element, "signalBMast"));
325        l.setSignalCMast(getElement(element, "signalCMast"));
326        l.setSignalDMast(getElement(element, "signalDMast"));
327
328        l.setSensorA(getElement(element, "sensorA"));
329        l.setSensorB(getElement(element, "sensorB"));
330        l.setSensorC(getElement(element, "sensorC"));
331        l.setSensorD(getElement(element, "sensorD"));
332
333        if (element.getChild("states") != null) {
334            Element state = element.getChild("states");
335            if (state.getChild("A-C") != null) {
336                Element ac = state.getChild("A-C");
337                l.setTurnoutStates(LayoutSlip.STATE_AC,
338                        ac.getChild("turnout").getText(),
339                        ac.getChild("turnoutB").getText());
340            }
341            if (state.getChild("A-D") != null) {
342                Element ad = state.getChild("A-D");
343                l.setTurnoutStates(LayoutSlip.STATE_AD,
344                        ad.getChild("turnout").getText(),
345                        ad.getChild("turnoutB").getText());
346            }
347            if (state.getChild("B-D") != null) {
348                Element bd = state.getChild("B-D");
349                l.setTurnoutStates(LayoutSlip.STATE_BD,
350                        bd.getChild("turnout").getText(),
351                        bd.getChild("turnoutB").getText());
352            }
353            if (state.getChild("B-C") != null) {
354                Element bc = state.getChild("B-C");
355                l.setTurnoutStates(LayoutSlip.STATE_BC,
356                        bc.getChild("turnout").getText(),
357                        bc.getChild("turnoutB").getText());
358            }
359        }
360
361        loadLogixNG_Data(lv, element);
362    }
363
364    String getElement(Element el, String child) {
365        if (el.getChild(child) != null) {
366            return el.getChild(child).getText();
367        }
368        return "";
369    }
370
371    private final static org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(LayoutSlipViewXml.class);
372}