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