001package jmri.jmrit.display.layoutEditor.configurexml; 002 003import java.awt.Color; 004import java.util.List; 005import jmri.ConfigureManager; 006import jmri.InstanceManager; 007import jmri.Sensor; 008import jmri.jmrit.display.layoutEditor.LayoutBlock; 009import jmri.jmrit.display.layoutEditor.LayoutBlockManager; 010import jmri.util.ColorUtil; 011import org.jdom2.Attribute; 012import org.jdom2.DataConversionException; 013import org.jdom2.Element; 014 015/** 016 * Provides the functionality for configuring a LayoutBlockManager 017 * 018 * @author Dave Duchamp Copyright (c) 2007 019 * @author George Warner Copyright (c) 2017-2019 020 */ 021public class LayoutBlockManagerXml extends jmri.managers.configurexml.AbstractNamedBeanManagerConfigXML { 022 023 public LayoutBlockManagerXml() { 024 } 025 026 /** 027 * Implementation for storing the contents of a LayoutBlockManager 028 * 029 * @param o Object to store, of type LayoutBlockManager 030 * @return Element containing the complete info 031 */ 032 @Override 033 public Element store(Object o) { 034 Element layoutblocks = new Element("layoutblocks"); 035 setStoreElementClass(layoutblocks); 036 LayoutBlockManager tm = (LayoutBlockManager) o; 037 if (tm.isAdvancedRoutingEnabled()) { 038 layoutblocks.setAttribute("blockrouting", "yes"); 039 } 040 jmri.NamedBeanHandle<Sensor> tmStable = tm.getNamedStabilisedSensor(); 041 if (tmStable != null) { 042 layoutblocks.setAttribute("routingStablisedSensor", tmStable.getName()); 043 } 044 045 // don't return an element if there is nothing to include 046 if (tm.getNamedBeanSet().isEmpty()) { 047 return null; 048 } 049 050 for (LayoutBlock b : tm.getNamedBeanSet()) { 051 052 // save only those LayoutBlocks that are in use--skip abandoned ones 053 if (b!=null && b.getUseCount() > 0) { 054 Element elem = new Element("layoutblock").setAttribute("systemName", b.getSystemName()); 055 elem.addContent(new Element("systemName").addContent(b.getSystemName())); 056 storeCommon(b, elem); 057 if (!b.getOccupancySensorName().isEmpty()) { 058 elem.setAttribute("occupancysensor", b.getOccupancySensorName()); 059 } 060 elem.setAttribute("occupiedsense", "" + b.getOccupiedSense()); 061 elem.setAttribute("trackcolor", ColorUtil.colorToColorName(b.getBlockTrackColor())); 062 elem.setAttribute("occupiedcolor", ColorUtil.colorToColorName(b.getBlockOccupiedColor())); 063 elem.setAttribute("extracolor", ColorUtil.colorToColorName(b.getBlockExtraColor())); 064 if (!b.getMemoryName().isEmpty()) { 065 elem.setAttribute("memory", b.getMemoryName()); 066 } 067 if (!b.useDefaultMetric()) { 068 elem.addContent(new Element("metric").addContent("" + b.getBlockMetric())); 069 } 070 layoutblocks.addContent(elem); 071 072 } 073 } 074 return (layoutblocks); 075 } 076 077 /** 078 * Subclass provides implementation to create the correct top element, 079 * including the type information. Default implementation is to use the 080 * local class here. 081 * 082 * @param layoutblocks The top-level element being created 083 */ 084 public void setStoreElementClass(Element layoutblocks) { 085 layoutblocks.setAttribute("class", getClass().getName()); 086 } 087 088 @Override 089 public void load(Element element, Object o) { 090 log.error("Invalid method called"); 091 } 092 093 @Override 094 public boolean load(Element shared, Element perNode) { 095 // create the master object 096 replaceLayoutBlockManager(); 097 // load individual layoutblocks 098 loadLayoutBlocks(shared); 099 return true; 100 } 101 102 /** 103 * Utility method to load the individual LayoutBlock objects. If there's no 104 * additional info needed for a specific layoutblock type, invoke this with 105 * the parent of the set of layoutblock elements. 106 * 107 * @param layoutblocks Element containing the layoutblock elements to load. 108 */ 109 public void loadLayoutBlocks(Element layoutblocks) { 110 LayoutBlockManager tm = InstanceManager.getDefault(LayoutBlockManager.class); 111 try { 112 tm.enableAdvancedRouting(layoutblocks.getAttribute("blockrouting").getBooleanValue()); 113 } catch (DataConversionException e1) { 114 log.warn("unable to convert layout block manager blockrouting attribute"); 115 } catch (NullPointerException e) { // considered normal if the attribute is not present 116 } 117 if (layoutblocks.getAttribute("routingStablisedSensor") != null) { 118 try { 119 tm.setStabilisedSensor(layoutblocks.getAttribute("routingStablisedSensor").getValue()); 120 } catch (jmri.JmriException e) { 121 } 122 } 123 124 List<Element> layoutblockList = layoutblocks.getChildren("layoutblock"); 125 if (log.isDebugEnabled()) { 126 log.debug("Found {} layoutblocks", layoutblockList.size()); 127 } 128 129 for (Element e : layoutblockList) { 130 String sysName = getSystemName(e); 131 if (sysName == null) { 132 log.warn("unexpected null in systemName {} {}", e, e.getAttributes()); 133 break; 134 } 135 136 String userName = getUserName(e); 137 LayoutBlock b = tm.createNewLayoutBlock(sysName, userName); 138 139 // load common parts 140 loadCommon(b, e); 141 142 if (b != null) { 143 // set attributes 144 Color color; 145 try { 146 color = ColorUtil.stringToColor(e.getAttribute("trackcolor").getValue()); 147 b.setBlockTrackColor(color); 148 } catch (IllegalArgumentException ex) { 149 b.setBlockTrackColor(Color.darkGray); 150 log.error("Invalid trackcolor '{}'; using 'darkGray'", e.getAttribute("trackcolor").getValue()); 151 } 152 try { 153 color = ColorUtil.stringToColor(e.getAttribute("occupiedcolor").getValue()); 154 b.setBlockOccupiedColor(color); 155 } catch (IllegalArgumentException ex) { 156 b.setBlockOccupiedColor(Color.red); 157 log.error("Invalid occupiedcolor '{}'; using 'red'", e.getAttribute("occupiedcolor").getValue()); 158 } 159 Attribute a = e.getAttribute("extracolor"); 160 if (a != null) { 161 try { 162 b.setBlockExtraColor(ColorUtil.stringToColor(a.getValue())); 163 } catch (IllegalArgumentException ex) { 164 b.setBlockExtraColor(Color.white); 165 log.error("Invalid extracolor '{}'; using 'white'", e.getAttribute("extracolor").getValue()); 166 } 167 } 168 a = e.getAttribute("occupancysensor"); 169 if (a != null) { 170 b.setOccupancySensorName(a.getValue()); 171 } 172 a = e.getAttribute("memory"); 173 if (a != null) { 174 b.setMemoryName(a.getValue()); 175 } 176 a = e.getAttribute("occupancysensorsense"); 177 int sense = Sensor.ACTIVE; 178 try { 179 sense = e.getAttribute("occupiedsense").getIntValue(); 180 } catch (org.jdom2.DataConversionException ex) { 181 log.error("failed to convert occupiedsense attribute"); 182 } 183 b.setOccupiedSense(sense); 184 if (e.getChild("metric") != null) { 185 String stMetric = e.getChild("metric").getText(); 186 try { 187 b.setBlockMetric(Integer.parseInt(stMetric)); 188 } catch (java.lang.NumberFormatException ex) { 189 log.error("failed to convert metric attribute for block {}", b.getDisplayName()); 190 } 191 } 192 } 193 } 194 } 195 196 /** 197 * Replace the current LayoutBlockManager, if there is one, with one newly 198 * created during a load operation. This is skipped if they are of the same 199 * absolute type. 200 */ 201 protected void replaceLayoutBlockManager() { 202 if (InstanceManager.getDefault(LayoutBlockManager.class).getClass().getName() 203 .equals(LayoutBlockManager.class.getName())) { 204 return; 205 } 206 // if old manager exists, remove it from configuration process 207 if (InstanceManager.getNullableDefault(LayoutBlockManager.class) != null) { 208 InstanceManager.getDefault(jmri.ConfigureManager.class).deregister( 209 InstanceManager.getDefault(LayoutBlockManager.class)); 210 } 211 212 // register new one with InstanceManager 213 LayoutBlockManager pManager = InstanceManager.getDefault(LayoutBlockManager.class); 214 // register new one for configuration 215 ConfigureManager cm = InstanceManager.getNullableDefault(jmri.ConfigureManager.class); 216 if (cm != null) { 217 cm.registerConfig(pManager, jmri.Manager.LAYOUTBLOCKS); 218 } 219 } 220 221 private final static org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(LayoutBlockManagerXml.class); 222}