001package jmri.jmrix.secsi.nodeconfig;
002
003import java.awt.Container;
004import java.awt.FlowLayout;
005import javax.swing.BorderFactory;
006import javax.swing.BoxLayout;
007import javax.swing.JComboBox;
008import javax.swing.JLabel;
009import javax.swing.JPanel;
010import javax.swing.border.Border;
011import jmri.jmrix.secsi.SerialNode;
012import jmri.jmrix.secsi.SerialSensorManager;
013import jmri.jmrix.secsi.SecsiSystemConnectionMemo;
014import jmri.util.swing.JmriJOptionPane;
015
016/**
017 * Frame for user configuration of serial nodes.
018 *
019 * @author Bob Jacobsen Copyright (C) 2004, 2007, 2008
020 * @author Dave Duchamp Copyright (C) 2004, 2006
021 */
022public class NodeConfigFrame extends jmri.util.JmriJFrame {
023
024    private SecsiSystemConnectionMemo memo;
025
026    protected javax.swing.JTextField nodeAddrField = new javax.swing.JTextField(3);
027    protected javax.swing.JLabel nodeAddrStatic = new javax.swing.JLabel("000");
028    protected javax.swing.JComboBox<String> nodeTypeBox;
029
030    protected javax.swing.JButton addButton = new javax.swing.JButton(Bundle.getMessage("ButtonAdd"));
031    protected javax.swing.JButton editButton = new javax.swing.JButton(Bundle.getMessage("ButtonEdit"));
032    protected javax.swing.JButton deleteButton = new javax.swing.JButton(Bundle.getMessage("ButtonDelete"));
033    protected javax.swing.JButton doneButton = new javax.swing.JButton(Bundle.getMessage("ButtonDone"));
034    protected javax.swing.JButton updateButton = new javax.swing.JButton(Bundle.getMessage("ButtonUpdate"));
035    protected javax.swing.JButton cancelButton = new javax.swing.JButton(Bundle.getMessage("ButtonCancel"));
036
037    protected javax.swing.JLabel statusText1 = new javax.swing.JLabel();
038    protected javax.swing.JLabel statusText2 = new javax.swing.JLabel();
039    protected javax.swing.JLabel statusText3 = new javax.swing.JLabel();
040
041    protected boolean changedNode = false;  // true if a node was changed, deleted, or added
042    protected boolean editMode = false;     // true if in edit mode
043    private boolean checkEnabled = jmri.InstanceManager.getDefault(jmri.configurexml.ShutdownPreferences.class).isStoreCheckEnabled();
044
045    protected SerialNode curNode = null;    // Serial Node being editted
046    protected int nodeAddress = 0;          // Node address
047    protected int nodeType = SerialNode.DAUGHTER; // Node type
048
049    protected boolean errorInStatus1 = false;
050    protected boolean errorInStatus2 = false;
051    protected String stdStatus1 = Bundle.getMessage("NotesStd1");
052    protected String stdStatus2 = Bundle.getMessage("NotesStd2");
053    protected String stdStatus3 = Bundle.getMessage("NotesStd3");
054    protected String editStatus1 = Bundle.getMessage("NotesEdit1");
055    protected String editStatus2 = Bundle.getMessage("NotesEdit2");
056    protected String editStatus3 = Bundle.getMessage("NotesEdit3");
057
058    /**
059     * Constructor method
060     * @param _memo system connection.
061     */
062    public NodeConfigFrame(SecsiSystemConnectionMemo _memo) {
063        super();
064        memo = _memo;
065    }
066
067    /**
068     * Initialize the node config window.
069     */
070    @Override
071    public void initComponents() {
072        setTitle(Bundle.getMessage("ConfigNodesTitle"));
073
074        Container contentPane = getContentPane();
075        contentPane.setLayout(new BoxLayout(contentPane, BoxLayout.Y_AXIS));
076
077        // Set up node address and node type
078        JPanel panel1 = new JPanel();
079        panel1.setLayout(new BoxLayout(panel1, BoxLayout.Y_AXIS));
080
081        // panel11 is the node address and type
082        JPanel panel11 = new JPanel();
083        panel11.setLayout(new FlowLayout());
084        panel11.add(new JLabel(Bundle.getMessage("LabelNodeAddress") + " "));
085        panel11.add(nodeAddrField);
086        nodeAddrField.setToolTipText(Bundle.getMessage("TipNodeAddress"));
087        nodeAddrField.setText("0");
088        panel11.add(nodeAddrStatic);
089        nodeAddrStatic.setVisible(false);
090        panel11.add(new JLabel("   " + Bundle.getMessage("LabelNodeType") + " "));
091        nodeTypeBox = new JComboBox<String>(SerialNode.getBoardNames());
092        panel11.add(nodeTypeBox);
093        nodeTypeBox.setToolTipText(Bundle.getMessage("TipNodeType"));
094        contentPane.add(panel11);
095
096        // Set up the notes panel
097        JPanel panel3 = new JPanel();
098        panel3.setLayout(new BoxLayout(panel3, BoxLayout.Y_AXIS));
099        JPanel panel31 = new JPanel();
100        panel31.setLayout(new FlowLayout());
101        statusText1.setText(stdStatus1);
102        statusText1.setVisible(true);
103        panel31.add(statusText1);
104        JPanel panel32 = new JPanel();
105        panel32.setLayout(new FlowLayout());
106        statusText2.setText(stdStatus2);
107        statusText2.setVisible(true);
108        panel32.add(statusText2);
109        JPanel panel33 = new JPanel();
110        panel33.setLayout(new FlowLayout());
111        statusText3.setText(stdStatus3);
112        statusText3.setVisible(true);
113        panel33.add(statusText3);
114        panel3.add(panel31);
115        panel3.add(panel32);
116        panel3.add(panel33);
117        Border panel3Border = BorderFactory.createEtchedBorder();
118        Border panel3Titled = BorderFactory.createTitledBorder(panel3Border,
119                Bundle.getMessage("BoxLabelNotes"));
120        panel3.setBorder(panel3Titled);
121        contentPane.add(panel3);
122
123        // Set up buttons
124        JPanel panel4 = new JPanel();
125        panel4.setLayout(new FlowLayout());
126        addButton.setText(Bundle.getMessage("ButtonAdd"));
127        addButton.setVisible(true);
128        addButton.setToolTipText(Bundle.getMessage("TipAddButton"));
129        addButton.addActionListener(new java.awt.event.ActionListener() {
130            @Override
131            public void actionPerformed(java.awt.event.ActionEvent e) {
132                addButtonActionPerformed();
133            }
134        });
135        panel4.add(addButton);
136        editButton.setText(Bundle.getMessage("ButtonEdit"));
137        editButton.setVisible(true);
138        editButton.setToolTipText(Bundle.getMessage("TipEditButton"));
139        panel4.add(editButton);
140        editButton.addActionListener(new java.awt.event.ActionListener() {
141            @Override
142            public void actionPerformed(java.awt.event.ActionEvent e) {
143                editButtonActionPerformed();
144            }
145        });
146        panel4.add(deleteButton);
147        deleteButton.setText(Bundle.getMessage("ButtonDelete"));
148        deleteButton.setVisible(true);
149        deleteButton.setToolTipText(Bundle.getMessage("TipDeleteButton"));
150        panel4.add(deleteButton);
151        deleteButton.addActionListener(new java.awt.event.ActionListener() {
152            @Override
153            public void actionPerformed(java.awt.event.ActionEvent e) {
154                deleteButtonActionPerformed();
155            }
156        });
157        panel4.add(doneButton);
158        doneButton.setText(Bundle.getMessage("ButtonDone"));
159        doneButton.setVisible(true);
160        doneButton.setToolTipText(Bundle.getMessage("TipDoneButton"));
161        panel4.add(doneButton);
162        doneButton.addActionListener(new java.awt.event.ActionListener() {
163            @Override
164            public void actionPerformed(java.awt.event.ActionEvent e) {
165                doneButtonActionPerformed();
166            }
167        });
168        panel4.add(updateButton);
169        updateButton.setText(Bundle.getMessage("ButtonUpdate"));
170        updateButton.setVisible(true);
171        updateButton.setToolTipText(Bundle.getMessage("TipUpdateButton"));
172        panel4.add(updateButton);
173        updateButton.addActionListener(new java.awt.event.ActionListener() {
174            @Override
175            public void actionPerformed(java.awt.event.ActionEvent e) {
176                updateButtonActionPerformed();
177            }
178        });
179        updateButton.setVisible(false);
180        panel4.add(cancelButton);
181        cancelButton.setText(Bundle.getMessage("ButtonCancel"));
182        cancelButton.setVisible(true);
183        cancelButton.setToolTipText(Bundle.getMessage("TipCancelButton"));
184        panel4.add(cancelButton);
185        cancelButton.addActionListener(new java.awt.event.ActionListener() {
186            @Override
187            public void actionPerformed(java.awt.event.ActionEvent e) {
188                cancelButtonActionPerformed();
189            }
190        });
191        cancelButton.setVisible(false);
192        contentPane.add(panel4);
193
194        // pack for display
195        pack();
196    }
197
198    /**
199     * Handle Add button.
200     */
201    public void addButtonActionPerformed() {
202        // Check that a node with this address does not exist
203        int nodeAddress = readNodeAddress();
204        if (nodeAddress < 0) {
205            return;
206        }
207        // get a SerialNode corresponding to this node address if one exists
208        curNode = (SerialNode) memo.getTrafficController().getNodeFromAddress(nodeAddress);
209        if (curNode != null) {
210            log.debug("Asked for new node address {}", Integer.toString(nodeAddress));
211            statusText1.setText(Bundle.getMessage("Error1", Integer.toString(nodeAddress)));
212            statusText1.setVisible(true);
213            errorInStatus1 = true;
214            resetNotes2();
215            return;
216        }
217        nodeType = nodeTypeBox.getSelectedIndex();
218
219        // all ready, create the new node
220        curNode = new SerialNode(nodeAddress, nodeType, memo.getTrafficController());
221        // configure the new node
222        setNodeParameters();
223        // register any orphan sensors that this node may have
224        ((SerialSensorManager)memo.getSensorManager()).registerSensorsForNode(curNode);
225        // reset after succefully adding node
226        resetNotes();
227        changedNode = true;
228        // provide user feedback
229        statusText1.setText(Bundle.getMessage("FeedBackAdd") + " "
230                + Integer.toString(nodeAddress));
231        errorInStatus1 = true;
232    }
233
234    /**
235     * Handle Edit button.
236     */
237    public void editButtonActionPerformed() {
238        // Find Serial Node address
239        nodeAddress = readNodeAddress();
240        if (nodeAddress < 0) {
241            return;
242        }
243        // get the SerialNode corresponding to this node address
244        curNode = (SerialNode) memo.getTrafficController().getNodeFromAddress(nodeAddress);
245        if (curNode == null) {
246            statusText1.setText(Bundle.getMessage("Error4"));
247            statusText1.setVisible(true);
248            errorInStatus1 = true;
249            resetNotes2();
250            return;
251        }
252        // Set up static node address
253        nodeAddrStatic.setText(Integer.toString(nodeAddress));
254        nodeAddrField.setVisible(false);
255        nodeAddrStatic.setVisible(true);
256        // get information for this node and set up combo box
257        nodeType = curNode.getNodeType();
258        nodeTypeBox.setSelectedIndex(nodeType);
259        // Switch buttons
260        editMode = true;
261        addButton.setVisible(false);
262        editButton.setVisible(false);
263        deleteButton.setVisible(false);
264        doneButton.setVisible(false);
265        updateButton.setVisible(true);
266        cancelButton.setVisible(true);
267        // Switch to edit notes
268        statusText1.setText(editStatus1);
269        statusText2.setText(editStatus2);
270        statusText3.setText(editStatus3);
271    }
272
273    /**
274     * Handle Delete button.
275     */
276    public void deleteButtonActionPerformed() {
277        // Find Serial Node address
278        int nodeAddress = readNodeAddress();
279        if (nodeAddress < 0) {
280            return;
281        }
282        // get the SerialNode corresponding to this node address
283        curNode = (SerialNode) memo.getTrafficController().getNodeFromAddress(nodeAddress);
284        if (curNode == null) {
285            statusText1.setText(Bundle.getMessage("Error4"));
286            statusText1.setVisible(true);
287            errorInStatus1 = true;
288            resetNotes2();
289            return;
290        }
291        // confirm deletion with the user
292        if (JmriJOptionPane.OK_OPTION == JmriJOptionPane.showConfirmDialog(
293                this, Bundle.getMessage("ConfirmDelete1") + "\n"
294                + Bundle.getMessage("ConfirmDelete2"), Bundle.getMessage("ConfirmDeleteTitle"),
295                JmriJOptionPane.OK_CANCEL_OPTION,
296                JmriJOptionPane.WARNING_MESSAGE)) {
297            // delete this node
298            memo.getTrafficController().deleteNode(nodeAddress);
299            // provide user feedback
300            resetNotes();
301            statusText1.setText(Bundle.getMessage("FeedBackDelete") + " "
302                    + Integer.toString(nodeAddress));
303            errorInStatus1 = true;
304            changedNode = true;
305        } else {
306            // reset as needed
307            resetNotes();
308        }
309    }
310
311    /**
312     * Handle Done button.
313     */
314    public void doneButtonActionPerformed() {
315        if (editMode) {
316            // Reset
317            editMode = false;
318            curNode = null;
319            // Switch buttons
320            addButton.setVisible(true);
321            editButton.setVisible(true);
322            deleteButton.setVisible(true);
323            doneButton.setVisible(true);
324            updateButton.setVisible(false);
325            cancelButton.setVisible(false);
326            nodeAddrField.setVisible(true);
327            nodeAddrStatic.setVisible(false);
328        }
329        if (changedNode && !checkEnabled) {
330            // Remind user to Save new configuration
331            JmriJOptionPane.showMessageDialog(this,
332                    Bundle.getMessage("ReminderNode1") + "\n" + Bundle.getMessage("Reminder2"),
333                    Bundle.getMessage("ReminderTitle"),
334                    JmriJOptionPane.INFORMATION_MESSAGE);
335        }
336        setVisible(false);
337        dispose();
338    }
339
340    /**
341     * Handle Update button.
342     */
343    public void updateButtonActionPerformed() {
344        // update node information
345        nodeType = nodeTypeBox.getSelectedIndex();
346        log.debug("update performed: was {} request {}", curNode.getNodeType(), nodeType);
347        if (curNode.getNodeType() != nodeType) {
348            // node type has changed
349            curNode.setNodeType(nodeType);
350        }
351        setNodeParameters();
352        changedNode = true;
353        // Reset Edit Mode
354        editMode = false;
355        curNode = null;
356        // Switch buttons
357        addButton.setVisible(true);
358        editButton.setVisible(true);
359        deleteButton.setVisible(true);
360        doneButton.setVisible(true);
361        updateButton.setVisible(false);
362        cancelButton.setVisible(false);
363        // make node address editable again
364        nodeAddrField.setVisible(true);
365        nodeAddrStatic.setVisible(false);
366        // refresh notes panel
367        statusText2.setText(stdStatus2);
368        statusText3.setText(stdStatus3);
369        // provide user feedback
370        statusText1.setText(Bundle.getMessage("FeedBackUpdate") + " "
371                + Integer.toString(nodeAddress));
372        errorInStatus1 = true;
373    }
374
375    /**
376     * Handle Cancel button.
377     */
378    public void cancelButtonActionPerformed() {
379        // Reset
380        editMode = false;
381        curNode = null;
382        // Switch buttons
383        addButton.setVisible(true);
384        editButton.setVisible(true);
385        deleteButton.setVisible(true);
386        doneButton.setVisible(true);
387        updateButton.setVisible(false);
388        cancelButton.setVisible(false);
389        // make node address editable again
390        nodeAddrField.setVisible(true);
391        nodeAddrStatic.setVisible(false);
392        // refresh notes panel
393        statusText1.setText(stdStatus1);
394        statusText2.setText(stdStatus2);
395        statusText3.setText(stdStatus3);
396    }
397
398    /**
399     * Do the done action if the window is closed early.
400     */
401    @Override
402    public void windowClosing(java.awt.event.WindowEvent e) {
403        doneButtonActionPerformed();
404    }
405
406    /**
407     * Method to set node parameters The node must exist, and be in 'curNode'
408     * Also, the node type must be set and in 'nodeType'
409     */
410    void setNodeParameters() {
411        // set curNode type
412        curNode.setNodeType(nodeType);
413        // Cause reinitialization of this Node to reflect these parameters
414        memo.getTrafficController().initializeSerialNode(curNode);
415    }
416
417    /**
418     * Method to reset the notes error after error display
419     */
420    private void resetNotes() {
421        if (errorInStatus1) {
422            if (editMode) {
423                statusText1.setText(editStatus1);
424            } else {
425                statusText1.setText(stdStatus1);
426            }
427            errorInStatus1 = false;
428        }
429        resetNotes2();
430    }
431
432    /**
433     * Reset the second line of Notes area
434     */
435    private void resetNotes2() {
436        if (errorInStatus2) {
437            if (editMode) {
438                statusText1.setText(editStatus2);
439            } else {
440                statusText2.setText(stdStatus2);
441            }
442            errorInStatus2 = false;
443        }
444    }
445
446    /**
447     * Read node address and check for legal range If successful, a node address
448     * in the range 0-255 is returned. If not successful, -1 is returned and an
449     * appropriate error message is placed in statusText1.
450     */
451    private int readNodeAddress() {
452        int addr = -1;
453        try {
454            addr = Integer.parseInt(nodeAddrField.getText());
455        } catch (Exception e) {
456            statusText1.setText(Bundle.getMessage("Error5"));
457            statusText1.setVisible(true);
458            errorInStatus1 = true;
459            resetNotes2();
460            return -1;
461        }
462        if ((addr < 0) || (addr > 255)) {
463            statusText1.setText(Bundle.getMessage("Error6"));
464            statusText1.setVisible(true);
465            errorInStatus1 = true;
466            resetNotes2();
467            return -1;
468        }
469        return (addr);
470    }
471
472    private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(NodeConfigFrame.class);
473
474}