001package jmri.jmrit.ctc; 002 003import java.util.ArrayList; 004import java.util.HashMap; 005import java.util.List; 006import jmri.Block; 007import jmri.ConfigureManager; 008import jmri.InstanceManager; 009import jmri.InstanceManagerAutoDefault; 010import jmri.Manager; 011import jmri.NamedBean; 012import jmri.NamedBeanHandle; 013import jmri.NamedBeanHandleManager; 014import jmri.NamedBeanUsageReport; 015import jmri.jmrit.ctc.ctcserialdata.*; 016import jmri.jmrit.ctc.editor.code.*; 017 018/** 019 * Start the CtcManager and register with the instance and configuration managers. 020 * <ul> 021 * <li>Create/provide the ProgramProperties instance</li> 022 * <li>Create/provide the CTCSerialData instance</li> 023 * <li>Provide the OtherData instance</li> 024 * <li>Provide hash maps of beans used by CTC</li> 025 * <li>Veto deletes for beans used by CTC</li> 026 * </ul> 027 * 028 * @author Dave Sand Copyright (C) 2020 029 */ 030public class CtcManager implements InstanceManagerAutoDefault, java.beans.VetoableChangeListener { 031 032 ProgramProperties programProperties = null; 033 CTCSerialData ctcSerialData = null; 034 HashMap<String, NBHSensor> nbhSensors = new HashMap<>(); 035 HashMap<String, NBHSignal> nbhSignals = new HashMap<>(); 036 HashMap<String, NBHTurnout> nbhTurnouts = new HashMap<>(); 037 HashMap<String, NamedBeanHandle<Block>> blocks = new HashMap<>(); 038 039 // Search results 040 NBHSensor foundSensor; 041 NBHSignal foundSignal; 042 NBHTurnout foundTurnout; 043 Block foundBlock; 044 045 List<NamedBeanUsageReport> usageReport; 046 047 public CtcManager() { 048 InstanceManager.setDefault(CtcManager.class, this); 049 InstanceManager.getOptionalDefault(ConfigureManager.class).ifPresent(cm -> { 050 cm.registerConfig(this, getXMLOrder()); 051 }); 052 InstanceManager.getDefault(jmri.SensorManager.class).addVetoableChangeListener(this); 053 InstanceManager.getDefault(jmri.SignalHeadManager.class).addVetoableChangeListener(this); 054 InstanceManager.getDefault(jmri.SignalMastManager.class).addVetoableChangeListener(this); 055 InstanceManager.getDefault(jmri.TurnoutManager.class).addVetoableChangeListener(this); 056 InstanceManager.getDefault(jmri.BlockManager.class).addVetoableChangeListener(this); 057 log.debug("CtcManager started"); // NOI18N 058 } 059 060 public ProgramProperties getProgramProperties() { 061 if (programProperties == null) { 062 programProperties = new ProgramProperties(); 063 } 064 return programProperties; 065 } 066 067 public ProgramProperties newProgramProperties() { 068 programProperties = new ProgramProperties(); 069 return programProperties; 070 } 071 072 public CTCSerialData getCTCSerialData() { 073 if (ctcSerialData == null) { 074 ctcSerialData = new CTCSerialData(); 075 } 076 return ctcSerialData; 077 } 078 079 public CTCSerialData newCTCSerialData() { 080 ctcSerialData = new CTCSerialData(); 081 082 nbhSensors.clear(); 083 nbhSignals.clear(); 084 nbhTurnouts.clear(); 085 blocks.clear(); 086 087 return ctcSerialData; 088 } 089 090 public OtherData getOtherData() { 091 if (ctcSerialData == null) { 092 ctcSerialData = getCTCSerialData(); 093 } 094 return ctcSerialData.getOtherData(); 095 } 096 097 public NBHSensor getNBHSensor(String name) { 098 // check for new names 099 return nbhSensors.get(name); 100 } 101 102 public void putNBHSensor(String name, NBHSensor nbh) { 103 NBHSensor oldSensor = nbhSensors.put(name, nbh); 104 log.debug("sensor put = {} -- {}", name, nbh); // NOI18N 105 if (oldSensor != null) { 106 log.debug("---- duplicate sensor: {} -- {}", name, nbh); // NOI18N 107 } 108 } 109 110 public NBHSignal getNBHSignal(String name) { 111 // check for new names 112 return nbhSignals.get(name); 113 } 114 115 public void putNBHSignal(String name, NBHSignal nbh) { 116 NBHSignal oldSignal = nbhSignals.put(name, nbh); 117 log.debug("signal put = {} -- {}", name, nbh); // NOI18N 118 if (oldSignal != null) { 119 log.debug("---- duplicate signal: {} -- {}", name, nbh); // NOI18N 120 } 121 } 122 123 public NBHTurnout getNBHTurnout(String name) { 124 // check for new names 125 return nbhTurnouts.get(name); 126 } 127 128 public void putNBHTurnout(String name, NBHTurnout nbh) { 129 NBHTurnout oldTurnout = nbhTurnouts.put(name, nbh); 130 log.debug("turnout put = {} -- {}", name, nbh); // NOI18N 131 if (oldTurnout != null) { 132 log.debug("---- duplicate turnout: {} -- {}", name, nbh); // NOI18N 133 } 134 } 135 136 public NamedBeanHandle<Block> getBlock(String name) { 137 // check for new names 138 return blocks.get(name); 139 } 140 141 public void putBlock(String name, NamedBeanHandle<Block> block) { 142 NamedBeanHandle<Block> oldBlock = blocks.put(name, block); 143 log.debug("block put = {} -- {}", name, block); // NOI18N 144 if (oldBlock != null) { 145 log.debug("---- duplicate block: {} -- {}", name, block); // NOI18N 146 } 147 } 148 149 public int getXMLOrder() { 150 return Manager.CTCDATA; 151 } 152 153 public void vetoableChange(java.beans.PropertyChangeEvent evt) throws java.beans.PropertyVetoException { 154 jmri.NamedBean nb = (jmri.NamedBean) evt.getOldValue(); 155 if ("CanDelete".equals(evt.getPropertyName())) { // NOI18N 156 if (findNBHforBean(nb)) { 157 java.beans.PropertyChangeEvent e = new java.beans.PropertyChangeEvent(this, "DoNotDelete", null, null); // NOI18N 158 throw new java.beans.PropertyVetoException(getVetoDetails(nb), e); 159 } 160 } 161 } 162 163 String getVetoDetails(NamedBean nb) { 164 StringBuilder sb = new StringBuilder(); 165 sb.append(Bundle.getMessage("CtcManagerDeleteVetoed", nb.getBeanType())); // NOI18N 166 for (NamedBeanUsageReport report : getUsageReport(nb)) { 167 sb.append(Bundle.getMessage("VetoDetailLine", report.usageData)); // NOI18N 168 } 169 return sb.toString(); 170 } 171 172 boolean findNBHforBean(NamedBean nb) { 173 if (nb == null) return false; 174 boolean found = false; 175 foundSensor = null; 176 foundSignal = null; 177 foundTurnout = null; 178 foundBlock = null; 179 180 if (nb instanceof jmri.Sensor) { 181 for (NBHSensor sensor : nbhSensors.values()) { 182 if (nb.equals(sensor.getBean())) { 183 foundSensor = sensor; 184 found = true; 185 break; 186 } 187 } 188 } 189 190 if (nb instanceof jmri.SignalHead || nb instanceof jmri.SignalMast) { 191 for (NBHSignal signal : nbhSignals.values()) { 192 if (nb.equals(signal.getBean())) { 193 foundSignal = signal; 194 found = true; 195 break; 196 } 197 } 198 } 199 200 if (nb instanceof jmri.Turnout) { 201 for (NBHTurnout turnout : nbhTurnouts.values()) { 202 if (nb.equals(turnout.getBean())) { 203 foundTurnout = turnout; 204 found = true; 205 break; 206 } 207 } 208 } 209 210 if (nb instanceof Block) { 211 for (NamedBeanHandle<Block> block : blocks.values()) { 212 if (nb.equals(block.getBean())) { 213 foundBlock = block.getBean(); 214 found = true; 215 break; 216 } 217 } 218 } 219 return found; 220 } 221 222 public List<NamedBeanUsageReport> getUsageReport(NamedBean bean) { 223 usageReport = new ArrayList<>(); 224 if (findNBHforBean(bean)) { 225 // Other data 226 if (getOtherData()._mFleetingToggleInternalSensor.equals(foundSensor) || 227 getOtherData()._mCTCDebugSystemReloadInternalSensor.equals(foundSensor) || 228 getOtherData()._mCTCDebug_TrafficLockingRuleTriggeredDisplayInternalSensor.equals(foundSensor)) { 229 usageReport.add(new NamedBeanUsageReport("CtcWhereUsedOther", Bundle.getMessage("WhereUsedOther"))); // NOI18N 230 } 231 232 // O.S. Sections 233 getCTCSerialData().getCodeButtonHandlerDataArrayList().forEach(cbhd -> { 234 getCodeButtonHandleDataUsage(cbhd); 235 }); 236 } 237 return usageReport; 238 } 239 240 void getCodeButtonHandleDataUsage(CodeButtonHandlerData cbhd) { 241 String osName = cbhd.myShortStringNoComma(); 242 243 // CB Sensors 244 if (cbhd._mCodeButtonInternalSensor.equals(foundSensor) || 245 cbhd._mOSSectionOccupiedExternalSensor.equals(foundSensor) || 246 cbhd._mOSSectionOccupiedExternalSensor2.equals(foundSensor)) { 247 usageReport.add(new NamedBeanUsageReport("CtcWhereUsedCBHD", Bundle.getMessage("WhereUsedSensor", osName, "CB"))); // NOI18N 248 } 249 250 // SIDI Sensors 251 if (cbhd._mSIDI_LeftInternalSensor.equals(foundSensor) || 252 cbhd._mSIDI_NormalInternalSensor.equals(foundSensor) || 253 cbhd._mSIDI_RightInternalSensor.equals(foundSensor)) { 254 usageReport.add(new NamedBeanUsageReport("CtcWhereUsedCBHD", Bundle.getMessage("WhereUsedSensor", osName, "SIDI"))); // NOI18N 255 } 256 257 // SIDI Signals 258 cbhd._mSIDI_LeftRightTrafficSignals.forEach(signal -> { 259 if (signal.equals(foundSignal)) { 260 usageReport.add(new NamedBeanUsageReport("CtcWhereUsedCBHD", Bundle.getMessage("WhereUsedSignal", osName, "SIDI"))); // NOI18N 261 } 262 }); 263 cbhd._mSIDI_RightLeftTrafficSignals.forEach(signal -> { 264 if (signal.equals(foundSignal)) { 265 usageReport.add(new NamedBeanUsageReport("CtcWhereUsedCBHD", Bundle.getMessage("WhereUsedSignal", osName, "SIDI"))); // NOI18N 266 } 267 }); 268 269 // SIDL Sensors 270 if (cbhd._mSIDL_LeftInternalSensor.equals(foundSensor) || 271 cbhd._mSIDL_NormalInternalSensor.equals(foundSensor) || 272 cbhd._mSIDL_RightInternalSensor.equals(foundSensor)) { 273 usageReport.add(new NamedBeanUsageReport("CtcWhereUsedCBHD", Bundle.getMessage("WhereUsedSensor", osName, "SIDL"))); // NOI18N 274 } 275 276 // SWDI Sensors 277 if (cbhd._mSWDI_NormalInternalSensor.equals(foundSensor) || 278 cbhd._mSWDI_ReversedInternalSensor.equals(foundSensor)) { 279 usageReport.add(new NamedBeanUsageReport("CtcWhereUsedCBHD", Bundle.getMessage("WhereUsedSensor", osName, "SWDI"))); // NOI18N 280 } 281 282 // SWDI Turnout 283 if (cbhd._mSWDI_ExternalTurnout.equals(foundTurnout)) { 284 usageReport.add(new NamedBeanUsageReport("CtcWhereUsedCBHD", Bundle.getMessage("WhereUsedTurnout", osName, "SWDI"))); // NOI18N 285 } 286 287 // SWDL Sensor 288 if (cbhd._mSWDL_InternalSensor.equals(foundSensor)) { 289 usageReport.add(new NamedBeanUsageReport("CtcWhereUsedCBHD", Bundle.getMessage("WhereUsedSensor", osName, "SWDL"))); // NOI18N 290 } 291 292 callOnDataUsage(cbhd, osName); 293 traffficLockingDataUsage(cbhd, osName); 294 295 // TUL Sensors 296 if (cbhd._mTUL_DispatcherInternalSensorLockToggle.equals(foundSensor) || 297 cbhd._mTUL_DispatcherInternalSensorUnlockedIndicator.equals(foundSensor)) { 298 usageReport.add(new NamedBeanUsageReport("CtcWhereUsedCBHD", Bundle.getMessage("WhereUsedSensor", osName, "TUL"))); // NOI18N 299 } 300 301 // TUL Turnouts 302 if (cbhd._mTUL_ExternalTurnout.equals(foundTurnout) || 303 cbhd._mTUL_AdditionalExternalTurnout1.equals(foundTurnout) || 304 cbhd._mTUL_AdditionalExternalTurnout2.equals(foundTurnout) || 305 cbhd._mTUL_AdditionalExternalTurnout3.equals(foundTurnout)) { 306 usageReport.add(new NamedBeanUsageReport("CtcWhereUsedCBHD", Bundle.getMessage("WhereUsedTurnout", osName, "TUL"))); // NOI18N 307 } 308 309 // IL Signals 310 cbhd._mIL_Signals.forEach(signal -> { 311 if (signal.equals(foundSignal)) { 312 usageReport.add(new NamedBeanUsageReport("CtcWhereUsedCBHD", Bundle.getMessage("WhereUsedSignal", osName, "IL"))); // NOI18N 313 } 314 }); 315 } 316 317 void callOnDataUsage(CodeButtonHandlerData cbhd, String osName) { 318 // CO Sensor 319 if (cbhd._mCO_CallOnToggleInternalSensor.equals(foundSensor)) { 320 usageReport.add(new NamedBeanUsageReport("CtcWhereUsedCBHD", Bundle.getMessage("WhereUsedSensor", osName, "CO"))); // NOI18N 321 } 322 cbhd._mCO_GroupingsList.forEach(row -> { 323 // Sensor 324 if (row._mCalledOnExternalSensor.equals(foundSensor)) { 325 usageReport.add(new NamedBeanUsageReport("CtcWhereUsedCBHD", Bundle.getMessage("WhereUsedSensor", osName, "CO"))); // NOI18N 326 } 327 328 // Signal 329 if (row._mExternalSignal.equals(foundSignal)) { 330 usageReport.add(new NamedBeanUsageReport("CtcWhereUsedCBHD", Bundle.getMessage("WhereUsedSignal", osName, "CO"))); // NOI18N 331 } 332 333 // Block 334 if (row._mExternalBlock != null && row._mExternalBlock.getBean().equals(foundBlock)) { 335 usageReport.add(new NamedBeanUsageReport("CtcWhereUsedCBHD", Bundle.getMessage("WhereUsedBlock", osName, "CO"))); // NOI18N 336 } 337 338 // Switch indicator sensors 339 row._mSwitchIndicators.forEach(sw -> { 340 if (sw.equals(foundSensor)) { 341 usageReport.add(new NamedBeanUsageReport("CtcWhereUsedCBHD", Bundle.getMessage("WhereUsedSensor", osName, "CO"))); // NOI18N 342 } 343 }); 344 }); 345 } 346 347 void traffficLockingDataUsage(CodeButtonHandlerData cbhd, String osName) { 348 cbhd._mTRL_LeftTrafficLockingRules.forEach(rule -> { 349 traffficLockingRuleDataUsage(rule, osName); 350 }); 351 352 cbhd._mTRL_RightTrafficLockingRules.forEach(rule -> { 353 traffficLockingRuleDataUsage(rule, osName); 354 }); 355 } 356 357 void traffficLockingRuleDataUsage(TrafficLockingData rule, String osName) { 358 // Signal -- _mDestinationSignalOrComment 359 if (foundSignal != null) { 360 if (rule._mDestinationSignalOrComment.equals(foundSignal.getHandleName())) { 361 usageReport.add(new NamedBeanUsageReport("CtcWhereUsedCBHD", Bundle.getMessage("WhereUsedSignal", osName, "TRL"))); // NOI18N 362 } 363 } 364 365 // Occupancy sensors 366 for (NBHSensor sensor : rule._mOccupancyExternalSensors) { 367 if (sensor.equals(foundSensor)) { 368 usageReport.add(new NamedBeanUsageReport("CtcWhereUsedCBHD", Bundle.getMessage("WhereUsedSensor", osName, "TRL"))); // NOI18N 369 break; 370 } 371 } 372 373 // Optional sensors 374 for (NBHSensor sensor : rule._mOptionalExternalSensors) { 375 if (sensor.equals(foundSensor)) { 376 usageReport.add(new NamedBeanUsageReport("CtcWhereUsedCBHD", Bundle.getMessage("WhereUsedSensor", osName, "TRL"))); // NOI18N 377 break; 378 } 379 } 380 } 381 382 private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(CtcManager.class); 383}