001package jmri.jmrit.operations.trains; 002 003import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; 004import java.awt.Dimension; 005import java.awt.FlowLayout; 006import java.awt.GridBagLayout; 007import javax.swing.BorderFactory; 008import javax.swing.BoxLayout; 009import javax.swing.ButtonGroup; 010import javax.swing.JButton; 011import javax.swing.JCheckBox; 012import javax.swing.JComboBox; 013import javax.swing.JLabel; 014import javax.swing.JPanel; 015import javax.swing.JRadioButton; 016import javax.swing.JScrollPane; 017import jmri.InstanceManager; 018import jmri.jmrit.operations.OperationsFrame; 019import jmri.jmrit.operations.OperationsXml; 020import jmri.jmrit.operations.rollingstock.cars.CarLoad; 021import jmri.jmrit.operations.rollingstock.cars.CarLoads; 022import jmri.jmrit.operations.rollingstock.cars.CarTypes; 023import jmri.jmrit.operations.setup.Control; 024import jmri.jmrit.operations.setup.Setup; 025import org.slf4j.Logger; 026import org.slf4j.LoggerFactory; 027 028/** 029 * Frame for user edit of a train's load options 030 * 031 * @author Dan Boudreau Copyright (C) 2013 032 * 033 */ 034public class TrainLoadOptionsFrame extends OperationsFrame implements java.beans.PropertyChangeListener { 035 036 private static boolean loadAndType = false; 037 038 Train _train = null; 039 040 JPanel pLoadControls = new JPanel(); 041 JPanel panelLoads = new JPanel(); 042 JScrollPane paneLoads = new JScrollPane(panelLoads); 043 044 // labels 045 JLabel trainName = new JLabel(); 046 JLabel trainDescription = new JLabel(); 047 048 // major buttons 049 JButton addLoadButton = new JButton(Bundle.getMessage("AddLoad")); 050 JButton deleteLoadButton = new JButton(Bundle.getMessage("DeleteLoad")); 051 JButton deleteAllLoadsButton = new JButton(Bundle.getMessage("DeleteAll")); 052 JButton saveTrainButton = new JButton(Bundle.getMessage("SaveTrain")); 053 054 // radio buttons 055 JRadioButton loadNameAll = new JRadioButton(Bundle.getMessage("AcceptAll")); 056 JRadioButton loadNameInclude = new JRadioButton(Bundle.getMessage("AcceptOnly")); 057 JRadioButton loadNameExclude = new JRadioButton(Bundle.getMessage("Exclude")); 058 059 ButtonGroup loadGroup = new ButtonGroup(); 060 061 // check boxes 062 JCheckBox loadAndTypeCheckBox = new JCheckBox(Bundle.getMessage("TypeAndLoad")); 063 064 // text field 065 // combo boxes 066 JComboBox<String> comboBoxTypes = InstanceManager.getDefault(CarTypes.class).getComboBox(); 067 JComboBox<String> comboBoxLoads = InstanceManager.getDefault(CarLoads.class).getComboBox(null); 068 069 public static final String DISPOSE = "dispose"; // NOI18N 070 071 public TrainLoadOptionsFrame() { 072 super(Bundle.getMessage("MenuItemLoadOptions")); 073 } 074 075 public void initComponents(TrainEditFrame parent) { 076 077 parent.setChildFrame(this); 078 _train = parent._train; 079 080 getContentPane().setLayout(new BoxLayout(getContentPane(), BoxLayout.Y_AXIS)); 081 082 // Layout the panel by rows 083 JPanel p1 = new JPanel(); 084 p1.setLayout(new BoxLayout(p1, BoxLayout.X_AXIS)); 085 p1.setMaximumSize(new Dimension(2000, 250)); 086 087 // Layout the panel by rows 088 // row 1a 089 JPanel pName = new JPanel(); 090 pName.setLayout(new GridBagLayout()); 091 pName.setBorder(BorderFactory.createTitledBorder(Bundle.getMessage("Name"))); 092 addItem(pName, trainName, 0, 0); 093 094 // row 1b 095 JPanel pDesc = new JPanel(); 096 pDesc.setLayout(new GridBagLayout()); 097 pDesc.setBorder(BorderFactory.createTitledBorder(Bundle.getMessage("Description"))); 098 addItem(pDesc, trainDescription, 0, 0); 099 100 p1.add(pName); 101 p1.add(pDesc); 102 103 // row 3 104 JPanel p3 = new JPanel(); 105 p3.setLayout(new BoxLayout(p3, BoxLayout.Y_AXIS)); 106 JScrollPane pane3 = new JScrollPane(p3); 107 pane3.setBorder(BorderFactory.createTitledBorder(Bundle.getMessage("LoadsTrain"))); 108 pane3.setMaximumSize(new Dimension(2000, 400)); 109 110 JPanel pLoadRadioButtons = new JPanel(); 111 pLoadRadioButtons.setLayout(new FlowLayout()); 112 113 pLoadRadioButtons.add(loadNameAll); 114 pLoadRadioButtons.add(loadNameInclude); 115 pLoadRadioButtons.add(loadNameExclude); 116 pLoadRadioButtons.add(loadAndTypeCheckBox); 117 118 pLoadControls.setLayout(new FlowLayout()); 119 120 pLoadControls.add(comboBoxTypes); 121 pLoadControls.add(comboBoxLoads); 122 pLoadControls.add(addLoadButton); 123 pLoadControls.add(deleteLoadButton); 124 pLoadControls.add(deleteAllLoadsButton); 125 126 pLoadControls.setVisible(false); 127 128 p3.add(pLoadRadioButtons); 129 p3.add(pLoadControls); 130 131 // row 4 132 panelLoads.setLayout(new GridBagLayout()); 133 paneLoads.setBorder(BorderFactory.createTitledBorder(Bundle.getMessage("Loads"))); 134 135 ButtonGroup loadGroup = new ButtonGroup(); 136 loadGroup.add(loadNameAll); 137 loadGroup.add(loadNameInclude); 138 loadGroup.add(loadNameExclude); 139 140 // row 12 141 JPanel panelButtons = new JPanel(); 142 panelButtons.setLayout(new GridBagLayout()); 143 panelButtons.setBorder(BorderFactory.createTitledBorder("")); 144 panelButtons.setMaximumSize(new Dimension(2000, 200)); 145 146 // row 13 147 addItem(panelButtons, saveTrainButton, 0, 0); 148 149 getContentPane().add(p1); 150 getContentPane().add(pane3); 151 getContentPane().add(paneLoads); 152 getContentPane().add(panelButtons); 153 154 // setup buttons 155 addButtonAction(saveTrainButton); 156 157 addButtonAction(deleteLoadButton); 158 addButtonAction(deleteAllLoadsButton); 159 addButtonAction(addLoadButton); 160 161 addRadioButtonAction(loadNameAll); 162 addRadioButtonAction(loadNameInclude); 163 addRadioButtonAction(loadNameExclude); 164 165 addComboBoxAction(comboBoxTypes); 166 167 if (_train != null) { 168 trainName.setText(_train.getName()); 169 trainDescription.setText(_train.getDescription()); 170 updateButtons(true); 171 // listen for train changes 172 _train.addPropertyChangeListener(this); 173 } else { 174 updateButtons(false); 175 } 176 addHelpMenu("package.jmri.jmrit.operations.Operations_TrainLoadOptions", true); // NOI18N 177 updateTypeComboBoxes(); 178 updateLoadComboBoxes(); 179 updateLoadNames(); 180 181 // get notified if car roads, loads, and owners gets modified 182 InstanceManager.getDefault(CarTypes.class).addPropertyChangeListener(this); 183 InstanceManager.getDefault(CarLoads.class).addPropertyChangeListener(this); 184 loadAndTypeCheckBox.setSelected(loadAndType); 185 186 initMinimumSize(new Dimension(Control.panelWidth600, Control.panelHeight400)); 187 } 188 189 // Save 190 @Override 191 public void buttonActionPerformed(java.awt.event.ActionEvent ae) { 192 if (_train != null) { 193 if (ae.getSource() == saveTrainButton) { 194 log.debug("train save button activated"); 195 saveTrain(); 196 } 197 if (ae.getSource() == addLoadButton) { 198 String loadName = (String) comboBoxLoads.getSelectedItem(); 199 if (loadAndTypeCheckBox.isSelected()) { 200 loadName = comboBoxTypes.getSelectedItem() + CarLoad.SPLIT_CHAR + loadName; 201 } 202 if (_train.addLoadName(loadName)) { 203 updateLoadNames(); 204 } 205 selectNextItemComboBox(comboBoxLoads); 206 } 207 if (ae.getSource() == deleteLoadButton) { 208 String loadName = (String) comboBoxLoads.getSelectedItem(); 209 if (loadAndTypeCheckBox.isSelected()) { 210 loadName = comboBoxTypes.getSelectedItem() + CarLoad.SPLIT_CHAR + loadName; 211 } 212 if (_train.deleteLoadName(loadName)) { 213 updateLoadNames(); 214 } 215 selectNextItemComboBox(comboBoxLoads); 216 } 217 if (ae.getSource() == deleteAllLoadsButton) { 218 deleteAllLoads(); 219 } 220 } 221 } 222 223 @Override 224 public void radioButtonActionPerformed(java.awt.event.ActionEvent ae) { 225 log.debug("radio button activated"); 226 if (_train != null) { 227 if (ae.getSource() == loadNameAll) { 228 _train.setLoadOption(Train.ALL_LOADS); 229 updateLoadNames(); 230 } 231 if (ae.getSource() == loadNameInclude) { 232 _train.setLoadOption(Train.INCLUDE_LOADS); 233 updateLoadNames(); 234 } 235 if (ae.getSource() == loadNameExclude) { 236 _train.setLoadOption(Train.EXCLUDE_LOADS); 237 updateLoadNames(); 238 } 239 } 240 } 241 242 // Car type combo box has been changed, show loads associated with this car type 243 @Override 244 public void comboBoxActionPerformed(java.awt.event.ActionEvent ae) { 245 if (ae.getSource() == comboBoxTypes) { 246 updateLoadComboBoxes(); 247 } 248 } 249 250 protected void updateButtons(boolean enabled) { 251 saveTrainButton.setEnabled(enabled); 252 253 loadNameAll.setEnabled(enabled); 254 loadNameInclude.setEnabled(enabled); 255 loadNameExclude.setEnabled(enabled); 256 loadAndTypeCheckBox.setEnabled(enabled); 257 } 258 259 private void updateLoadNames() { 260 log.debug("Update load names"); 261 panelLoads.removeAll(); 262 if (_train != null) { 263 // set radio button 264 loadNameAll.setSelected(_train.getLoadOption().equals(Train.ALL_LOADS)); 265 loadNameInclude.setSelected(_train.getLoadOption().equals(Train.INCLUDE_ROADS)); 266 loadNameExclude.setSelected(_train.getLoadOption().equals(Train.EXCLUDE_ROADS)); 267 268 pLoadControls.setVisible(!loadNameAll.isSelected()); 269 270 if (!loadNameAll.isSelected()) { 271 int x = 0; 272 int y = 0; // vertical position in panel 273 274 int numberOfLoads = getNumberOfCheckboxesPerLine() / 2 + 1; 275 for (String loadName : _train.getLoadNames()) { 276 JLabel load = new JLabel(); 277 load.setText(loadName); 278 addItemTop(panelLoads, load, x++, y); 279 // limit the number of loads per line 280 if (x > numberOfLoads) { 281 y++; 282 x = 0; 283 } 284 } 285 revalidate(); 286 } 287 } else { 288 loadNameAll.setSelected(true); 289 } 290 panelLoads.repaint(); 291 panelLoads.revalidate(); 292 } 293 294 private void deleteAllLoads() { 295 if (_train != null) { 296 for (String load : _train.getLoadNames()) { 297 _train.deleteLoadName(load); 298 } 299 } 300 updateLoadNames(); 301 } 302 303 @SuppressFBWarnings(value = "ST_WRITE_TO_STATIC_FROM_INSTANCE_METHOD", justification = "GUI ease of use") 304 private void saveTrain() { 305 // save the last state of the "Use car type and load" checkbox 306 loadAndType = loadAndTypeCheckBox.isSelected(); 307 OperationsXml.save(); 308 if (Setup.isCloseWindowOnSaveEnabled()) { 309 dispose(); 310 } 311 } 312 313 private void updateTypeComboBoxes() { 314 InstanceManager.getDefault(CarTypes.class).updateComboBox(comboBoxTypes); 315 // remove types not serviced by this train 316 for (int i = comboBoxTypes.getItemCount() - 1; i >= 0; i--) { 317 String type = comboBoxTypes.getItemAt(i); 318 if (_train != null && !_train.isTypeNameAccepted(type)) { 319 comboBoxTypes.removeItem(type); 320 } 321 } 322 } 323 324 private void updateLoadComboBoxes() { 325 String carType = (String) comboBoxTypes.getSelectedItem(); 326 InstanceManager.getDefault(CarLoads.class).updateComboBox(carType, comboBoxLoads); 327 } 328 329 @Override 330 public void dispose() { 331 InstanceManager.getDefault(CarTypes.class).removePropertyChangeListener(this); 332 InstanceManager.getDefault(CarLoads.class).removePropertyChangeListener(this); 333 if (_train != null) { 334 _train.removePropertyChangeListener(this); 335 } 336 super.dispose(); 337 } 338 339 @Override 340 public void propertyChange(java.beans.PropertyChangeEvent e) { 341 if (Control.SHOW_PROPERTY) { 342 log.debug("Property change: ({}) old: ({}) new: ({})", e.getPropertyName(), e.getOldValue(), e 343 .getNewValue()); 344 } 345 if (e.getPropertyName().equals(CarLoads.LOAD_NAME_CHANGED_PROPERTY) 346 || e.getPropertyName().equals(CarLoads.LOAD_CHANGED_PROPERTY)) { 347 updateLoadComboBoxes(); 348 updateLoadNames(); 349 } 350 if (e.getPropertyName().equals(CarTypes.CARTYPES_CHANGED_PROPERTY) 351 || e.getPropertyName().equals(Train.TYPES_CHANGED_PROPERTY)) { 352 updateTypeComboBoxes(); 353 } 354 } 355 356 private final static Logger log = LoggerFactory.getLogger(TrainLoadOptionsFrame.class); 357}