001package jmri.jmrit.operations.locations.tools;
002
003import java.awt.Dimension;
004import java.awt.GridBagLayout;
005import java.text.MessageFormat;
006
007import javax.swing.*;
008
009import org.slf4j.Logger;
010import org.slf4j.LoggerFactory;
011
012import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
013import jmri.InstanceManager;
014import jmri.jmrit.operations.OperationsFrame;
015import jmri.jmrit.operations.OperationsXml;
016import jmri.jmrit.operations.locations.Location;
017import jmri.jmrit.operations.locations.LocationManager;
018import jmri.jmrit.operations.locations.Track;
019import jmri.jmrit.operations.rollingstock.RollingStock;
020import jmri.jmrit.operations.rollingstock.RollingStockManager;
021import jmri.jmrit.operations.rollingstock.cars.CarManager;
022import jmri.jmrit.operations.rollingstock.engines.EngineManager;
023import jmri.jmrit.operations.setup.Control;
024import jmri.jmrit.operations.trains.TrainCommon;
025
026/**
027 * Frame for copying a location for operations.
028 *
029 * @author Bob Jacobsen Copyright (C) 2001
030 * @author Daniel Boudreau Copyright (C) 2014
031 */
032public class LocationCopyFrame extends OperationsFrame implements java.beans.PropertyChangeListener {
033
034    LocationManager locationManager = InstanceManager.getDefault(LocationManager.class);
035
036    // text field
037    JTextField loctionNameTextField = new javax.swing.JTextField(Control.max_len_string_location_name);
038
039    // major buttons
040    JButton copyButton = new javax.swing.JButton(Bundle.getMessage("ButtonCopy"));
041    JButton saveButton = new javax.swing.JButton(Bundle.getMessage("ButtonSave"));
042
043    // combo boxes
044    JComboBox<Location> locationBox = locationManager.getComboBox();
045
046    // checkboxes
047    JCheckBox moveRollingStockCheckBox = new JCheckBox(Bundle.getMessage("MoveRollingStock"));
048    JCheckBox deleteTrackCheckBox = new JCheckBox(Bundle.getMessage("DeleteCopiedTrack"));
049
050    // remember state of checkboxes during a session
051    static boolean moveRollingStock = false;
052    static boolean deleteTrack = false;
053
054    public LocationCopyFrame() {
055
056        // general GUI config
057        getContentPane().setLayout(new BoxLayout(getContentPane(), BoxLayout.Y_AXIS));
058
059        // Set up the panels
060        // Layout the panel by rows
061        // row 1
062        JPanel pName = new JPanel();
063        pName.setLayout(new GridBagLayout());
064        pName.setBorder(BorderFactory.createTitledBorder(Bundle.getMessage("LocationName")));
065        addItem(pName, loctionNameTextField, 0, 0);
066
067        // row 2
068        JPanel pCopy = new JPanel();
069        pCopy.setLayout(new GridBagLayout());
070        pCopy.setBorder(BorderFactory.createTitledBorder(Bundle.getMessage("SelectLocationToCopy")));
071        addItem(pCopy, locationBox, 0, 0);
072
073        // row 3
074        JPanel pOptions = new JPanel();
075        pOptions.setLayout(new GridBagLayout());
076        pOptions.setBorder(BorderFactory.createTitledBorder(Bundle.getMessage("Options")));
077        addItemLeft(pOptions, moveRollingStockCheckBox, 0, 1);
078        addItemLeft(pOptions, deleteTrackCheckBox, 0, 2);
079
080        // row 4
081        JPanel pButton = new JPanel();
082        pButton.setLayout(new GridBagLayout());
083        addItem(pButton, copyButton, 0, 0);
084        addItem(pButton, saveButton, 1, 0);
085
086        getContentPane().add(pName);
087        getContentPane().add(pCopy);
088        getContentPane().add(pOptions);
089        getContentPane().add(pButton);
090
091        // set the checkbox states
092        moveRollingStockCheckBox.setSelected(moveRollingStock);
093        deleteTrackCheckBox.setSelected(deleteTrack);
094        deleteTrackCheckBox.setEnabled(moveRollingStockCheckBox.isSelected());
095
096        // get notified if combo box gets modified
097        locationManager.addPropertyChangeListener(this);
098
099        // add help menu to window
100        addHelpMenu("package.jmri.jmrit.operations.Operations_CopyLocation", true); // NOI18N
101
102        pack();
103        setMinimumSize(new Dimension(Control.panelWidth400, Control.panelHeight400));
104
105        // setup buttons
106        addButtonAction(copyButton);
107        addButtonAction(saveButton);
108
109        addCheckBoxAction(moveRollingStockCheckBox);
110
111        setTitle(Bundle.getMessage("MenuItemCopyLocation"));
112    }
113
114    @Override
115    @SuppressFBWarnings(value = "ST_WRITE_TO_STATIC_FROM_INSTANCE_METHOD", justification = "GUI ease of use")
116    protected void buttonActionPerformed(java.awt.event.ActionEvent ae) {
117        if (ae.getSource() == copyButton) {
118            log.debug("copy location button activated");
119            if (!checkName()) {
120                return;
121            }
122
123            if (locationBox.getSelectedItem() == null) {
124                JOptionPane.showMessageDialog(this, Bundle.getMessage("SelectLocationToCopy"), MessageFormat.format(Bundle
125                        .getMessage("CanNotLocation"), new Object[]{Bundle.getMessage("ButtonCopy")}), JOptionPane.ERROR_MESSAGE);
126                return;
127            }
128
129            Location location = (Location) locationBox.getSelectedItem();
130            // check to see if there are cars scheduled for pickup or set out
131            if (moveRollingStockCheckBox.isSelected()) {
132                for (Track track : location.getTracksList()) {
133                    if (track.getPickupRS() > 0) {
134                        JOptionPane.showMessageDialog(this, MessageFormat.format(Bundle
135                                .getMessage("FoundRollingStockPickUp"), new Object[]{track.getPickupRS()}),
136                                MessageFormat.format(Bundle.getMessage("TrainsServicingTrack"), new Object[]{track
137                                    .getName()}), JOptionPane.WARNING_MESSAGE);
138                        return; // can't move rolling stock, some are scheduled for a pick up
139                    }
140                    if (track.getDropRS() > 0) {
141                        JOptionPane.showMessageDialog(this, MessageFormat.format(Bundle
142                                .getMessage("FoundRollingStockDrop"), new Object[]{track.getDropRS()}),
143                                MessageFormat.format(Bundle.getMessage("TrainsServicingTrack"), new Object[]{track
144                                    .getName()}), JOptionPane.WARNING_MESSAGE);
145                        return; // can't move rolling stock, some are scheduled for drops
146                    }
147                }
148            }
149            // now copy all of the tracks
150            Location newLocation = locationManager.newLocation(loctionNameTextField.getText());
151            location.copyLocation(newLocation);
152
153            // does the user want the cars to also move to the new tracks?
154            if (moveRollingStockCheckBox.isSelected()) {
155                for (Track track : location.getTracksList()) {
156                    moveRollingStock(track, newLocation.getTrackByName(track.getName(), null));
157                    if (deleteTrackCheckBox.isSelected()) {
158                        location.deleteTrack(track);
159                    }
160                }
161            }
162        }
163        if (ae.getSource() == saveButton) {
164            log.debug("save track button activated");
165            // save checkbox states
166            moveRollingStock = moveRollingStockCheckBox.isSelected();
167            deleteTrack = deleteTrackCheckBox.isSelected();
168            // save location file
169            OperationsXml.save();
170        }
171    }
172
173    @Override
174    protected void checkBoxActionPerformed(java.awt.event.ActionEvent ae) {
175        if (ae.getSource() == moveRollingStockCheckBox) {
176            deleteTrackCheckBox.setEnabled(moveRollingStockCheckBox.isSelected());
177            deleteTrackCheckBox.setSelected(false);
178        }
179    }
180
181    protected void updateComboBoxes() {
182        log.debug("update location combobox");
183        Object item = locationBox.getSelectedItem(); // remember which object was selected
184        locationManager.updateComboBox(locationBox);
185        locationBox.setSelectedItem(item);
186    }
187
188    /**
189     *
190     * @return true if name entered OK and isn't too long
191     */
192    protected boolean checkName() {
193        if (loctionNameTextField.getText().trim().isEmpty()) {
194            JOptionPane.showMessageDialog(this, Bundle.getMessage("MustEnterName"), MessageFormat.format(Bundle
195                    .getMessage("CanNotLocation"), new Object[]{Bundle.getMessage("ButtonCopy")}), JOptionPane.ERROR_MESSAGE);
196            return false;
197        }
198        if (TrainCommon.splitString(loctionNameTextField.getText()).length() > Control.max_len_string_location_name) {
199            JOptionPane.showMessageDialog(this, MessageFormat.format(Bundle.getMessage("LocationNameLengthMax"),
200                    new Object[]{Integer.toString(Control.max_len_string_location_name + 1)}), MessageFormat.format(Bundle
201                            .getMessage("CanNotLocation"), new Object[]{Bundle.getMessage("ButtonCopy")}), JOptionPane.ERROR_MESSAGE);
202            return false;
203        }
204        Location check = locationManager.getLocationByName(loctionNameTextField.getText());
205        if (check != null) {
206            JOptionPane.showMessageDialog(this, Bundle.getMessage("LocationAlreadyExists"), MessageFormat.format(Bundle
207                    .getMessage("CanNotLocation"), new Object[]{Bundle.getMessage("ButtonCopy")}), JOptionPane.ERROR_MESSAGE);
208            return false;
209        }
210        return true;
211    }
212
213    protected void moveRollingStock(Track fromTrack, Track toTrack) {
214        moveRollingStock(fromTrack, toTrack, InstanceManager.getDefault(CarManager.class));
215        moveRollingStock(fromTrack, toTrack, InstanceManager.getDefault(EngineManager.class));
216    }
217
218    private void moveRollingStock(Track fromTrack, Track toTrack, RollingStockManager<? extends RollingStock> manager) {
219        for (RollingStock rs : manager.getByIdList()) {
220            if (rs.getTrack() == fromTrack) {
221                rs.setLocation(toTrack.getLocation(), toTrack, RollingStock.FORCE);
222            }
223        }
224    }
225
226    @Override
227    public void dispose() {
228        locationManager.removePropertyChangeListener(this);
229        super.dispose();
230    }
231
232    @Override
233    public void propertyChange(java.beans.PropertyChangeEvent e) {
234        log.debug("PropertyChange ({}) new: ({})", e.getPropertyName(), e.getNewValue());
235        if (e.getPropertyName().equals(LocationManager.LISTLENGTH_CHANGED_PROPERTY)) {
236            updateComboBoxes();
237        }
238    }
239
240    private final static Logger log = LoggerFactory.getLogger(LocationCopyFrame.class);
241}