001package jmri.jmrit.operations.routes.tools;
002
003import java.awt.*;
004import java.awt.event.ComponentListener;
005import java.beans.PropertyChangeEvent;
006import java.beans.PropertyChangeListener;
007import java.util.List;
008
009import javax.swing.*;
010
011import jmri.InstanceManager;
012import jmri.jmrit.display.Editor;
013import jmri.jmrit.display.EditorManager;
014import jmri.jmrit.operations.OperationsFrame;
015import jmri.jmrit.operations.routes.*;
016import jmri.jmrit.operations.setup.Control;
017import jmri.jmrit.operations.setup.Setup;
018import jmri.jmrit.operations.trains.TrainIcon;
019import jmri.util.swing.JmriJOptionPane;
020
021/**
022 * Frame for setting train icon coordinates for a location.
023 *
024 * @author Bob Jacobsen Copyright (C) 2001
025 * @author Daniel Boudreau Copyright (C) 2010
026 */
027public class SetTrainIconRouteFrame extends OperationsFrame implements PropertyChangeListener {
028
029    RouteManager routeManager = InstanceManager.getDefault(RouteManager.class);
030
031    // labels
032    JLabel textX = new JLabel("   X  ");
033    JLabel textY = new JLabel("   Y  ");
034
035    JLabel routeLocationName = new JLabel();
036
037    // text field
038    // check boxes
039    // major buttons
040    JButton previousButton = new JButton(Bundle.getMessage("Previous"));
041    JButton nextButton = new JButton(Bundle.getMessage("Next"));
042    JButton placeButton = new JButton(Bundle.getMessage("PlaceTestIcon"));
043    JButton applyButton = new JButton(Bundle.getMessage("ButtonApply"));
044    JButton saveButton = new JButton(Bundle.getMessage("ButtonSave"));
045
046    // combo boxes
047    // Spinners
048    JSpinner spinTrainIconX = new JSpinner(new SpinnerNumberModel(0, 0, 10000, 1));
049    JSpinner spinTrainIconY = new JSpinner(new SpinnerNumberModel(0, 0, 10000, 1));
050
051    Route _route;
052    RouteLocation _rl;
053    int _routeIndex = 0;
054    List<RouteLocation> _routeList;
055
056    // test train icon
057    TrainIcon _tIon;
058
059    public SetTrainIconRouteFrame(Route route) {
060        super(Bundle.getMessage("MenuSetTrainIcon"));
061
062        if (route == null) {
063            return;
064        }
065        _route = route;
066        _route.addPropertyChangeListener(this);
067
068        // general GUI config
069        getContentPane().setLayout(new BoxLayout(getContentPane(), BoxLayout.Y_AXIS));
070
071        // set tool tips
072        placeButton.setToolTipText(Bundle.getMessage("TipPlaceButton") + " " + Setup.getPanelName());
073        applyButton.setToolTipText(Bundle.getMessage("TipApplyButton"));
074        saveButton.setToolTipText(Bundle.getMessage("TipSaveButton"));
075
076        // Set up the panels
077        JPanel pRoute = new JPanel();
078        pRoute.setBorder(BorderFactory
079                .createTitledBorder(Bundle.getMessage("Route") + " " + _route.getName()));
080        pRoute.setLayout(new GridBagLayout());
081        addItem(pRoute, previousButton, 0, 0);
082        addItem(pRoute, routeLocationName, 1, 0);
083        addItem(pRoute, nextButton, 2, 0);
084
085        JPanel pSpin = new JPanel();
086        pSpin.setLayout(new GridBagLayout());
087        pSpin.setBorder(BorderFactory.createTitledBorder(Bundle.getMessage("TrainIcon")));
088        addItem(pSpin, textX, 0, 0);
089        addItem(pSpin, spinTrainIconX, 1, 0);
090        addItem(pSpin, textY, 2, 0);
091        addItem(pSpin, spinTrainIconY, 3, 0);
092
093        JPanel pControl = new JPanel();
094        pControl.setLayout(new GridBagLayout());
095        pControl.setBorder(BorderFactory.createTitledBorder(""));
096        addItem(pControl, placeButton, 0, 0);
097        addItem(pControl, applyButton, 1, 0);
098        addItem(pControl, saveButton, 2, 0);
099
100        getContentPane().add(pRoute);
101        getContentPane().add(pSpin);
102        getContentPane().add(pControl);
103
104        // add help menu to window
105        addHelpMenu("package.jmri.jmrit.operations.Operations_SetTrainIconCoordinates", true); // NOI18N
106
107        // setup buttons
108        addButtonAction(previousButton);
109        addButtonAction(nextButton);
110        addButtonAction(placeButton);
111        addButtonAction(applyButton);
112        addButtonAction(saveButton);
113
114        // start off with save button disabled
115        saveButton.setEnabled(false);
116
117        updateRoute();
118
119        // setup spinners
120        addSpinnerChangeListerner(spinTrainIconX);
121        addSpinnerChangeListerner(spinTrainIconY);
122
123        initMinimumSize(new Dimension(Control.panelWidth400, Control.panelHeight400));
124
125    }
126
127    int value = JmriJOptionPane.NO_OPTION;
128
129    @Override
130    public void buttonActionPerformed(java.awt.event.ActionEvent ae) {
131        if (ae.getSource() == previousButton) {
132            updateRouteLocation(BACK);
133        }
134        if (ae.getSource() == nextButton) {
135            updateRouteLocation(FORWARD);
136        }
137        if (ae.getSource() == placeButton) {
138            placeTestIcons();
139        }
140        if (ae.getSource() == applyButton) {
141            if (value != JmriJOptionPane.YES_OPTION) {
142                value = JmriJOptionPane.showConfirmDialog(this, Bundle
143                        .getMessage("UpdateTrainIconRoute", _route.getName()), Bundle
144                                .getMessage("DoYouWantThisRoute"),
145                        JmriJOptionPane.YES_NO_OPTION);
146            }
147            if (value == JmriJOptionPane.YES_OPTION) {
148                saveButton.setEnabled(true);
149            }
150            updateTrainIconCoordinates();
151        }
152        if (ae.getSource() == saveButton) {
153            InstanceManager.getDefault(RouteManagerXml.class).writeOperationsFile();
154            if (Setup.isCloseWindowOnSaveEnabled()) {
155                dispose();
156            }
157        }
158    }
159
160    @Override
161    public void spinnerChangeEvent(javax.swing.event.ChangeEvent ae) {
162        if (ae.getSource() == spinTrainIconX && _tIon != null) {
163            _tIon.setLocation((Integer) spinTrainIconX.getValue(), _tIon.getLocation().y);
164        }
165        if (ae.getSource() == spinTrainIconY && _tIon != null) {
166            _tIon.setLocation(_tIon.getLocation().x, (Integer) spinTrainIconY.getValue());
167        }
168    }
169
170    private void loadSpinners(RouteLocation rl) {
171        log.debug("Load spinners route location {}", rl.getName());
172        spinTrainIconX.setValue(rl.getTrainIconX());
173        spinTrainIconY.setValue(rl.getTrainIconY());
174    }
175
176    // place test markers on panel
177    private void placeTestIcons() {
178        Editor editor = InstanceManager.getDefault(EditorManager.class).getTargetFrame(Setup.getPanelName());
179        if (editor == null) {
180            JmriJOptionPane.showMessageDialog(this, Bundle.getMessage("LoadPanel",
181                    Setup.getPanelName()), Bundle.getMessage("PanelNotFound"),
182                    JmriJOptionPane.ERROR_MESSAGE);
183        } else {
184            if (_tIon != null) {
185                _tIon.remove();
186            }
187            // icon
188            _tIon = editor.addTrainIcon(_rl.getName());
189            _tIon.getToolTip().setText(_route.getName());
190            _tIon.getToolTip().setBackgroundColor(Color.white);
191            _tIon.setLocation(_rl.getTrainIconX(), _rl.getTrainIconY());
192            setTrainIconNameAndColor();
193            addIconListener(_tIon);
194        }
195    }
196
197    private void setTrainIconNameAndColor() {
198        if (_tIon == null) {
199            return;
200        }
201        _tIon.setText(_rl.getName());
202        // set color based on train direction at current location
203        if (_rl.getTrainDirection() == RouteLocation.NORTH) {
204            _tIon.setLocoColor(Setup.getTrainIconColorNorth());
205        }
206        if (_rl.getTrainDirection() == RouteLocation.SOUTH) {
207            _tIon.setLocoColor(Setup.getTrainIconColorSouth());
208        }
209        if (_rl.getTrainDirection() == RouteLocation.EAST) {
210            _tIon.setLocoColor(Setup.getTrainIconColorEast());
211        }
212        if (_rl.getTrainDirection() == RouteLocation.WEST) {
213            _tIon.setLocoColor(Setup.getTrainIconColorWest());
214        }
215    }
216
217    private void updateRoute() {
218        log.debug("Updating route");
219        _routeList = _route.getLocationsBySequenceList();
220        updateRouteLocation(NO_CHANGE);
221    }
222
223    private static final int FORWARD = 1;
224    private static final int BACK = -1;
225    private static final int NO_CHANGE = 0;
226
227    private void updateRouteLocation(int direction) {
228        if (direction == FORWARD) {
229            _routeIndex++;
230        }
231        if (direction == BACK) {
232            _routeIndex--;
233        }
234        // Confirm that index is in range
235        if (_routeIndex > _routeList.size() - 1) {
236            _routeIndex = _routeList.size() - 1;
237        }
238        if (_routeIndex < 0) {
239            _routeIndex = 0;
240        }
241
242        if (_rl != null) {
243            _rl.removePropertyChangeListener(this);
244        }
245        if (_routeList.size() > 0) {
246            _rl = _routeList.get(_routeIndex);
247        }
248        if (_rl != null) {
249            _rl.addPropertyChangeListener(this);
250            loadSpinners(_rl);
251            routeLocationName.setText(_rl.getName());
252        }
253        // disable or enable previous and next buttons
254        previousButton.setEnabled(_routeIndex != 0);
255        nextButton.setEnabled(_routeIndex != _routeList.size() - 1);
256
257        setTrainIconNameAndColor();
258    }
259
260    private void updateTrainIconCoordinates() {
261        if (_rl != null) {
262            _rl.removePropertyChangeListener(this);
263            _rl.setTrainIconX((Integer) spinTrainIconX.getValue());
264            _rl.setTrainIconY((Integer) spinTrainIconY.getValue());
265            _rl.addPropertyChangeListener(this);
266        }
267    }
268
269    private void addIconListener(TrainIcon tI) {
270        tI.addComponentListener(new ComponentListener() {
271            @Override
272            public void componentHidden(java.awt.event.ComponentEvent e) {
273            }
274
275            @Override
276            public void componentShown(java.awt.event.ComponentEvent e) {
277            }
278
279            @Override
280            public void componentMoved(java.awt.event.ComponentEvent e) {
281                trainIconMoved(e);
282            }
283
284            @Override
285            public void componentResized(java.awt.event.ComponentEvent e) {
286            }
287        });
288    }
289
290    protected void trainIconMoved(java.awt.event.ComponentEvent ae) {
291        if (ae.getSource() == _tIon) {
292            log.debug("train icon X: {} Y: {}", _tIon.getLocation().x, _tIon.getLocation().y);
293            spinTrainIconX.setValue(_tIon.getLocation().x);
294            spinTrainIconY.setValue(_tIon.getLocation().y);
295        }
296    }
297
298    private void removeIcons() {
299        if (_tIon != null) {
300            _tIon.remove();
301        }
302    }
303
304    @Override
305    public void dispose() {
306        removeIcons();
307        if (_route != null) {
308            _route.removePropertyChangeListener(this);
309        }
310        if (_rl != null) {
311            _rl.removePropertyChangeListener(this);
312        }
313        super.dispose();
314    }
315
316    @Override
317    public void propertyChange(PropertyChangeEvent e) {
318        log.debug("Property change ({}) old: ({}) new: ({})", e.getPropertyName(), e.getOldValue(),
319                e.getNewValue());
320        if (e.getSource().equals(_route)) {
321            updateRoute();
322        }
323        if (e.getSource().equals(_rl)) {
324            updateRouteLocation(NO_CHANGE);
325        }
326    }
327
328    private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(SetTrainIconRouteFrame.class);
329}