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}