001package jmri.jmrit.operations.routes.tools;
002
003import java.awt.*;
004import java.awt.event.ComponentListener;
005
006import javax.swing.*;
007
008import jmri.InstanceManager;
009import jmri.jmrit.display.Editor;
010import jmri.jmrit.display.EditorManager;
011import jmri.jmrit.operations.OperationsFrame;
012import jmri.jmrit.operations.OperationsXml;
013import jmri.jmrit.operations.locations.Location;
014import jmri.jmrit.operations.locations.LocationManager;
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 SetTrainIconPositionFrame extends OperationsFrame {
028
029    RouteManager routeManager = InstanceManager.getDefault(RouteManager.class);
030
031    // labels
032    JLabel textEastX = new JLabel("   X  ");
033    JLabel textEastY = new JLabel("   Y  ");
034    JLabel textWestX = new JLabel("   X  ");
035    JLabel textWestY = new JLabel("   Y  ");
036    JLabel textNorthX = new JLabel("   X  ");
037    JLabel textNorthY = new JLabel("   Y  ");
038    JLabel textSouthX = new JLabel("   X  ");
039    JLabel textSouthY = new JLabel("   Y  ");
040
041    JLabel textRangeX = new JLabel("   X +/-");
042    JLabel textRangeY = new JLabel("   Y +/-");
043
044    // major buttons
045    JButton placeButton = new JButton(Bundle.getMessage("PlaceTestIcon"));
046    JButton applyButton = new JButton(Bundle.getMessage("UpdateRoutes"));
047    JButton saveButton = new JButton(Bundle.getMessage("ButtonSave"));
048
049    // combo boxes
050    JComboBox<Location> locationBox = InstanceManager.getDefault(LocationManager.class).getComboBox();
051
052    // Spinners
053    JSpinner spinTrainIconEastX = new JSpinner(new SpinnerNumberModel(0, 0, 10000, 1));
054    JSpinner spinTrainIconEastY = new JSpinner(new SpinnerNumberModel(0, 0, 10000, 1));
055    JSpinner spinTrainIconWestX = new JSpinner(new SpinnerNumberModel(0, 0, 10000, 1));
056    JSpinner spinTrainIconWestY = new JSpinner(new SpinnerNumberModel(0, 0, 10000, 1));
057    JSpinner spinTrainIconNorthX = new JSpinner(new SpinnerNumberModel(0, 0, 10000, 1));
058    JSpinner spinTrainIconNorthY = new JSpinner(new SpinnerNumberModel(0, 0, 10000, 1));
059    JSpinner spinTrainIconSouthX = new JSpinner(new SpinnerNumberModel(0, 0, 10000, 1));
060    JSpinner spinTrainIconSouthY = new JSpinner(new SpinnerNumberModel(0, 0, 10000, 1));
061
062    // detection range
063    JSpinner spinTrainIconRangeX = new JSpinner(new SpinnerNumberModel(Location.RANGE_DEFAULT, 0, 1000, 1));
064    JSpinner spinTrainIconRangeY = new JSpinner(new SpinnerNumberModel(Location.RANGE_DEFAULT, 0, 1000, 1));
065
066    // Four test train icons
067    TrainIcon _tIonEast;
068    TrainIcon _tIonWest;
069    TrainIcon _tIonNorth;
070    TrainIcon _tIonSouth;
071
072    public SetTrainIconPositionFrame() {
073        super(Bundle.getMessage("MenuSetTrainIcon"));
074
075        // general GUI config
076        getContentPane().setLayout(new BoxLayout(getContentPane(), BoxLayout.Y_AXIS));
077
078        // set tool tips
079        placeButton.setToolTipText(Bundle.getMessage("TipPlaceButton") + " \"" + Setup.getPanelName() + "\""); // NOI18N
080        applyButton.setToolTipText(Bundle.getMessage("TipApplyAllButton"));
081        saveButton.setToolTipText(Bundle.getMessage("TipSaveButton"));
082
083        // Set up the panels
084        JPanel pLocation = new JPanel();
085        pLocation.setBorder(BorderFactory.createTitledBorder(Bundle.getMessage("Location")));
086        pLocation.add(locationBox);
087
088        JPanel pEast = new JPanel();
089        pEast.setLayout(new GridBagLayout());
090        pEast.setBorder(BorderFactory.createTitledBorder(Bundle.getMessage("EastTrainIcon")));
091        addItem(pEast, textEastX, 0, 0);
092        addItem(pEast, spinTrainIconEastX, 1, 0);
093        addItem(pEast, textEastY, 2, 0);
094        addItem(pEast, spinTrainIconEastY, 3, 0);
095
096        JPanel pWest = new JPanel();
097        pWest.setLayout(new GridBagLayout());
098        pWest.setBorder(BorderFactory.createTitledBorder(Bundle.getMessage("WestTrainIcon")));
099        addItem(pWest, textWestX, 0, 0);
100        addItem(pWest, spinTrainIconWestX, 1, 0);
101        addItem(pWest, textWestY, 2, 0);
102        addItem(pWest, spinTrainIconWestY, 3, 0);
103
104        JPanel pNorth = new JPanel();
105        pNorth.setLayout(new GridBagLayout());
106        pNorth.setBorder(BorderFactory.createTitledBorder(Bundle.getMessage("NorthTrainIcon")));
107        addItem(pNorth, textNorthX, 0, 0);
108        addItem(pNorth, spinTrainIconNorthX, 1, 0);
109        addItem(pNorth, textNorthY, 2, 0);
110        addItem(pNorth, spinTrainIconNorthY, 3, 0);
111
112        JPanel pSouth = new JPanel();
113        pSouth.setLayout(new GridBagLayout());
114        pSouth.setBorder(BorderFactory.createTitledBorder(Bundle.getMessage("SouthTrainIcon")));
115        addItem(pSouth, textSouthX, 0, 0);
116        addItem(pSouth, spinTrainIconSouthX, 1, 0);
117        addItem(pSouth, textSouthY, 2, 0);
118        addItem(pSouth, spinTrainIconSouthY, 3, 0);
119
120        JPanel pRange = new JPanel();
121        pRange.setLayout(new GridBagLayout());
122        pRange.setBorder(BorderFactory.createTitledBorder(Bundle.getMessage("RangeTrainIcon")));
123        addItem(pRange, textRangeX, 0, 0);
124        addItem(pRange, spinTrainIconRangeX, 1, 0);
125        addItem(pRange, textRangeY, 2, 0);
126        addItem(pRange, spinTrainIconRangeY, 3, 0);
127
128        JPanel pControl = new JPanel();
129        pControl.setLayout(new GridBagLayout());
130        pControl.setBorder(BorderFactory.createTitledBorder(""));
131        addItem(pControl, placeButton, 0, 0);
132        addItem(pControl, applyButton, 1, 0);
133        addItem(pControl, saveButton, 2, 0);
134
135        // only show valid directions
136        pEast.setVisible((Setup.getTrainDirection() & Setup.EAST) == Setup.EAST);
137        pWest.setVisible((Setup.getTrainDirection() & Setup.WEST) == Setup.WEST);
138        pNorth.setVisible((Setup.getTrainDirection() & Setup.NORTH) == Setup.NORTH);
139        pSouth.setVisible((Setup.getTrainDirection() & Setup.SOUTH) == Setup.SOUTH);
140
141        getContentPane().add(pLocation);
142        getContentPane().add(pNorth);
143        getContentPane().add(pSouth);
144        getContentPane().add(pEast);
145        getContentPane().add(pWest);
146        getContentPane().add(pRange);
147        getContentPane().add(pControl);
148
149        // add help menu to window
150        addHelpMenu("package.jmri.jmrit.operations.Operations_SetTrainIconCoordinates", true); // NOI18N
151
152        // setup buttons
153        addButtonAction(placeButton);
154        addButtonAction(applyButton);
155        addButtonAction(saveButton);
156
157        // setup combo box
158        addComboBoxAction(locationBox);
159
160        // setup spinners
161        spinnersEnable(false);
162        addSpinnerChangeListerner(spinTrainIconEastX);
163        addSpinnerChangeListerner(spinTrainIconEastY);
164        addSpinnerChangeListerner(spinTrainIconWestX);
165        addSpinnerChangeListerner(spinTrainIconWestY);
166        addSpinnerChangeListerner(spinTrainIconNorthX);
167        addSpinnerChangeListerner(spinTrainIconNorthY);
168        addSpinnerChangeListerner(spinTrainIconSouthX);
169        addSpinnerChangeListerner(spinTrainIconSouthY);
170
171        addSpinnerChangeListerner(spinTrainIconRangeX);
172        addSpinnerChangeListerner(spinTrainIconRangeY);
173
174        initMinimumSize(new Dimension(Control.panelWidth500, Control.panelHeight400));
175
176    }
177
178    @Override
179    public void buttonActionPerformed(java.awt.event.ActionEvent ae) {
180        // check to see if a location has been selected
181        if (locationBox.getSelectedItem() == null) {
182            JmriJOptionPane.showMessageDialog(this, Bundle.getMessage("SelectLocationToEdit"),
183                    Bundle.getMessage("NoLocationSelected"), JmriJOptionPane.ERROR_MESSAGE);
184            return;
185        }
186        Location location = (Location) locationBox.getSelectedItem();
187        if (location == null) {
188            return;
189        }
190        if (ae.getSource() == placeButton) {
191            placeTestIcons();
192        }
193        if (ae.getSource() == applyButton) {
194            // update all routes?
195            int value = JmriJOptionPane.showConfirmDialog(this, Bundle.getMessage("DoYouWantAllRoutes"),
196                    Bundle.getMessage("UpdateTrainIcon", location.getName()),
197                    JmriJOptionPane.YES_NO_OPTION);
198            if (value == JmriJOptionPane.YES_OPTION) {
199                saveSpinnerValues(location);
200                updateTrainIconCoordinates(location);
201            }
202        }
203        if (ae.getSource() == saveButton) {
204            int value = JmriJOptionPane.showConfirmDialog(this, Bundle.getMessage("UpdateDefaults"),
205                    Bundle.getMessage("UpdateTrainIcon", location.getName()),
206                    JmriJOptionPane.YES_NO_OPTION);
207            if (value == JmriJOptionPane.YES_OPTION) {
208                saveSpinnerValues(location);
209            }
210            OperationsXml.save(); // save location and route files
211            if (Setup.isCloseWindowOnSaveEnabled()) {
212                dispose();
213            }
214        }
215    }
216
217    @Override
218    public void comboBoxActionPerformed(java.awt.event.ActionEvent ae) {
219        if (locationBox.getSelectedItem() == null) {
220            resetSpinners();
221            removeIcons();
222        } else {
223            loadSpinners((Location) locationBox.getSelectedItem());
224        }
225    }
226
227    @Override
228    public void spinnerChangeEvent(javax.swing.event.ChangeEvent ae) {
229        if (ae.getSource() == spinTrainIconEastX && _tIonEast != null) {
230            _tIonEast.setLocation((Integer) spinTrainIconEastX.getValue(), _tIonEast.getLocation().y);
231        }
232        if (ae.getSource() == spinTrainIconEastY && _tIonEast != null) {
233            _tIonEast.setLocation(_tIonEast.getLocation().x, (Integer) spinTrainIconEastY.getValue());
234        }
235        if (ae.getSource() == spinTrainIconWestX && _tIonWest != null) {
236            _tIonWest.setLocation((Integer) spinTrainIconWestX.getValue(), _tIonWest.getLocation().y);
237        }
238        if (ae.getSource() == spinTrainIconWestY && _tIonWest != null) {
239            _tIonWest.setLocation(_tIonWest.getLocation().x, (Integer) spinTrainIconWestY.getValue());
240        }
241        if (ae.getSource() == spinTrainIconNorthX && _tIonNorth != null) {
242            _tIonNorth.setLocation((Integer) spinTrainIconNorthX.getValue(), _tIonNorth.getLocation().y);
243        }
244        if (ae.getSource() == spinTrainIconNorthY && _tIonNorth != null) {
245            _tIonNorth.setLocation(_tIonNorth.getLocation().x, (Integer) spinTrainIconNorthY.getValue());
246        }
247        if (ae.getSource() == spinTrainIconSouthX && _tIonSouth != null) {
248            _tIonSouth.setLocation((Integer) spinTrainIconSouthX.getValue(), _tIonSouth.getLocation().y);
249        }
250        if (ae.getSource() == spinTrainIconSouthY && _tIonSouth != null) {
251            _tIonSouth.setLocation(_tIonSouth.getLocation().x, (Integer) spinTrainIconSouthY.getValue());
252        }
253    }
254
255    private void resetSpinners() {
256        spinnersEnable(false);
257        spinTrainIconEastX.setValue(0);
258        spinTrainIconEastY.setValue(0);
259        spinTrainIconWestX.setValue(0);
260        spinTrainIconWestY.setValue(0);
261        spinTrainIconNorthX.setValue(0);
262        spinTrainIconNorthY.setValue(0);
263        spinTrainIconSouthX.setValue(0);
264        spinTrainIconSouthY.setValue(0);
265    }
266
267    private void loadSpinners(Location location) {
268        log.debug("Load spinners location {}", location.getName());
269        spinnersEnable(true);
270        spinTrainIconEastX.setValue(location.getTrainIconEast().x);
271        spinTrainIconEastY.setValue(location.getTrainIconEast().y);
272        spinTrainIconWestX.setValue(location.getTrainIconWest().x);
273        spinTrainIconWestY.setValue(location.getTrainIconWest().y);
274        spinTrainIconNorthX.setValue(location.getTrainIconNorth().x);
275        spinTrainIconNorthY.setValue(location.getTrainIconNorth().y);
276        spinTrainIconSouthX.setValue(location.getTrainIconSouth().x);
277        spinTrainIconSouthY.setValue(location.getTrainIconSouth().y);
278
279        spinTrainIconRangeX.setValue(location.getTrainIconRangeX());
280        spinTrainIconRangeY.setValue(location.getTrainIconRangeY());
281    }
282
283    private void spinnersEnable(boolean enable) {
284        spinTrainIconEastX.setEnabled(enable);
285        spinTrainIconEastY.setEnabled(enable);
286        spinTrainIconWestX.setEnabled(enable);
287        spinTrainIconWestY.setEnabled(enable);
288        spinTrainIconNorthX.setEnabled(enable);
289        spinTrainIconNorthY.setEnabled(enable);
290        spinTrainIconSouthX.setEnabled(enable);
291        spinTrainIconSouthY.setEnabled(enable);
292
293        spinTrainIconRangeX.setEnabled(enable);
294        spinTrainIconRangeY.setEnabled(enable);
295    }
296
297    private void saveSpinnerValues(Location location) {
298        log.debug("Save train icons coordinates for location {}", location.getName());
299        location.setTrainIconEast(
300                new Point((Integer) spinTrainIconEastX.getValue(), (Integer) spinTrainIconEastY.getValue()));
301        location.setTrainIconWest(
302                new Point((Integer) spinTrainIconWestX.getValue(), (Integer) spinTrainIconWestY.getValue()));
303        location.setTrainIconNorth(
304                new Point((Integer) spinTrainIconNorthX.getValue(), (Integer) spinTrainIconNorthY.getValue()));
305        location.setTrainIconSouth(
306                new Point((Integer) spinTrainIconSouthX.getValue(), (Integer) spinTrainIconSouthY.getValue()));
307
308        location.setTrainIconRangeX((Integer) spinTrainIconRangeX.getValue());
309        location.setTrainIconRangeY((Integer) spinTrainIconRangeY.getValue());
310    }
311
312    // place test markers on panel
313    private void placeTestIcons() {
314        removeIcons();
315        if (locationBox.getSelectedItem() == null) {
316            return;
317        }
318        Editor editor = InstanceManager.getDefault(EditorManager.class).getTargetFrame(Setup.getPanelName());
319        if (editor == null) {
320            JmriJOptionPane.showMessageDialog(this,
321                    Bundle.getMessage("LoadPanel", Setup.getPanelName()),
322                    Bundle.getMessage("PanelNotFound"), JmriJOptionPane.ERROR_MESSAGE);
323            return;
324        }
325        Location location = (Location) locationBox.getSelectedItem();
326        if (location != null) {
327            // East icon
328            if ((Setup.getTrainDirection() & Setup.EAST) == Setup.EAST) {
329                _tIonEast = editor.addTrainIcon(Bundle.getMessage("East"));
330                _tIonEast.getToolTip().setText(location.getName());
331                _tIonEast.getToolTip().setBackgroundColor(Color.white);
332                _tIonEast.setLocoColor(Setup.getTrainIconColorEast());
333                _tIonEast.setLocation((Integer) spinTrainIconEastX.getValue(), (Integer) spinTrainIconEastY.getValue());
334                addIconListener(_tIonEast);
335            }
336            // West icon
337            if ((Setup.getTrainDirection() & Setup.WEST) == Setup.WEST) {
338                _tIonWest = editor.addTrainIcon(Bundle.getMessage("West"));
339                _tIonWest.getToolTip().setText(location.getName());
340                _tIonWest.getToolTip().setBackgroundColor(Color.white);
341                _tIonWest.setLocoColor(Setup.getTrainIconColorWest());
342                _tIonWest.setLocation((Integer) spinTrainIconWestX.getValue(), (Integer) spinTrainIconWestY.getValue());
343                addIconListener(_tIonWest);
344            }
345            // North icon
346            if ((Setup.getTrainDirection() & Setup.NORTH) == Setup.NORTH) {
347                _tIonNorth = editor.addTrainIcon(Bundle.getMessage("North"));
348                _tIonNorth.getToolTip().setText(location.getName());
349                _tIonNorth.getToolTip().setBackgroundColor(Color.white);
350                _tIonNorth.setLocoColor(Setup.getTrainIconColorNorth());
351                _tIonNorth.setLocation((Integer) spinTrainIconNorthX.getValue(),
352                        (Integer) spinTrainIconNorthY.getValue());
353                addIconListener(_tIonNorth);
354            }
355            // South icon
356            if ((Setup.getTrainDirection() & Setup.SOUTH) == Setup.SOUTH) {
357                _tIonSouth = editor.addTrainIcon(Bundle.getMessage("South"));
358                _tIonSouth.getToolTip().setText(location.getName());
359                _tIonSouth.getToolTip().setBackgroundColor(Color.white);
360                _tIonSouth.setLocoColor(Setup.getTrainIconColorSouth());
361                _tIonSouth.setLocation((Integer) spinTrainIconSouthX.getValue(),
362                        (Integer) spinTrainIconSouthY.getValue());
363                addIconListener(_tIonSouth);
364            }
365        }
366    }
367
368    public void updateTrainIconCoordinates(Location location) {
369        for (Route route : InstanceManager.getDefault(RouteManager.class).getRoutesByIdList()) {
370            for (RouteLocation rl : route.getLocationsBySequenceList()) {
371                if (rl.getName().equals(location.getName())) {
372                    log.debug("Updating train icon for route location {} in route {}", rl.getName(), route.getName());
373                    rl.setTrainIconCoordinates();
374                }
375            }
376        }
377    }
378
379    private void removeIcons() {
380        if (_tIonEast != null) {
381            _tIonEast.remove();
382        }
383        if (_tIonWest != null) {
384            _tIonWest.remove();
385        }
386        if (_tIonNorth != null) {
387            _tIonNorth.remove();
388        }
389        if (_tIonSouth != null) {
390            _tIonSouth.remove();
391        }
392    }
393
394    private void addIconListener(TrainIcon tI) {
395        tI.addComponentListener(new ComponentListener() {
396            @Override
397            public void componentHidden(java.awt.event.ComponentEvent e) {
398            }
399
400            @Override
401            public void componentShown(java.awt.event.ComponentEvent e) {
402            }
403
404            @Override
405            public void componentMoved(java.awt.event.ComponentEvent e) {
406                trainIconMoved(e);
407            }
408
409            @Override
410            public void componentResized(java.awt.event.ComponentEvent e) {
411            }
412        });
413    }
414
415    protected void trainIconMoved(java.awt.event.ComponentEvent ae) {
416        if (ae.getSource() == _tIonEast) {
417            log.debug("East train icon X: {} Y: {}", _tIonEast.getLocation().x, _tIonEast.getLocation().y);
418            spinTrainIconEastX.setValue(_tIonEast.getLocation().x);
419            spinTrainIconEastY.setValue(_tIonEast.getLocation().y);
420        }
421        if (ae.getSource() == _tIonWest) {
422            log.debug("West train icon X: {} Y: {}", _tIonWest.getLocation().x, _tIonWest.getLocation().y);
423            spinTrainIconWestX.setValue(_tIonWest.getLocation().x);
424            spinTrainIconWestY.setValue(_tIonWest.getLocation().y);
425        }
426        if (ae.getSource() == _tIonNorth) {
427            log.debug("North train icon X: {} Y: {}", _tIonNorth.getLocation().x, _tIonNorth.getLocation().y);
428            spinTrainIconNorthX.setValue(_tIonNorth.getLocation().x);
429            spinTrainIconNorthY.setValue(_tIonNorth.getLocation().y);
430        }
431        if (ae.getSource() == _tIonSouth) {
432            log.debug("South train icon X: {} Y: {}", _tIonSouth.getLocation().x, _tIonSouth.getLocation().y);
433            spinTrainIconSouthX.setValue(_tIonSouth.getLocation().x);
434            spinTrainIconSouthY.setValue(_tIonSouth.getLocation().y);
435        }
436    }
437
438    @Override
439    public void dispose() {
440        removeIcons();
441        super.dispose();
442    }
443
444    private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(SetTrainIconPositionFrame.class);
445}