001package jmri.implementation; 002 003import java.util.*; 004import javax.annotation.*; 005 006import jmri.NamedBean; 007import jmri.NamedBeanHandle; 008import jmri.NamedBeanUsageReport; 009 010import jmri.InstanceManager; 011import jmri.SignalAppearanceMap; 012import jmri.SignalMast; 013import jmri.SignalSystem; 014 015import org.slf4j.Logger; 016import org.slf4j.LoggerFactory; 017 018/** 019 * Abstract class providing the basic logic of the SignalMast interface. 020 * 021 * @author Bob Jacobsen Copyright (C) 2009 022 */ 023public abstract class AbstractSignalMast extends AbstractNamedBean 024 implements SignalMast, java.beans.VetoableChangeListener { 025 026 private final static Logger log = LoggerFactory.getLogger(AbstractSignalMast.class); 027 028 public AbstractSignalMast(String systemName, String userName) { 029 super(systemName, userName); 030 } 031 032 public AbstractSignalMast(String systemName) { 033 super(systemName); 034 } 035 036 @Override 037 public void setAspect(@Nonnull String aspect) { 038 String oldAspect = this.aspect; 039 this.aspect = aspect; 040 this.speed = (String) getSignalSystem().getProperty(aspect, "speed"); 041 firePropertyChange("Aspect", oldAspect, aspect); 042 } 043 044 @Override 045 public String getAspect() { 046 return aspect; 047 } 048 protected String aspect = null; 049 050 public String getSpeed() { 051 return speed; 052 } 053 protected String speed = null; 054 055 /** 056 * The state is the index of the current aspect in the list of possible 057 * aspects. 058 */ 059 @Override 060 public int getState() { 061 return -1; 062 } 063 064 @Override 065 public void setState(int i) { 066 } 067 068 /** 069 * By default, signals are lit. 070 */ 071 private boolean mLit = true; 072 073 /** 074 * Default behavior for "lit" property is to track value and return it. 075 */ 076 @Override 077 public boolean getLit() { 078 return mLit; 079 } 080 081 /** 082 * By default, signals are not held. 083 */ 084 private boolean mHeld = false; 085 086 /** 087 * "Held" property is just tracked and notified. 088 */ 089 @Override 090 public boolean getHeld() { 091 return mHeld; 092 } 093 094 /** 095 * Set the lit property. 096 * <p> 097 * This acts on all the SignalHeads included in this SignalMast 098 * 099 * @param newLit the new value of lit 100 */ 101 @Override 102 public void setLit(boolean newLit) { 103 boolean oldLit = mLit; 104 mLit = newLit; 105 if (oldLit != newLit) { 106 //updateOutput(); 107 // notify listeners, if any 108 firePropertyChange("Lit", oldLit, newLit); 109 } 110 } 111 112 /** 113 * Set the held property of the signal mast. 114 * <p> 115 * Note that this does not directly effect the output on the layout; the 116 * held property is a local variable which effects the aspect only via 117 * higher-level logic. 118 * 119 * @param newHeld the new value of the help property 120 */ 121 @Override 122 public void setHeld(boolean newHeld) { 123 boolean oldHeld = mHeld; 124 mHeld = newHeld; 125 if (oldHeld != newHeld) { 126 // notify listeners, if any 127 firePropertyChange("Held", oldHeld, newHeld); 128 } 129 } 130 131 @Override 132 public boolean isAtStop() { 133 if (speed.equals("0")) return true; // should this also include DANGER? 134 return false; 135 } 136 137 @Override 138 public boolean isShowingRestricting() { 139 String displayedAspect = getAspect(); 140 if ( displayedAspect != null && displayedAspect.equals(getAppearanceMap().getSpecificAppearance(jmri.SignalAppearanceMap.PERMISSIVE))) return true; 141 return false; 142 } 143 144 @Override 145 public boolean isCleared() { 146 String displayedAspect = getAspect(); 147 if ( displayedAspect == null ) { 148 return false; 149 } 150 if (displayedAspect.equals(getAppearanceMap().getSpecificAppearance(jmri.SignalAppearanceMap.PERMISSIVE))) return false; 151 if (displayedAspect.equals(getAppearanceMap().getSpecificAppearance(jmri.SignalAppearanceMap.HELD))) return false; 152 if (displayedAspect.equals(getAppearanceMap().getSpecificAppearance(jmri.SignalAppearanceMap.DANGER))) return false; 153 return true; 154 } 155 156 protected DefaultSignalAppearanceMap map; 157 SignalSystem systemDefn; 158 159 boolean disablePermissiveSignalMastLogic = false; 160 @Override 161 public void setPermissiveSmlDisabled(boolean disabled) { 162 disablePermissiveSignalMastLogic = disabled; 163 firePropertyChange("PermissiveSmlDisabled", null, disabled); 164 } 165 /** 166 * {@inheritDoc } 167 */ 168 @Override 169 public boolean isPermissiveSmlDisabled() { 170 return disablePermissiveSignalMastLogic; 171 } 172 173 protected void configureSignalSystemDefinition(String name) { 174 systemDefn = InstanceManager.getDefault(jmri.SignalSystemManager.class).getSystem(name); 175 if (systemDefn == null) { 176 log.error("Did not find signal definition: {}", name); 177 throw new IllegalArgumentException("Signal definition not found: " + name); 178 } 179 } 180 181 protected void configureAspectTable(String signalSystemName, String aspectMapName) { 182 map = DefaultSignalAppearanceMap.getMap(signalSystemName, aspectMapName); 183 } 184 185 @Override 186 public SignalSystem getSignalSystem() { 187 return systemDefn; 188 } 189 190 @Override 191 public SignalAppearanceMap getAppearanceMap() { 192 return map; 193 } 194 195 protected ArrayList<String> disabledAspects = new ArrayList<>(1); 196 197 @Override 198 @Nonnull 199 public Vector<String> getValidAspects() { 200 java.util.Enumeration<String> e = map.getAspects(); 201 // copy List to Vector 202 Vector<String> v = new Vector<>(); 203 while (e.hasMoreElements()) { 204 String a = e.nextElement(); 205 if (!disabledAspects.contains(a)) { 206 v.add(a); 207 } 208 } 209 return v; 210 } 211 212 /** 213 * {@inheritDoc } 214 */ 215 @Override 216 public String getMastType() { return mastType; } 217 @Override 218 public void setMastType(@Nonnull String type) { 219 Objects.requireNonNull(type, "MastType cannot be null"); 220 mastType = type; 221 } 222 String mastType; 223 224 /** 225 * Get a list of all the known aspects for this mast, including those that 226 * have been disabled. 227 * 228 * @return list of known aspects; may be empty 229 */ 230 public Vector<String> getAllKnownAspects() { 231 java.util.Enumeration<String> e = map.getAspects(); 232 Vector<String> v = new Vector<>(); 233 while (e.hasMoreElements()) { 234 v.add(e.nextElement()); 235 } 236 return v; 237 } 238 239 public void setAspectDisabled(String aspect) { 240 if (aspect == null || aspect.equals("")) { 241 return; 242 } 243 if (!map.checkAspect(aspect)) { 244 log.warn("attempting to disable an aspect: {} that is not on the mast {}", aspect, getDisplayName()); 245 return; 246 } 247 if (!disabledAspects.contains(aspect)) { 248 disabledAspects.add(aspect); 249 firePropertyChange("aspectDisabled", null, aspect); 250 } 251 } 252 253 public void setAspectEnabled(String aspect) { 254 if (aspect == null || aspect.equals("")) { 255 return; 256 } 257 if (!map.checkAspect(aspect)) { 258 log.warn("attempting to disable an aspect: {} that is not on the mast {}", aspect, getDisplayName()); 259 return; 260 } 261 if (disabledAspects.contains(aspect)) { 262 disabledAspects.remove(aspect); 263 firePropertyChange("aspectEnabled", null, aspect); 264 } 265 } 266 267 public List<String> getDisabledAspects() { 268 return disabledAspects; 269 } 270 271 @Override 272 public boolean isAspectDisabled(String aspect) { 273 return disabledAspects.contains(aspect); 274 } 275 276 boolean allowUnLit = true; 277 278 @Override 279 public void setAllowUnLit(boolean boo) { 280 allowUnLit = boo; 281 } 282 283 @Override 284 public boolean allowUnLit() { 285 return allowUnLit; 286 } 287 288 @Override 289 public void vetoableChange(java.beans.PropertyChangeEvent evt) throws java.beans.PropertyVetoException { 290 } 291 292 @Override 293 public String getBeanType() { 294 return Bundle.getMessage("BeanNameSignalMast"); 295 } 296 297 @Override 298 public List<NamedBeanUsageReport> getUsageReport(NamedBean bean) { 299 List<NamedBeanUsageReport> report = new ArrayList<>(); 300 if (bean != null) { 301 if (bean instanceof jmri.Turnout) { 302 if (this instanceof jmri.implementation.TurnoutSignalMast) { 303 var m = (jmri.implementation.TurnoutSignalMast) this; 304 var t = (jmri.Turnout) bean; 305 if (m.isTurnoutUsed(t)) { 306 report.add(new NamedBeanUsageReport("SignalMastTurnout")); // NOI18N 307 } 308 } else if (this instanceof jmri.implementation.MatrixSignalMast) { 309 var m = (jmri.implementation.MatrixSignalMast) this; 310 var t = (jmri.Turnout) bean; 311 if (m.isTurnoutUsed(t)) { 312 report.add(new NamedBeanUsageReport("SignalMastTurnout")); // NOI18N 313 } 314 } 315 } else if (bean instanceof jmri.SignalHead) { 316 if (this instanceof jmri.implementation.SignalHeadSignalMast) { 317 var m = (jmri.implementation.SignalHeadSignalMast) this; 318 var h = (jmri.SignalHead) bean; 319 for (NamedBeanHandle<jmri.SignalHead> handle : m.getHeadsUsed()) { 320 if (h.equals(handle.getBean())) { 321 report.add(new NamedBeanUsageReport("SignalMastSignalHead")); // NOI18N 322 } 323 } 324 } 325 } 326 } 327 return report; 328 } 329}