001package jmri.jmrit.operations.locations.tools; 002 003import java.awt.Dimension; 004import java.awt.GridBagLayout; 005 006import javax.swing.*; 007 008import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; 009import jmri.InstanceManager; 010import jmri.jmrit.operations.OperationsFrame; 011import jmri.jmrit.operations.OperationsXml; 012import jmri.jmrit.operations.locations.*; 013import jmri.jmrit.operations.locations.schedules.ScheduleManager; 014import jmri.jmrit.operations.rollingstock.RollingStock; 015import jmri.jmrit.operations.rollingstock.RollingStockManager; 016import jmri.jmrit.operations.rollingstock.cars.CarManager; 017import jmri.jmrit.operations.rollingstock.engines.EngineManager; 018import jmri.jmrit.operations.setup.Control; 019import jmri.jmrit.operations.trains.TrainCommon; 020import jmri.util.swing.JmriJOptionPane; 021 022/** 023 * Frame for copying a track for operations. 024 * 025 * @author Bob Jacobsen Copyright (C) 2001 026 * @author Daniel Boudreau Copyright (C) 2013 027 */ 028public class TrackCopyFrame extends OperationsFrame implements java.beans.PropertyChangeListener { 029 030 // text field 031 JTextField trackNameTextField = new javax.swing.JTextField(Control.max_len_string_track_name); 032 033 // major buttons 034 JButton copyButton = new javax.swing.JButton(Bundle.getMessage("ButtonCopy")); 035 JButton saveButton = new javax.swing.JButton(Bundle.getMessage("ButtonSave")); 036 037 // combo boxes 038 JComboBox<Location> locationBox = InstanceManager.getDefault(LocationManager.class).getComboBox(); 039 JComboBox<Track> trackBox = new JComboBox<>(); 040 JComboBox<Location> destinationBox = InstanceManager.getDefault(LocationManager.class).getComboBox(); 041 042 // checkboxes 043 JCheckBox sameNameCheckBox = new JCheckBox(Bundle.getMessage("SameName")); 044 JCheckBox moveRollingStockCheckBox = new JCheckBox(Bundle.getMessage("MoveRollingStock")); 045 JCheckBox deleteTrackCheckBox = new JCheckBox(Bundle.getMessage("DeleteCopiedTrack")); 046 047 Location _location; // copy from this location 048 Location _destination; // copy the track to this location 049 050 // remember state of checkboxes during a session 051 static boolean sameName = false; 052 static boolean moveRollingStock = false; 053 static boolean deleteTrack = false; 054 055 /* 056 * Copies track to destination 057 */ 058 public TrackCopyFrame(Track track, Location destination) { 059 _destination = destination; 060 061 // general GUI config 062 getContentPane().setLayout(new BoxLayout(getContentPane(), BoxLayout.Y_AXIS)); 063 064 // Set up the panels 065 // Layout the panel by rows 066 // row 1 067 JPanel pName = new JPanel(); 068 pName.setLayout(new GridBagLayout()); 069 pName.setBorder(BorderFactory.createTitledBorder(Bundle.getMessage("TrackName"))); 070 addItem(pName, trackNameTextField, 0, 0); 071 072 // row 2 073 JPanel pCopy = new JPanel(); 074 pCopy.setLayout(new GridBagLayout()); 075 pCopy.setBorder(BorderFactory.createTitledBorder(Bundle.getMessage("SelectTrackToCopy"))); 076 addItem(pCopy, locationBox, 0, 0); 077 addItem(pCopy, trackBox, 1, 0); 078 079 // row 3 080 JPanel pCopyTo = new JPanel(); 081 pCopyTo.setLayout(new GridBagLayout()); 082 pCopyTo.setBorder(BorderFactory.createTitledBorder(Bundle.getMessage("SelectCopyToLocation"))); 083 addItem(pCopyTo, destinationBox, 0, 0); 084 085 // row 4 086 JPanel pOptions = new JPanel(); 087 pOptions.setLayout(new GridBagLayout()); 088 pOptions.setBorder(BorderFactory.createTitledBorder(Bundle.getMessage("Options"))); 089 addItemLeft(pOptions, sameNameCheckBox, 0, 0); 090 addItemLeft(pOptions, moveRollingStockCheckBox, 0, 1); 091 addItemLeft(pOptions, deleteTrackCheckBox, 0, 2); 092 093 // row 5 094 JPanel pButton = new JPanel(); 095 pButton.setLayout(new GridBagLayout()); 096 addItem(pButton, copyButton, 0, 0); 097 addItem(pButton, saveButton, 1, 0); 098 099 getContentPane().add(pName); 100 getContentPane().add(pCopy); 101 getContentPane().add(pCopyTo); 102 getContentPane().add(pOptions); 103 getContentPane().add(pButton); 104 105 addComboBoxAction(locationBox); 106 addComboBoxAction(trackBox); 107 108 addComboBoxAction(destinationBox); 109 110 // set the checkbox states 111 sameNameCheckBox.setSelected(sameName); 112 moveRollingStockCheckBox.setSelected(moveRollingStock); 113 deleteTrackCheckBox.setSelected(deleteTrack); 114 deleteTrackCheckBox.setEnabled(moveRollingStockCheckBox.isSelected()); 115 116 // get notified if combo box gets modified 117 InstanceManager.getDefault(LocationManager.class).addPropertyChangeListener(this); 118 119 // add help menu to window 120 addHelpMenu("package.jmri.jmrit.operations.Operations_CopyTrack", true); // NOI18N 121 122 pack(); 123 setMinimumSize(new Dimension(Control.panelWidth400, Control.panelHeight400)); 124 125 if (track != null) { 126 locationBox.setSelectedItem(track.getLocation()); 127 trackBox.setSelectedItem(track); 128 } 129 destinationBox.setSelectedItem(destination); 130 131 // setup buttons 132 addButtonAction(copyButton); 133 addButtonAction(saveButton); 134 135 addCheckBoxAction(sameNameCheckBox); 136 addCheckBoxAction(moveRollingStockCheckBox); 137 138 setTitle(Bundle.getMessage("MenuItemCopyTrack")); 139 } 140 141 // location combo box 142 @Override 143 protected void comboBoxActionPerformed(java.awt.event.ActionEvent ae) { 144 if (ae.getSource() == locationBox) { 145 updateTrackComboBox(); 146 } 147 if (ae.getSource() == trackBox) { 148 updateTrackName(); 149 } 150 if (ae.getSource() == destinationBox) { 151 _destination = (Location) destinationBox.getSelectedItem(); 152 copyButton.setEnabled(_destination != null); 153 } 154 } 155 156 protected void updateTrackComboBox() { 157 log.debug("update track combobox"); 158 if (_location != null) { 159 _location.removePropertyChangeListener(this); 160 } 161 if (locationBox.getSelectedItem() == null) { 162 trackBox.removeAllItems(); 163 } else { 164 log.debug("copy from location: {}", locationBox.getSelectedItem()); 165 _location = (Location) locationBox.getSelectedItem(); 166 Track track = (Track)trackBox.getSelectedItem(); 167 _location.updateComboBox(trackBox); 168 trackBox.setSelectedItem(track); 169 _location.addPropertyChangeListener(this); 170 } 171 } 172 173 protected void updateTrackName() { 174 if (sameNameCheckBox.isSelected() && trackBox.getSelectedItem() != null) { 175 trackNameTextField.setText(trackBox.getSelectedItem().toString()); 176 } 177 } 178 179 @Override 180 @SuppressFBWarnings(value = "ST_WRITE_TO_STATIC_FROM_INSTANCE_METHOD", justification = "GUI ease of use") 181 protected void buttonActionPerformed(java.awt.event.ActionEvent ae) { 182 if (ae.getSource() == copyButton) { 183 log.debug("copy track button activated"); 184 if (!checkName()) { 185 return; 186 } 187 if (trackBox.getSelectedItem() == null || trackBox.getSelectedItem().equals(Location.NONE) || _destination == null) { 188 // tell user that they need to select a track to copy 189 JmriJOptionPane.showMessageDialog(this, Bundle.getMessage("SelectLocationAndTrack"), Bundle 190 .getMessage("SelectTrackToCopy"), JmriJOptionPane.INFORMATION_MESSAGE); 191 return; 192 } 193 Track fromTrack = (Track) trackBox.getSelectedItem(); 194 if (moveRollingStockCheckBox.isSelected() && fromTrack.getPickupRS() > 0) { 195 JmriJOptionPane.showMessageDialog(this, Bundle.getMessage("FoundRollingStockPickUp", 196 fromTrack.getPickupRS()), Bundle 197 .getMessage("TrainsServicingTrack", fromTrack.getName()), 198 JmriJOptionPane.WARNING_MESSAGE); 199 return; // failed 200 } 201 if (moveRollingStockCheckBox.isSelected() && fromTrack.getDropRS() > 0) { 202 JmriJOptionPane.showMessageDialog(this, Bundle.getMessage("FoundRollingStockDrop", 203 fromTrack.getDropRS()), Bundle 204 .getMessage("TrainsServicingTrack", fromTrack.getName()), 205 JmriJOptionPane.WARNING_MESSAGE); 206 return; // failed 207 } 208 // only copy tracks that are okay with the location 209 if (fromTrack.isStaging() ^ _destination.isStaging()) { 210 JmriJOptionPane.showMessageDialog(this, Bundle.getMessage("TrackTypeWrong", 211 fromTrack.getTrackType(), _destination.getName()), Bundle 212 .getMessage("CanNotCopy", fromTrack.getName()), JmriJOptionPane.ERROR_MESSAGE); 213 return; 214 } 215 Track toTrack = fromTrack.copyTrack(trackNameTextField.getText(), _destination); 216 if (moveRollingStockCheckBox.isSelected()) { 217 // move rolling stock 218 moveRollingStock(fromTrack, toTrack); 219 if (deleteTrackCheckBox.isSelected()) { 220 InstanceManager.getDefault(ScheduleManager.class).replaceTrack(fromTrack, toTrack); 221 fromTrack.getLocation().deleteTrack(fromTrack); 222 } 223 } 224 } 225 if (ae.getSource() == saveButton) { 226 log.debug("save track button activated"); 227 // save checkbox states 228 sameName = sameNameCheckBox.isSelected(); 229 moveRollingStock = moveRollingStockCheckBox.isSelected(); 230 deleteTrack = deleteTrackCheckBox.isSelected(); 231 // save location file 232 OperationsXml.save(); 233 } 234 } 235 236 @Override 237 protected void checkBoxActionPerformed(java.awt.event.ActionEvent ae) { 238 if (ae.getSource() == sameNameCheckBox) { 239 updateTrackName(); 240 } 241 if (ae.getSource() == moveRollingStockCheckBox) { 242 deleteTrackCheckBox.setEnabled(moveRollingStockCheckBox.isSelected()); 243 deleteTrackCheckBox.setSelected(false); 244 } 245 } 246 247 protected void updateComboBoxes() { 248 log.debug("update location combobox"); 249 InstanceManager.getDefault(LocationManager.class).updateComboBox(locationBox); 250 InstanceManager.getDefault(LocationManager.class).updateComboBox(destinationBox); 251 } 252 253 /** 254 * 255 * @return true if name entered OK and isn't too long 256 */ 257 protected boolean checkName() { 258 if (trackNameTextField.getText().trim().isEmpty()) { 259 JmriJOptionPane.showMessageDialog(this, Bundle.getMessage("MustEnterName"), Bundle 260 .getMessage("CanNotTrack", Bundle.getMessage("ButtonCopy")), JmriJOptionPane.ERROR_MESSAGE); 261 return false; 262 } 263 if (TrainCommon.splitString(trackNameTextField.getText()).length() > Control.max_len_string_track_name) { 264 JmriJOptionPane.showMessageDialog(this, Bundle.getMessage("TrackNameLengthMax", 265 Integer.toString(Control.max_len_string_track_name + 1)), Bundle 266 .getMessage("CanNotTrack", Bundle.getMessage("ButtonCopy")), JmriJOptionPane.ERROR_MESSAGE); 267 return false; 268 } 269 // check to see if track already exists 270 if (_destination == null) { 271 return false; 272 } 273 Track check = _destination.getTrackByName(trackNameTextField.getText(), null); 274 if (check != null) { 275 JmriJOptionPane.showMessageDialog(this, Bundle.getMessage("TrackAlreadyExists"), Bundle 276 .getMessage("CanNotTrack", Bundle.getMessage("ButtonCopy")), JmriJOptionPane.ERROR_MESSAGE); 277 return false; 278 } 279 return true; 280 } 281 282 protected void moveRollingStock(Track fromTrack, Track toTrack) { 283 moveRollingStock(fromTrack, toTrack, InstanceManager.getDefault(CarManager.class)); 284 moveRollingStock(fromTrack, toTrack, InstanceManager.getDefault(EngineManager.class)); 285 } 286 287 private void moveRollingStock(Track fromTrack, Track toTrack, RollingStockManager<? extends RollingStock> manager) { 288 for (RollingStock rs : manager.getByIdList()) { 289 if (rs.getTrack() == fromTrack) { 290 rs.setLocation(toTrack.getLocation(), toTrack, RollingStock.FORCE); 291 } 292 } 293 } 294 295 @Override 296 public void dispose() { 297 InstanceManager.getDefault(LocationManager.class).removePropertyChangeListener(this); 298 if (_destination != null) { 299 _destination.removePropertyChangeListener(this); 300 } 301 if (_location != null) { 302 _location.removePropertyChangeListener(this); 303 } 304 super.dispose(); 305 } 306 307 @Override 308 public void propertyChange(java.beans.PropertyChangeEvent e) { 309 log.debug("PropertyChange ({}) old ({}) new ({})", e.getPropertyName(), e.getOldValue(), e.getNewValue()); 310 if (e.getPropertyName().equals(LocationManager.LISTLENGTH_CHANGED_PROPERTY)) { 311 updateComboBoxes(); 312 } 313 if (e.getSource() == _location) { 314 updateTrackComboBox(); 315 } 316 if (e.getSource() == _destination && e.getPropertyName().equals(Location.DISPOSE_CHANGED_PROPERTY)) { 317 dispose(); 318 } 319 } 320 321 private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(TrackCopyFrame.class); 322}