001package jmri.jmrit.beantable;
002
003import java.awt.Frame;
004import java.awt.GridBagLayout;
005import java.awt.event.ActionEvent;
006import java.text.MessageFormat;
007import java.util.*;
008
009import javax.swing.*;
010import javax.swing.event.ChangeEvent;
011
012import jmri.*;
013import jmri.jmrit.operations.OperationsFrame;
014import jmri.jmrit.operations.OperationsPanel;
015import jmri.util.PhysicalLocation;
016import jmri.util.PhysicalLocationPanel;
017import jmri.util.swing.JmriJOptionPane;
018
019/**
020 * Swing action to create a SetPhysicalLocation dialog.
021 *
022 * @author Bob Jacobsen Copyright (C) 2001
023 * @author Daniel Boudreau Copyright (C) 2010
024 * @author Mark Underwood Copyright (C) 2011
025 */
026public class SetPhysicalLocationAction extends AbstractAction {
027
028    Reporter _reporter;
029
030    static ResourceBundle rb = ResourceBundle.getBundle("jmri.jmrit.beantable.JmritBeantablePhysicalLocationBundle");
031
032    /**
033     * Constructor.
034     *
035     * @param s title of the action
036     * @param reporter {@link Reporter} to use
037     */
038    public SetPhysicalLocationAction(String s, Reporter reporter) {
039        super(s);
040        _reporter = reporter;
041    }
042
043    SetPhysicalLocationFrame f = null;
044
045    /**
046     * Action method.
047     *
048     * @param e the associated {@link ActionEvent} that triggered this action
049     */
050    @Override
051    public void actionPerformed(ActionEvent e) {
052        // create a copy route frame
053        if (f == null || !f.isVisible()) {
054            f = new SetPhysicalLocationFrame(_reporter);
055            f.setVisible(true);
056        }
057        f.setExtendedState(Frame.NORMAL);
058    }
059
060    /**
061     * Frame for setting train physical location coordinates for a Reporter.
062     *
063     * @author Bob Jacobsen Copyright (C) 2001
064     * @author Daniel Boudreau Copyright (C) 2010
065     * @author Mark Underwood Copyright (C) 2011
066     * 
067     */
068    private static class SetPhysicalLocationFrame extends OperationsFrame {
069
070        /**
071         * Frame Constructor.
072         * @param reporter reporter
073         */
074        public SetPhysicalLocationFrame(Reporter reporter) {
075            super(rb.getString("MenuSetPhysicalLocation"), new SetPhysicalLocationPanel(reporter));
076
077            // add help menu to window
078            addHelpMenu("package.jmri.jmrit.operations.Operations_SetTrainIconCoordinates", true); // fix this later
079
080            super.pack();
081        }
082    }
083
084    private static class SetPhysicalLocationPanel extends OperationsPanel {
085
086        Reporter _reporter;
087
088        String emptyReporterString = "(No Reporters)";
089
090        List<Reporter> _reporterList = new ArrayList<>();
091
092        // labels
093        // text field
094        // check boxes
095        // major buttons
096        JButton saveButton = new JButton(Bundle.getMessage("ButtonSave"));
097        JButton closeButton = new JButton(Bundle.getMessage("ButtonClose"));
098
099        // combo boxes
100        JComboBox<String> reporterBox = getReporterComboBox();
101
102        // Spinners
103        PhysicalLocationPanel physicalLocation;
104
105        public SetPhysicalLocationPanel(Reporter l) {
106
107            // Store the location (null if called from the list view)
108            _reporter = l;
109
110            // general GUI config
111            setLayout(new BoxLayout(this, BoxLayout.Y_AXIS));
112
113            // set tool tips
114            saveButton.setToolTipText(rb.getString("TipSaveButton"));
115            closeButton.setToolTipText(rb.getString("TipCloseButton"));
116
117            // Set up the panels
118            JPanel pLocation = new JPanel();
119            pLocation.setBorder(BorderFactory.createTitledBorder(rb.getString("ReporterName")));
120            pLocation.setToolTipText(rb.getString("TipSelectReporter"));
121            pLocation.add(reporterBox);
122
123            physicalLocation = new PhysicalLocationPanel(rb.getString("PhysicalLocation"));
124            physicalLocation.setToolTipText(rb.getString("TipPhysicalLocation"));
125            physicalLocation.setVisible(true);
126
127            JPanel pControl = new JPanel();
128            pControl.setLayout(new GridBagLayout());
129            pControl.setBorder(BorderFactory.createTitledBorder(""));
130            addItem(pControl, saveButton, 1, 0);
131            addItem(pControl, closeButton, 2, 0);
132
133            add(pLocation);
134            add(physicalLocation);
135            add(pControl);
136
137            // setup buttons
138            saveButton.addActionListener(this::saveButtonActionPerformed);
139            closeButton.addActionListener(this::closeButtonActionPerformed);
140
141            // setup combo box
142            addComboBoxAction(reporterBox);
143            reporterBox.setSelectedIndex(0);
144
145            if (_reporter != null) {
146                reporterBox.setSelectedItem(_reporter);
147            }
148
149            setVisible(true);
150        }
151
152        /**
153         * Construct the combo box with the list of available Reporters.
154         */
155        protected JComboBox<String> getReporterComboBox() {
156            ReporterManager mgr = InstanceManager.getDefault(jmri.ReporterManager.class);
157            List<String> displayList = new ArrayList<>();
158            for (Reporter r : mgr.getNamedBeanSet()) {
159                if (r != null) {
160                    _reporterList.add(r);
161                    displayList.add(r.getDisplayName());
162                }
163            }
164            if (displayList.isEmpty()) {
165                displayList.add(emptyReporterString);
166                saveButton.setEnabled(false);
167            }
168            String[] sa = new String[displayList.size()];
169            displayList.toArray(sa);
170            JComboBox<String> retv = new JComboBox<>(sa);
171            return (retv);
172
173        }
174
175        /**
176         * Close button action.
177         */
178        public void closeButtonActionPerformed(@SuppressWarnings("javadoc") ActionEvent ae) {
179            JmriJOptionPane.showMessageDialog(this,
180                    rb.getString("CloseButtonSaveWarning"),
181                    rb.getString("CloseButtonSaveWarningTitle"),
182                    JmriJOptionPane.WARNING_MESSAGE);
183            dispose();
184        }
185
186        /**
187         * Save button action -> save this Reporter's location.
188         */
189        public void saveButtonActionPerformed(@SuppressWarnings("javadoc") ActionEvent ae) {
190            // check to see if a location has been selected
191            if (reporterBox.getSelectedItem() == null
192                    || reporterBox.getSelectedItem().equals("")) {
193                JmriJOptionPane.showMessageDialog(this,
194                        rb.getString("SelectLocationToEdit"),
195                        rb.getString("NoLocationSelected"),
196                        JmriJOptionPane.ERROR_MESSAGE);
197                return;
198            }
199            Reporter l = getReporterFromList();
200            if (l == null) {
201                return;
202            }
203            int value = JmriJOptionPane.showConfirmDialog(null, MessageFormat.format(rb.getString("UpdatePhysicalLocation"),
204                    new Object[]{l.getDisplayName()}), rb.getString("SaveLocation?"), JmriJOptionPane.YES_NO_OPTION);
205            if (value == JmriJOptionPane.YES_OPTION) {
206                saveSpinnerValues(l);
207            }
208        }
209
210        /**
211         * Get a Reporter from its name in the combo box.
212         */
213        private Reporter getReporterFromList() {
214            String s = (String) reporterBox.getSelectedItem();
215            // Since we don't have "getByDisplayName()" we need to do this in two steps
216            Reporter r = InstanceManager.getDefault(jmri.ReporterManager.class).getByDisplayName(s);
217            return (r);
218        }
219
220        /**
221         * Combo box action.
222         */
223        @Override
224        public void comboBoxActionPerformed(ActionEvent ae) {
225            if (reporterBox.getSelectedItem() != null) {
226                if (reporterBox.getSelectedItem().equals("") || reporterBox.getSelectedItem().equals(emptyReporterString)) {
227                    resetSpinners();
228                } else {
229                    Reporter l = getReporterFromList();
230                    loadSpinners(l);
231                }
232            }
233        }
234
235        /**
236         * Spinner change event.
237         */
238        @Override
239        public void spinnerChangeEvent(ChangeEvent ae) {
240            if (ae.getSource() == physicalLocation) {
241                Reporter l = getReporterFromList();
242                if (l != null) {
243                    PhysicalLocation.setBeanPhysicalLocation(physicalLocation.getValue(), l);
244                }
245            }
246        }
247
248        /**
249         * Reset spinners to zero.
250         */
251        private void resetSpinners() {
252            // Reset spinners to zero.
253            physicalLocation.setValue(new PhysicalLocation());
254        }
255
256        /**
257         * Load spinners from an existing Reporter
258         */
259        private void loadSpinners(Reporter r) {
260            log.debug("Load spinners Reporter location {}", r.getSystemName());
261            physicalLocation.setValue(PhysicalLocation.getBeanPhysicalLocation(r));
262        }
263
264        // Unused. Carried over from SetTrainIconPosition or whatever it was
265        // called...
266 /*
267         * private void spinnersEnable(boolean enable){
268         * physicalLocation.setEnabled(enable); }
269         */
270        /**
271         * Write spinner values to a Reporter.
272         */
273        private void saveSpinnerValues(Reporter r) {
274            log.debug("Save train icons coordinates for location {}", r.getSystemName());
275            PhysicalLocation.setBeanPhysicalLocation(physicalLocation.getValue(), r);
276        }
277
278    }
279
280    private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(SetPhysicalLocationAction.class);
281
282}