001package jmri.jmrit.operations.rollingstock.engines; 002 003import java.beans.PropertyChangeEvent; 004import java.util.*; 005 006import javax.swing.JComboBox; 007 008import org.jdom2.Element; 009import org.slf4j.Logger; 010import org.slf4j.LoggerFactory; 011 012import jmri.*; 013import jmri.jmrit.operations.OperationsPanel; 014import jmri.jmrit.operations.rollingstock.RollingStock; 015import jmri.jmrit.operations.rollingstock.RollingStockManager; 016import jmri.jmrit.operations.setup.OperationsSetupXml; 017import jmri.jmrit.operations.trains.Train; 018import jmri.jmrit.operations.trains.TrainManifestHeaderText; 019 020/** 021 * Manages the engines. 022 * 023 * @author Daniel Boudreau Copyright (C) 2008 024 */ 025public class EngineManager extends RollingStockManager<Engine> 026 implements InstanceManagerAutoDefault, InstanceManagerAutoInitialize { 027 028 public EngineManager() { 029 } 030 031 /** 032 * Finds an existing engine or creates a new engine if needed requires engine's 033 * road and number 034 * 035 * @param engineRoad The engine's road initials 036 * @param engineNumber The engine's road number 037 * 038 * @return new engine or existing engine 039 */ 040 @Override 041 public Engine newRS(String engineRoad, String engineNumber) { 042 Engine engine = getByRoadAndNumber(engineRoad, engineNumber); 043 if (engine == null) { 044 engine = new Engine(engineRoad, engineNumber); 045 register(engine); 046 } 047 return engine; 048 } 049 050 @Override 051 public void deregister(Engine engine) { 052 super.deregister(engine); 053 InstanceManager.getDefault(EngineManagerXml.class).setDirty(true); 054 } 055 056 /** 057 * Sort by engine model 058 * 059 * @return list of engines ordered by engine model 060 */ 061 public List<Engine> getByModelList() { 062 return getByList(getByRoadNameList(), BY_MODEL); 063 } 064 065 /** 066 * Sort by engine consist 067 * 068 * @return list of engines ordered by engine consist 069 */ 070 public List<Engine> getByConsistList() { 071 return getByList(getByRoadNameList(), BY_CONSIST); 072 } 073 074 public List<Engine> getByHpList() { 075 return getByList(getByModelList(), BY_HP); 076 } 077 078 // The special sort options for engines 079 private static final int BY_MODEL = 30; 080 private static final int BY_CONSIST = 31; 081 private static final int BY_HP = 32; 082 083 // add engine options to sort comparator 084 @Override 085 protected java.util.Comparator<Engine> getComparator(int attribute) { 086 switch (attribute) { 087 case BY_MODEL: 088 return (e1, e2) -> (e1.getModel().compareToIgnoreCase(e2.getModel())); 089 case BY_CONSIST: 090 return (e1, e2) -> (e1.getConsistName().compareToIgnoreCase(e2.getConsistName())); 091 case BY_HP: 092 return (e1, e2) -> (e1.getHpInteger() - e2.getHpInteger()); 093 default: 094 return super.getComparator(attribute); 095 } 096 } 097 098 /** 099 * return a list available engines (no assigned train) engines are ordered least 100 * recently moved to most recently moved. 101 * 102 * @param train The Train requesting this list. 103 * 104 * @return Ordered list of engines not assigned to a train 105 */ 106 public List<Engine> getAvailableTrainList(Train train) { 107 // now build list of available engines for this route 108 List<Engine> out = new ArrayList<>(); 109 // get engines by moves list 110 for (RollingStock rs : getByMovesList()) { 111 Engine engine = (Engine) rs; 112 if (engine.getTrack() != null && (engine.getTrain() == null || engine.getTrain() == train)) { 113 out.add(engine); 114 } 115 } 116 return out; 117 } 118 119 /** 120 * Returns a list of locos sorted by blocking number for a train. This returns a 121 * list of consisted locos in the order that they were entered in. 122 * 123 * @param train The Train requesting this list. 124 * @return A list of sorted locos. 125 */ 126 public List<Engine> getByTrainBlockingList(Train train) { 127 return getByList(super.getByTrainList(train), BY_BLOCKING); 128 } 129 130 /** 131 * Get a list of engine road names. 132 * 133 * @param model The string model name, can be NONE. 134 * 135 * @return List of engine road names. 136 */ 137 public List<String> getEngineRoadNames(String model) { 138 List<String> names = new ArrayList<>(); 139 Enumeration<String> en = _hashTable.keys(); 140 while (en.hasMoreElements()) { 141 Engine engine = getById(en.nextElement()); 142 if ((engine.getModel().equals(model) || model.equals(NONE)) && !names.contains(engine.getRoadName())) { 143 names.add(engine.getRoadName()); 144 } 145 } 146 java.util.Collections.sort(names); 147 return names; 148 } 149 150 public void updateEngineRoadComboBox(String engineModel, JComboBox<String> roadEngineBox) { 151 roadEngineBox.removeAllItems(); 152 roadEngineBox.addItem(NONE); 153 List<String> roads = getEngineRoadNames(engineModel); 154 for (String roadName : roads) { 155 roadEngineBox.addItem(roadName); 156 } 157 OperationsPanel.padComboBox(roadEngineBox); 158 } 159 160 int _commentLength = 0; 161 162 @edu.umd.cs.findbugs.annotations.SuppressFBWarnings( value="SLF4J_FORMAT_SHOULD_BE_CONST", 163 justification="I18N of Info Message") 164 public int getMaxCommentLength() { 165 if (_commentLength == 0) { 166 _commentLength = TrainManifestHeaderText.getStringHeader_Comment().length(); 167 String comment = ""; 168 Engine engineMax = null; 169 for (Engine engine : getList()) { 170 if (engine.getComment().length() > _commentLength) { 171 _commentLength = engine.getComment().length(); 172 comment = engine.getComment(); 173 engineMax = engine; 174 } 175 } 176 if (engineMax != null) { 177 log.info(Bundle.getMessage("InfoMaxComment", engineMax.toString(), comment, _commentLength)); 178 } 179 } 180 return _commentLength; 181 } 182 183 public void load(Element root) { 184 if (root.getChild(Xml.ENGINES) != null) { 185 List<Element> engines = root.getChild(Xml.ENGINES).getChildren(Xml.ENGINE); 186 log.debug("readFile sees {} engines", engines.size()); 187 for (Element e : engines) { 188 register(new Engine(e)); 189 } 190 } 191 } 192 193 /** 194 * Create an XML element to represent this Entry. This member has to remain 195 * synchronized with the detailed DTD in operations-engines.dtd. 196 * 197 * @param root The common Element for operations-engines.dtd. 198 * 199 */ 200 public void store(Element root) { 201 Element values; 202 root.addContent(values = new Element(Xml.ENGINES)); 203 // add entries 204 for (RollingStock rs : getByRoadNameList()) { 205 Engine eng = (Engine) rs; 206 values.addContent(eng.store()); 207 } 208 } 209 210 protected void setDirtyAndFirePropertyChange(String p, Object old, Object n) { 211 // Set dirty 212 InstanceManager.getDefault(EngineManagerXml.class).setDirty(true); 213 super.firePropertyChange(p, old, n); 214 } 215 216 @Override 217 public void propertyChange(PropertyChangeEvent evt) { 218 if (evt.getPropertyName().equals(Engine.COMMENT_CHANGED_PROPERTY)) { 219 _commentLength = 0; 220 } 221 super.propertyChange(evt); 222 } 223 224 private final static Logger log = LoggerFactory.getLogger(EngineManager.class); 225 226 @Override 227 public void initialize() { 228 InstanceManager.getDefault(OperationsSetupXml.class); // load setup 229 // create manager to load engines and their attributes 230 InstanceManager.getDefault(EngineManagerXml.class); 231 } 232}