001package jmri.jmrit.simpleprog;
002
003import java.awt.Container;
004import java.awt.GridLayout;
005import javax.swing.Box;
006import javax.swing.BoxLayout;
007import javax.swing.JLabel;
008import javax.swing.JPanel;
009import javax.swing.JSeparator;
010import javax.swing.JSpinner;
011import javax.swing.SpinnerNumberModel;
012import jmri.ProgListener;
013import jmri.Programmer;
014import jmri.jmrit.symbolicprog.SymbolicProgBundle;
015
016/**
017 * Frame providing a simple command station programmer
018 *
019 * @author Bob Jacobsen Copyright (C) 2001, 2007
020 * @author Giorgio Terdina Copyright (C) 2007
021 * @author Daniel Bergqvist Copyright (C) 2021
022 */
023public class SimpleProgFrame extends jmri.util.JmriJFrame implements jmri.ProgListener {
024
025    /**
026     * GUI member declarations
027     */
028    javax.swing.JToggleButton readButton = new javax.swing.JToggleButton();
029    javax.swing.JToggleButton writeButton = new javax.swing.JToggleButton();
030    // use JSpinner for CV number input
031    SpinnerNumberModel model = new SpinnerNumberModel(1, 1, 1024, 1); // 1024 is highest CV number documented by NMRA as per 2017
032    JSpinner addrField = new JSpinner(model);
033
034    javax.swing.JTextField valField = new javax.swing.JTextField(4);
035
036    jmri.jmrit.progsupport.ProgModePane modePane = new jmri.jmrit.progsupport.ProgModePane(BoxLayout.Y_AXIS);
037
038    javax.swing.ButtonGroup radixGroup = new javax.swing.ButtonGroup();
039    javax.swing.JRadioButton hexButton = new javax.swing.JRadioButton();
040    javax.swing.JRadioButton decButton = new javax.swing.JRadioButton();
041
042    javax.swing.JLabel resultsField = new javax.swing.JLabel(" ");
043
044    public SimpleProgFrame() {
045        super();
046
047        // configure items for GUI
048        readButton.setText(SymbolicProgBundle.getMessage("READ CV"));
049        readButton.setToolTipText(SymbolicProgBundle.getMessage("READ THE VALUE FROM THE SELECTED CV"));
050
051        writeButton.setText(SymbolicProgBundle.getMessage("WRITE CV"));
052        writeButton.setToolTipText(SymbolicProgBundle.getMessage("WRITE THE VALUE TO THE SELECTED CV"));
053
054        hexButton.setText(SymbolicProgBundle.getMessage("Hexadecimal"));
055        decButton.setText(SymbolicProgBundle.getMessage("Decimal"));
056        decButton.setSelected(true);
057
058        // add the actions to the buttons
059        readButton.addActionListener(this::readPushed);
060        writeButton.addActionListener(this::writePushed);
061        decButton.addActionListener(this::decHexButtonChanged);
062        hexButton.addActionListener(this::decHexButtonChanged);
063
064        resultsField.setAlignmentX(JLabel.CENTER_ALIGNMENT);
065
066        Container contentPane = super.getContentPane();
067        // general GUI config
068        setTitle(SymbolicProgBundle.getMessage("SIMPLE PROGRAMMER"));
069        contentPane.setLayout(new BoxLayout(contentPane, BoxLayout.Y_AXIS));
070
071        // install items in GUI
072        javax.swing.JPanel tPane;  // temporary pane for layout
073        javax.swing.JPanel tPane2;
074
075        tPane = new JPanel();
076        tPane.setLayout(new BoxLayout(tPane, BoxLayout.X_AXIS));
077        tPane.add(readButton);
078        tPane.add(writeButton);
079        contentPane.add(tPane);
080
081        tPane = new JPanel();
082        tPane.setLayout(new GridLayout(2, 2));
083        tPane.add(new JLabel(SymbolicProgBundle.getMessage("CV NUMBER:")));
084        tPane.add(addrField); // JSpinner
085        tPane.add(new JLabel(SymbolicProgBundle.getMessage("VALUE:")));
086        tPane.add(valField);
087        contentPane.add(tPane);
088
089        contentPane.add(new JSeparator());
090
091        tPane = new JPanel();
092        tPane.setLayout(new BoxLayout(tPane, BoxLayout.X_AXIS));
093
094        tPane.add(modePane);
095
096        tPane.add(new JSeparator(javax.swing.SwingConstants.VERTICAL));
097
098        tPane2 = new JPanel();
099        tPane2.setLayout(new BoxLayout(tPane2, BoxLayout.Y_AXIS));
100        radixGroup.add(decButton);
101        radixGroup.add(hexButton);
102        tPane2.add(new JLabel(SymbolicProgBundle.getMessage("VALUE IS:")));
103        tPane2.add(decButton);
104        tPane2.add(hexButton);
105        tPane2.add(Box.createVerticalGlue());
106        tPane.add(tPane2);
107
108        contentPane.add(tPane);
109
110        contentPane.add(new JSeparator());
111
112        contentPane.add(resultsField);
113
114        if (modePane.getProgrammer() != null) {
115            readButton.setEnabled(modePane.getProgrammer().getCanRead());
116        } else {
117            readButton.setEnabled(false);
118        }
119
120        // add help menu to window
121        addHelpMenu("package.jmri.jmrit.simpleprog.SimpleProgFrame", true);
122
123        super.pack();
124    }
125
126    // utility function to get value, handling radix
127    private int getNewVal() {
128        try {
129            if (decButton.isSelected()) {
130                return Integer.parseInt(valField.getText());
131            } else {
132                return Integer.parseInt(valField.getText(), 16);
133            }
134        } catch (java.lang.NumberFormatException e) {
135            valField.setText("");
136            return 0;
137        }
138    }
139
140    private String getNewAddr() {
141        return addrField.getValue() + "";
142    }
143
144    private String statusCode(int status) {
145        Programmer p = modePane.getProgrammer();
146        if (status == ProgListener.OK) {
147            return SymbolicProgBundle.getMessage("StateOK");
148        }
149        if (p == null) {
150            return SymbolicProgBundle.getMessage("StateNoProgrammer");
151        } else {
152            return p.decodeErrorCode(status);
153        }
154    }
155
156    // listen for messages from the Programmer object
157    @Override
158    public void programmingOpReply(int value, int status) {
159        resultsField.setText(statusCode(status));
160
161        //operation over, raise the buttons
162        readButton.setSelected(false);
163        writeButton.setSelected(false);
164
165        // capture the read value
166        if (value != -1) // -1 implies nothing being returned
167        {
168            if (decButton.isSelected()) {
169                valField.setText("" + value);
170            } else {
171                valField.setText(Integer.toHexString(value));
172            }
173        }
174    }
175
176    // handle the buttons being pushed
177    public void readPushed(java.awt.event.ActionEvent e) {
178        Programmer p = modePane.getProgrammer();
179        if (p == null) {
180            resultsField.setText(SymbolicProgBundle.getMessage("StateNoProgrammer"));
181            readButton.setSelected(false);
182        } else {
183            if (p.getCanRead()) {
184                try {
185                    resultsField.setText(SymbolicProgBundle.getMessage("StateReading"));
186                    p.readCV(getNewAddr(), this);
187                } catch (jmri.ProgrammerException ex) {
188                    resultsField.setText("" + ex);
189                    readButton.setSelected(false);
190                }
191            } else {
192                resultsField.setText(SymbolicProgBundle.getMessage("CantReadThisMode"));
193                readButton.setSelected(false);
194            }
195        }
196    }
197
198    public void writePushed(java.awt.event.ActionEvent e) {
199        Programmer p = modePane.getProgrammer();
200        if (p == null) {
201            resultsField.setText(SymbolicProgBundle.getMessage("StateNoProgrammer"));
202            writeButton.setSelected(false);
203        } else {
204            try {
205                resultsField.setText(SymbolicProgBundle.getMessage("StateWriting"));
206                p.writeCV(getNewAddr(), getNewVal(), this);
207            } catch (jmri.ProgrammerException ex) {
208                resultsField.setText("" + ex);
209                writeButton.setSelected(false);
210            }
211        }
212    }
213
214    // provide simple data conversion if dec or hex button changed
215    public void decHexButtonChanged(java.awt.event.ActionEvent e) {
216        resultsField.setText(SymbolicProgBundle.getMessage("StateOK"));
217        if (valField.getText().equals("")) {
218            return;
219        }
220        int value = 0;
221        try {
222            if (decButton.isSelected()) // convert from hex to dec
223            {
224                value = Integer.valueOf(valField.getText(), 16);
225            } else // convert from dec to hex
226            {
227                value = Integer.parseInt(valField.getText());
228            }
229        } catch (java.lang.NumberFormatException ee) {
230            resultsField.setText(Bundle.getMessage("ErrorTitle"));
231        }
232        if (value != 0) {
233            if (decButton.isSelected()) {
234                valField.setText(Integer.toString(value));
235            } else {
236                valField.setText(Integer.toHexString(value));
237            }
238        }
239    }
240
241    @Override
242    public void dispose() {
243        modePane.dispose();
244        super.dispose();
245    }
246
247}