001package jmri.jmrit.display.layoutEditor.configurexml;
002
003import java.awt.geom.Point2D;
004import java.util.List;
005import jmri.Turnout;
006import jmri.jmrit.display.layoutEditor.LayoutEditor;
007import jmri.jmrit.display.layoutEditor.LayoutTraverser;
008import jmri.jmrit.display.layoutEditor.LayoutTraverserView;
009import jmri.jmrit.display.layoutEditor.TrackSegment;
010import org.jdom2.Attribute;
011import org.jdom2.DataConversionException;
012import org.jdom2.Element;
013
014/**
015 * This module handles configuration for display.LayoutTraverser objects for a
016 * LayoutEditor.
017 *
018 * @author David Duchamp Copyright (c) 2007
019 * @author George Warner Copyright (c) 2017-2018
020 * @author Bob Jacobsen  Copyright (c) 2020
021 */
022public class LayoutTraverserViewXml extends LayoutTrackViewXml {
023
024    public LayoutTraverserViewXml() {
025    }
026
027    /**
028     * Default implementation for storing the contents of a LayoutTraverser
029     *
030     * @param o Object to store, of type LayoutTraverser
031     * @return Element containing the complete info
032     */
033    @Override
034    public Element store(Object o) {
035
036        LayoutTraverserView pv = (LayoutTraverserView) o;
037        LayoutTraverser lt = pv.getTraverser();
038
039        Element element = new Element("layouttraverser");
040        boolean turnoutControl = lt.isTurnoutControlled();
041        // include attributes
042        element.setAttribute("ident", lt.getName());
043        if (!lt.getBlockName().isEmpty()) {
044            element.setAttribute("blockname", lt.getBlockName());
045        }
046        element.setAttribute("slotoffset", String.valueOf(lt.getSlotOffset()));
047        element.setAttribute("orientation", String.valueOf(lt.getOrientation()));
048        element.setAttribute("mainline", lt.isMainline() ? "yes" : "no");
049
050        Point2D coords = pv.getCoordsCenter();
051        element.setAttribute("xcen", "" + coords.getX());
052        element.setAttribute("ycen", "" + coords.getY());
053        element.setAttribute("turnoutControlled", "" + (turnoutControl ? "yes" : "no"));
054        element.setAttribute("deckwidth", "" + lt.getDeckWidth());
055        boolean dispatcherManaged = lt.isDispatcherManaged();
056        if (dispatcherManaged) {
057            String exitMastName = lt.getExitSignalMastName();
058            if (exitMastName != null && !exitMastName.isEmpty()) {
059                element.setAttribute("exitmast", exitMastName);
060            }
061            String bufferMastName = lt.getBufferSignalMastName();
062            if (bufferMastName != null && !bufferMastName.isEmpty()) {
063                element.setAttribute("buffermast", bufferMastName);
064            }
065            element.setAttribute("signalIconPlacement", "" + lt.getSignalIconPlacement());
066            element.setAttribute("dispatcherManaged", "yes");
067        }
068        element.setAttribute("class", "jmri.jmrit.display.layoutEditor.configurexml.LayoutTraverserViewXml");
069        // add slot tracks
070        for (int i = 0; i < lt.getNumberSlots(); i++) {
071            Element rElem = new Element("slot");
072            rElem.setAttribute("offset", "" + lt.getSlotOffsetValue(i));
073            TrackSegment t = lt.getSlotConnectOrdered(i);
074            if (t != null) {
075                rElem.setAttribute("connectname", t.getId());
076            }
077            String mastName = lt.getSlotList().get(i).getApproachMastName();
078            if (mastName != null && !mastName.isEmpty()) {
079                rElem.setAttribute("approachmast", mastName);
080            }
081            rElem.setAttribute("index", "" + lt.getSlotIndex(i));
082            if (turnoutControl && lt.getSlotTurnoutName(i) != null) {
083                rElem.setAttribute("turnout", lt.getSlotTurnoutName(i));
084                if (lt.getSlotTurnoutState(i) == Turnout.THROWN) {
085                    rElem.setAttribute("turnoutstate", "thrown");
086                } else {
087                    rElem.setAttribute("turnoutstate", "closed");
088                }
089            }
090            if (lt.isSlotDisabled(i)) {
091                rElem.setAttribute("disabled", "yes");
092            }
093            if (lt.isSlotDisabledWhenOccupied(i)) {
094                rElem.setAttribute("disableWhenOccupied", "yes");
095            }
096            element.addContent(rElem);
097        }
098        storeLogixNG_Data(pv, element);
099        return element;
100    }
101
102    @Override
103    public boolean load(Element shared, Element perNode) {
104        log.error("Invalid method called");
105        return false;
106    }
107
108    /**
109     * Load, starting with the layout traverser element, then all the other data
110     *
111     * @param element Top level Element to unpack.
112     * @param o       LayoutEditor as an Object
113     */
114    @Override
115    public void load(Element element, Object o) {
116        // create the objects
117        LayoutEditor p = (LayoutEditor) o;
118
119        // get center point
120        String name = element.getAttribute("ident").getValue();
121        log.debug("Loading layouttraverser: {} " , name);
122        double x = 0.0;
123        double y = 0.0;
124        double slotOffset = 25.0;
125        int orientation = LayoutTraverser.HORIZONTAL;
126        try {
127            x = element.getAttribute("xcen").getFloatValue();
128            y = element.getAttribute("ycen").getFloatValue();
129            log.debug("  xcen={} ycen={}", x, y);
130            if (element.getAttribute("slotoffset") != null) {
131                slotOffset = element.getAttribute("slotoffset").getDoubleValue();
132                log.debug("  slotOffset={}", slotOffset);
133            }
134            if (element.getAttribute("orientation") != null) {
135                orientation = element.getAttribute("orientation").getIntValue();
136                log.debug("  orientation={}", orientation);
137            }
138        } catch (org.jdom2.DataConversionException e) {
139            log.error("failed to convert layouttraverser attributes", e);
140        }
141        // create the new LayoutTraverser
142        LayoutTraverser lt = new LayoutTraverser(name, p);
143        LayoutTraverserView lv = new LayoutTraverserView(lt, new Point2D.Double(x, y), p);
144
145        p.addLayoutTrack(lv.getTraverser(), lv);
146
147        lv.setCoordsCenter(new Point2D.Double(x, y));
148        lt.setSlotOffset(slotOffset);
149        lt.setOrientation(orientation);
150
151        // get remaining attributes
152        Attribute a = element.getAttribute("mainline");
153        if (a != null) {
154            lt.setMainline("yes".equalsIgnoreCase(a.getValue()));
155            log.debug("  mainline={}", lt.isMainline());
156        }
157        a = element.getAttribute("deckwidth");
158        if (a != null) {
159            try {
160                lt.setDeckWidth(a.getDoubleValue());
161                log.debug("  deckwidth={}", lt.getDeckWidth());
162            } catch (DataConversionException e) {
163                log.warn("Could not parse deckwidth attribute!");
164            }
165        }
166
167        a = element.getAttribute("blockname");
168        if (a != null) {
169            lt.tLayoutBlockName = a.getValue();
170            log.debug("  blockname={}", lt.tLayoutBlockName);
171        }
172
173        a = element.getAttribute("turnoutControlled");
174        if (a != null) {
175            lt.setTurnoutControlled("yes".equalsIgnoreCase(a.getValue()));
176            log.debug("  turnoutControlled={}", lt.isTurnoutControlled());
177        }
178
179        a = element.getAttribute("dispatcherManaged");
180        if (a != null) {
181            lt.setDispatcherManaged("yes".equalsIgnoreCase(a.getValue()));
182            log.debug("  dispatcherManaged={}", lt.isDispatcherManaged());
183            if (lt.isDispatcherManaged()) {
184                a = element.getAttribute("exitmast");
185                if (a != null) {
186                    lt.tExitSignalMastName = a.getValue();
187                    log.debug("  exitmast={}", lt.tExitSignalMastName);
188                }
189                a = element.getAttribute("buffermast");
190                if (a != null) {
191                    lt.tBufferSignalMastName = a.getValue();
192                    log.debug("  buffermast={}", lt.tBufferSignalMastName);
193                }
194                a = element.getAttribute("signalIconPlacement");
195                if (a != null) {
196                    try {
197                        lt.setSignalIconPlacement(a.getIntValue());
198                        log.debug("  signalIconPlacement={}", lt.getSignalIconPlacement());
199                    } catch (DataConversionException e) {
200                        log.error("failed to convert signalIconPlacement attribute");
201                    }
202                }
203            }
204        }
205
206        // load slot tracks
207        List<Element> slotTrackList = element.getChildren("slot");
208        log.debug("  found {} slot elements" , slotTrackList.size());
209        if (slotTrackList.size() > 0) {
210            for (Element value : slotTrackList) {
211                double offset = 0.0;
212                int index = 0;
213                try {
214                    offset = (value.getAttribute("offset")).getFloatValue();
215                    index = (value.getAttribute("index")).getIntValue();
216                    log.debug("    loading slot index = {} with offset = {}" , index , offset);
217                } catch (DataConversionException e) {
218                    log.error("failed to convert slot track offset or index attributes");
219                }
220
221                a = value.getAttribute("connectname");
222                String connectName = (a != null) ? a.getValue() : "";
223                if (a != null) {
224                    log.debug("connectname={}", connectName);
225                }
226
227                lt.addSlotTrack(offset, index, connectName);
228
229                a = value.getAttribute("approachmast");
230                if (a != null) {
231                    lt.getSlotList().get(lt.getNumberSlots() - 1).approachMastName = a.getValue();
232                    log.debug("      approachmast={}", a.getValue());
233                }
234
235                a = value.getAttribute("turnout");
236                if (lt.isTurnoutControlled() && a != null) {
237                    String turnoutName = a.getValue();
238                    log.debug("      turnout={}", turnoutName);
239                    Attribute stateAttr = value.getAttribute("turnoutstate");
240                    int turnoutState = Turnout.CLOSED;
241                    if (stateAttr != null && "thrown".equalsIgnoreCase(stateAttr.getValue())) {
242                        turnoutState = Turnout.THROWN;
243                    }
244                    lt.setSlotTurnout(index, turnoutName, turnoutState);
245                    if (stateAttr != null) {
246                        log.debug("      turnoutstate={}", stateAttr.getValue());
247                    }
248                }
249
250                a = value.getAttribute("disabled");
251                lt.setSlotDisabled(index, (a != null) && "yes".equalsIgnoreCase(a.getValue()));
252                if (a != null) log.debug("      disabled={}", a.getValue());
253
254                a = value.getAttribute("disableWhenOccupied");
255                lt.setSlotDisabledWhenOccupied(index, (a != null) && "yes".equalsIgnoreCase(a.getValue()));
256                if (a != null) log.debug("      disableWhenOccupied={}", a.getValue());
257            }
258        }
259
260        loadLogixNG_Data(lv, element);
261        log.debug("  finished loading traverser {}" , name);
262    }
263
264    private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(LayoutTraverserViewXml.class);
265}