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}