001package jmri.jmrit.entryexit; 002 003import java.beans.PropertyChangeEvent; 004import java.beans.PropertyChangeListener; 005import java.beans.PropertyChangeSupport; 006import java.util.ArrayList; 007import java.util.HashMap; 008import java.util.List; 009import javax.swing.JMenuItem; 010import jmri.NamedBean; 011import jmri.SignalMast; 012import jmri.jmrit.display.layoutEditor.LayoutBlock; 013import jmri.jmrit.display.layoutEditor.LayoutEditor; 014 015public class Source implements PropertyChangeListener { 016 017 JMenuItem clear = null; 018 JMenuItem cancel = null; 019 JMenuItem editCancel = null; 020 JMenuItem editClear = null; 021 JMenuItem editOneClick = null; 022 JMenuItem oneClick = null; 023 024 NamedBean sourceObject = null; 025 NamedBean sourceSignal = null; 026 //String ref = "Empty"; 027 transient PointDetails pd = null; 028 029 EntryExitPairs manager = jmri.InstanceManager.getDefault(jmri.jmrit.entryexit.EntryExitPairs.class); 030 031 //Using Object here rather than sourceSensor, working on the basis that it might 032 //one day be possible to have a signal icon selectable on a panel and 033 //generate a propertychange, so hence do not want to tie it down at this stage. 034 transient HashMap<PointDetails, DestinationPoints> pointToDest = new HashMap<PointDetails, DestinationPoints>(); 035 036 public boolean isEnabled(Object dest, LayoutEditor panel) { 037 PointDetails lookingFor = manager.getPointDetails(dest, panel); 038 if (pointToDest.containsKey(lookingFor)) { 039 return pointToDest.get(lookingFor).isEnabled(); 040 } 041 return true; 042 } 043 044 public void setEnabled(Object dest, LayoutEditor panel, boolean boo) { 045 PointDetails lookingFor = manager.getPointDetails(dest, panel); 046 if (pointToDest.containsKey(lookingFor)) { 047 pointToDest.get(lookingFor).setEnabled(boo); 048 } 049 } 050 051 public Source(PointDetails point/*, ArrayList<LayoutBlock> protectingBlock*/) { 052 if (point.getSensor() != null) { 053 addSourceObject(point.getSensor()); 054 } else { 055 addSourceObject(point.getSignal()); 056 } 057 //protectingBlocks = protectingBlock; 058 point.setSource(this); 059 sourceSignal = point.getSignal(); 060 pd = point; 061 } 062 063 /** 064 * Property change support for table in AddEntryExitPairPanel. 065 * Catch when paths go active. 066 * @since 4.17.4 067 */ 068 private final PropertyChangeSupport pcs = new PropertyChangeSupport(this); 069 070 /** 071 * Add property change listener. 072 * @since 4.17.4 073 * @param listener the pcl to add. 074 */ 075 public void addPropertyChangeListener(PropertyChangeListener listener) { 076 pcs.addPropertyChangeListener(listener); 077 } 078 079 /** 080 * Remove property change listener. 081 * @since 4.17.4 082 * @param listener the pcl to remove. 083 */ 084 public void removePropertyChangeListener(PropertyChangeListener listener) { 085 pcs.removePropertyChangeListener(listener); 086 } 087 088 /** 089 * @since 4.17.4 090 */ 091 @Override 092 public void propertyChange(PropertyChangeEvent evt) { 093 pcs.firePropertyChange("active", evt.getOldValue(), evt.getNewValue()); 094 } 095 096 097 void cancelClearInterlockFromSource(int cancelClear) { 098 for (DestinationPoints dp : pointToDest.values()) { 099 if (dp.isActive()) { 100 dp.cancelClearInterlock(cancelClear); 101 } 102 } 103 } 104 105 void setMenuEnabled(boolean boo) { 106 if (clear != null) { 107 clear.setEnabled(boo); 108 } 109 if (cancel != null) { 110 cancel.setEnabled(boo); 111 } 112 if (editClear != null) { 113 editClear.setEnabled(boo); 114 } 115 if (editCancel != null) { 116 editCancel.setEnabled(boo); 117 } 118 if (oneClick != null) { 119 oneClick.setEnabled(!boo); 120 } 121 if (editOneClick != null) { 122 editOneClick.setEnabled(!boo); 123 } 124 } 125 126 /** 127 * @since 4.17.4 128 * Making the source object available for scripting in Jython. 129 * @return the point details. 130 */ 131 public PointDetails getPoint() { 132 return pd; 133 } 134 135 LayoutBlock getStart() { 136 return pd.getFacing(); 137 } 138 139 List<LayoutBlock> getSourceProtecting() { 140 return pd.getProtecting(); 141 } 142 143 NamedBean getSourceSignal() { 144 if (sourceSignal == null) { 145 pd.getSignal(); 146 } 147 return sourceSignal; 148 } 149 150 /** 151 * @since 4.17.4 152 * Add Property Change Listener. 153 * @param dest the points details to add. 154 * @param id the points details id. 155 */ 156 public void addDestination(PointDetails dest, String id) { 157 if (pointToDest.containsKey(dest)) { 158 return; 159 } 160 161 DestinationPoints dstPoint = new DestinationPoints(dest, id, this); 162 dest.setDestination(dstPoint, this); 163 pointToDest.put(dest, dstPoint); 164 dstPoint.addPropertyChangeListener(this); 165 } 166 167 /** 168 * @since 4.17.4 169 * Remove Property Change Listener. 170 * @param dest the point details location to remove. 171 */ 172 public void removeDestination(PointDetails dest) { 173 pointToDest.get(dest).dispose(); 174 pointToDest.remove(dest); 175 dest.removePropertyChangeListener(this); 176 if (pointToDest.size() == 0) { 177 getPoint().removeSource(this); 178 } 179 } 180 181 void addSourceObject(NamedBean source) { 182 if (sourceObject == source) { 183 return; 184 } 185 sourceObject = source; 186 } 187 188 Object getSourceObject() { 189 return sourceObject; 190 } 191 192 public ArrayList<PointDetails> getDestinationPoints() { 193 //ArrayList<PointDetails> rtn = 194 return new ArrayList<PointDetails>(pointToDest.keySet()); 195 } 196 197 public boolean isDestinationValid(PointDetails destPoint) { 198 return pointToDest.containsKey(destPoint); 199 } 200 201 public boolean getUniDirection(Object dest, LayoutEditor panel) { 202 //Work on the principle that if the source is uniDirection, then the destination has to be. 203 PointDetails lookingFor = manager.getPointDetails(dest, panel); 204 if (pointToDest.containsKey(lookingFor)) { 205 return pointToDest.get(lookingFor).getUniDirection(); 206 } 207 return true; 208 } 209 210 public void setUniDirection(Object dest, LayoutEditor panel, boolean set) { 211 212 PointDetails lookingFor = manager.getPointDetails(dest, panel); 213 if (pointToDest.containsKey(lookingFor)) { 214 pointToDest.get(lookingFor).setUniDirection(set); 215 } 216 } 217 218 public boolean canBeBiDirection(Object dest, LayoutEditor panel) { 219 if (getSourceSignal() == null) { 220 return true; 221 } 222 //Work on the pinciple that if the source is uniDirection, then the destination has to be. 223 PointDetails lookingFor = manager.getPointDetails(dest, panel); 224 if (pointToDest.containsKey(lookingFor)) { 225 return pointToDest.get(lookingFor).getSignal() == null; 226 } 227 return false; 228 } 229 230 public boolean isRouteActive(PointDetails endpoint) { 231 if (pointToDest.containsKey(endpoint)) { 232 return pointToDest.get(endpoint).activeEntryExit; 233 } 234 return false; 235 } 236 237 public void activeBean(DestinationPoints dest, boolean reverseDirection) { 238 if (dest != null) { 239 dest.activeBean(reverseDirection); 240 } 241 } 242 243 public DestinationPoints getDestForPoint(PointDetails dp) { 244 return pointToDest.get(dp); 245 } 246 247 public int getNumberOfDestinations() { 248 return pointToDest.size(); 249 } 250 251 public void setEntryExitType(Object dest, LayoutEditor panel, int type) { 252 PointDetails lookingFor = manager.getPointDetails(dest, panel); 253 if (pointToDest.containsKey(lookingFor)) { 254 pointToDest.get(lookingFor).setEntryExitType(type); 255 } 256 if (type == EntryExitPairs.FULLINTERLOCK) { 257 if (sourceSignal instanceof SignalMast) { 258 if (!manager.isAbsSignalMode()) { 259 ((SignalMast) sourceSignal).setHeld(true); 260 } 261 } 262 } 263 } 264 265 public int getEntryExitType(Object dest, LayoutEditor panel) { 266 PointDetails lookingFor = manager.getPointDetails(dest, panel); 267 if (pointToDest.containsKey(lookingFor)) { 268 return pointToDest.get(lookingFor).getEntryExitType(); 269 } 270 271 return 0x00; 272 } 273 274 public void cancelInterlock(Object dest, LayoutEditor panel) { 275 PointDetails lookingFor = manager.getPointDetails(dest, panel); 276 if (pointToDest.containsKey(lookingFor)) { 277 pointToDest.get(lookingFor).cancelClearInterlock(EntryExitPairs.CANCELROUTE); 278 } 279 } 280 281 public String getUniqueId(Object dest, LayoutEditor panel) { 282 PointDetails lookingFor = manager.getPointDetails(dest, panel); 283 if (pointToDest.containsKey(lookingFor)) { 284 return pointToDest.get(lookingFor).getUniqueId(); 285 } 286 return null; 287 } 288 289 public ArrayList<String> getDestinationUniqueId() { 290 ArrayList<String> rList = new ArrayList<String>(); 291 for (DestinationPoints d : pointToDest.values()) { 292 rList.add(d.getUniqueId()); 293 } 294 return rList; 295 } 296 297 public DestinationPoints getByUniqueId(String id) { 298 for (DestinationPoints d : pointToDest.values()) { 299 if (d.getUniqueId().equals(id)) { 300 return d; 301 } 302 } 303 return null; 304 } 305 306 public DestinationPoints getByUserName(String id) { 307 for (DestinationPoints d : pointToDest.values()) { 308 String uname = d.getUserName(); 309 if (uname != null && uname.equals(id)) { 310 return d; 311 } 312 } 313 return null; 314 } 315 316}