001package jmri.jmrit.operations.trains.tools; 002 003import java.awt.Dimension; 004import java.awt.GridBagLayout; 005import java.util.ArrayList; 006import java.util.List; 007 008import javax.swing.*; 009 010import jmri.InstanceManager; 011import jmri.jmrit.operations.OperationsFrame; 012import jmri.jmrit.operations.OperationsXml; 013import jmri.jmrit.operations.rollingstock.cars.CarTypes; 014import jmri.jmrit.operations.setup.Control; 015import jmri.jmrit.operations.setup.Setup; 016import jmri.jmrit.operations.trains.Train; 017import jmri.jmrit.operations.trains.TrainManager; 018import jmri.util.swing.JmriJOptionPane; 019 020/** 021 * Frame to display which trains service certain car types 022 * 023 * @author Dan Boudreau Copyright (C) 2009, 2022 024 */ 025public class TrainsByCarTypeFrame extends OperationsFrame implements java.beans.PropertyChangeListener { 026 027 TrainManager trainManager = InstanceManager.getDefault(TrainManager.class); 028 029 ArrayList<JCheckBox> trainList = new ArrayList<>(); 030 JPanel trainCheckBoxes = new JPanel(); 031 032 // panels 033 JPanel pTrains; 034 035 // major buttons 036 JButton clearButton = new JButton(Bundle.getMessage("ClearAll")); 037 JButton setButton = new JButton(Bundle.getMessage("SelectAll")); 038 JButton saveButton = new JButton(Bundle.getMessage("ButtonSave")); 039 040 // check boxes 041 JCheckBox copyCheckBox = new JCheckBox(Bundle.getMessage("ButtonCopy")); 042 043 // combo boxes 044 JComboBox<String> typeComboBox = InstanceManager.getDefault(CarTypes.class).getComboBox(); 045 JComboBox<String> copyComboBox = InstanceManager.getDefault(CarTypes.class).getComboBox(); 046 047 public TrainsByCarTypeFrame() { 048 super(Bundle.getMessage("TitleModifyTrains")); 049 } 050 051 public void initComponents(String carType) { 052 053 // general GUI config 054 getContentPane().setLayout(new BoxLayout(getContentPane(), BoxLayout.Y_AXIS)); 055 056 // Set up the panels 057 JPanel pCarType = new JPanel(); 058 pCarType.setLayout(new GridBagLayout()); 059 pCarType.setBorder(BorderFactory.createTitledBorder(Bundle.getMessage("Type"))); 060 061 JPanel pCarCopy = new JPanel(); 062 pCarCopy.setLayout(new GridBagLayout()); 063 addItem(pCarCopy, copyCheckBox, 0, 0); 064 addItem(pCarCopy, new JLabel(" "), 1, 0); // some space 065 addItem(pCarCopy, copyComboBox, 2, 0); 066 pCarCopy.setBorder(BorderFactory.createTitledBorder(Bundle.getMessage("CopyType"))); 067 068 addItem(pCarType, typeComboBox, 0, 0); 069 addItem(pCarType, new JLabel(" "), 1, 0); // some space 070 addItem(pCarType, pCarCopy, 2, 0); 071 072 typeComboBox.setSelectedItem(carType); 073 copyCheckBox.setToolTipText(Bundle.getMessage("TipCopyCarType")); 074 075 pTrains = new JPanel(); 076 pTrains.setLayout(new GridBagLayout()); 077 JScrollPane trainPane = new JScrollPane(pTrains); 078 trainPane.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED); 079 trainPane.setBorder(BorderFactory.createTitledBorder(Bundle.getMessage("Trains"))); 080 updateTrains(); 081 082 JPanel pButtons = new JPanel(); 083 pButtons.setLayout(new GridBagLayout()); 084 pButtons.setBorder(BorderFactory.createEtchedBorder()); 085 086 addItem(pButtons, clearButton, 0, 0); 087 addItem(pButtons, setButton, 1, 0); 088 addItem(pButtons, saveButton, 2, 0); 089 090 getContentPane().add(pCarType); 091 getContentPane().add(trainPane); 092 getContentPane().add(pButtons); 093 094 // setup combo box 095 addComboBoxAction(typeComboBox); 096 addComboBoxAction(copyComboBox); 097 098 // setup buttons 099 addButtonAction(setButton); 100 addButtonAction(clearButton); 101 addButtonAction(saveButton); 102 103 // setup checkbox 104 addCheckBoxAction(copyCheckBox); 105 106 trainManager.addPropertyChangeListener(this); 107 InstanceManager.getDefault(CarTypes.class).addPropertyChangeListener(this); 108 109 // build menu 110 JMenuBar menuBar = new JMenuBar(); 111 JMenu toolMenu = new JMenu(Bundle.getMessage("MenuTools")); 112 toolMenu.add(new PrintTrainsByCarTypesAction(false)); 113 toolMenu.add(new PrintTrainsByCarTypesAction(true)); 114 menuBar.add(toolMenu); 115 setJMenuBar(menuBar); 116 addHelpMenu("package.jmri.jmrit.operations.Operations_ModifyTrainsByCarType", true); // NOI18N 117 118 setPreferredSize(null); 119 initMinimumSize(new Dimension(Control.panelWidth300, Control.panelHeight250)); 120 } 121 122 @Override 123 public void comboBoxActionPerformed(java.awt.event.ActionEvent ae) { 124 log.debug("combo box action"); 125 updateTrains(); 126 } 127 128 // Save, Delete, Add 129 @Override 130 public void buttonActionPerformed(java.awt.event.ActionEvent ae) { 131 if (ae.getSource() == saveButton) { 132 save(); 133 } 134 if (ae.getSource() == setButton) { 135 selectCheckboxes(true); 136 } 137 if (ae.getSource() == clearButton) { 138 selectCheckboxes(false); 139 } 140 } 141 142 /** 143 * Update the car types that trains and tracks service. Note that the 144 * checkbox name is the id of the train or track. 145 */ 146 private void save() { 147 if (copyCheckBox.isSelected() && 148 JmriJOptionPane.showConfirmDialog(this, Bundle.getMessage("CopyCarType", 149 typeComboBox.getSelectedItem(), copyComboBox.getSelectedItem()), 150 Bundle.getMessage("CopyCarTypeTitle"), 151 JmriJOptionPane.YES_NO_OPTION) != JmriJOptionPane.YES_OPTION) { 152 return; 153 } 154 log.debug("Save {} trains", trainList.size()); 155 removePropertyChangeTrains(); 156 // protected against concurrent operation by making a copy 157 for (JCheckBox cb : new ArrayList<>(trainList)) { 158 Train train = trainManager.getTrainById(cb.getName()); 159 if (cb.isSelected()) { 160 train.addTypeName((String) typeComboBox.getSelectedItem()); 161 } else { 162 train.deleteTypeName((String) typeComboBox.getSelectedItem()); 163 } 164 } 165 OperationsXml.save(); // save files 166 updateTrains(); 167 if (Setup.isCloseWindowOnSaveEnabled()) { 168 dispose(); 169 } 170 } 171 172 private void updateTrains() { 173 log.debug("update trains"); 174 removePropertyChangeTrains(); 175 trainList.clear(); 176 int x = 0; 177 pTrains.removeAll(); 178 String carType = (String) typeComboBox.getSelectedItem(); 179 if (copyCheckBox.isSelected()) { 180 carType = (String) copyComboBox.getSelectedItem(); 181 } 182 List<Train> trains = trainManager.getTrainsByNameList(); 183 for (Train train : trains) { 184 train.addPropertyChangeListener(this); 185 JCheckBox cb = new JCheckBox(train.getName()); 186 cb.setName(train.getId()); 187 cb.setToolTipText(Bundle.getMessage("TipTrainCarType", carType)); 188 addCheckBoxAction(cb); 189 trainList.add(cb); 190 cb.setSelected(train.isTypeNameAccepted(carType)); 191 addItemLeft(pTrains, cb, 0, x); 192 JLabel description = new JLabel(train.getDescription()); 193 addItemLeft(pTrains, description, 1, x++); 194 } 195 pTrains.revalidate(); 196 repaint(); 197 } 198 199 private void updateComboBox() { 200 log.debug("update combobox"); 201 InstanceManager.getDefault(CarTypes.class).updateComboBox(typeComboBox); 202 InstanceManager.getDefault(CarTypes.class).updateComboBox(copyComboBox); 203 } 204 205 private void selectCheckboxes(boolean b) { 206 for (JCheckBox checkBox : new ArrayList<>(trainList)) { 207 checkBox.setSelected(b); 208 } 209 } 210 211 @Override 212 public void checkBoxActionPerformed(java.awt.event.ActionEvent ae) { 213 // copy checkbox? 214 if (ae.getSource() == copyCheckBox) { 215 updateTrains(); 216 } else { 217 JCheckBox cb = (JCheckBox) ae.getSource(); 218 log.debug("Checkbox {} text: {}", cb.getName(), cb.getText()); 219 if (trainList.contains(cb)) { 220 log.debug("Checkbox train {}", cb.getText()); 221 } else { 222 log.error("Error checkbox not found"); 223 } 224 } 225 } 226 227 private void removePropertyChangeTrains() { 228 for (JCheckBox checkBox : new ArrayList<>(trainList)) { 229 // if object has been deleted, it's not here; ignore it 230 Train train = trainManager.getTrainById(checkBox.getName()); 231 if (train != null) { 232 train.removePropertyChangeListener(this); 233 } 234 } 235 } 236 237 @Override 238 public void dispose() { 239 trainManager.removePropertyChangeListener(this); 240 InstanceManager.getDefault(CarTypes.class).removePropertyChangeListener(this); 241 removePropertyChangeTrains(); 242 super.dispose(); 243 } 244 245 @Override 246 public void propertyChange(java.beans.PropertyChangeEvent e) { 247 log.debug("Property change {} old: {} new: {}", e.getPropertyName(), e.getOldValue(), e.getNewValue()); 248 if (e.getPropertyName().equals(TrainManager.LISTLENGTH_CHANGED_PROPERTY) || 249 e.getPropertyName().equals(Train.TYPES_CHANGED_PROPERTY) || 250 e.getPropertyName().equals(Train.NAME_CHANGED_PROPERTY) || 251 e.getPropertyName().equals(Train.DESCRIPTION_CHANGED_PROPERTY)) { 252 updateTrains(); 253 } 254 if (e.getPropertyName().equals(CarTypes.CARTYPES_CHANGED_PROPERTY) || 255 e.getPropertyName().equals(CarTypes.CARTYPES_NAME_CHANGED_PROPERTY)) { 256 updateComboBox(); 257 } 258 } 259 260 private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(TrainsByCarTypeFrame.class); 261}