001package jmri.jmrit.beantable;
002
003import com.alexandriasoftware.swing.Validation;
004import java.awt.Color;
005import java.awt.FlowLayout;
006import java.awt.event.ActionListener;
007import java.awt.event.ItemEvent;
008import javax.annotation.CheckForNull;
009import javax.annotation.Nonnull;
010import javax.swing.BoxLayout;
011import javax.swing.JButton;
012import javax.swing.JCheckBox;
013import javax.swing.JLabel;
014import javax.swing.JPanel;
015import javax.swing.JSpinner;
016import javax.swing.JTextField;
017import jmri.Manager;
018import jmri.swing.ManagerComboBox;
019import jmri.swing.SystemNameValidator;
020
021/**
022 * JPanel to create a new hardware-backed NamedBean.
023 *
024 * @author Bob Jacobsen Copyright (C) 2009
025 * @author Pete Cressman Copyright (C) 2010
026 */
027public class AddNewHardwareDevicePanel extends jmri.util.swing.JmriPanel {
028
029    /**
030     * Create the panel.
031     *
032     * @param sysAddress text field for the system name or address
033     * @param sysAddressValidator validation control for sysAddress
034     * @param userName text field for the optional user name
035     * @param prefixBox selector for the connection for the NamedBean
036     * @param endRange selector for range to create multiple NamedBeans
037     * @param addRange check box to allow creation of multiple NamedBeans
038     * @param addButton button to trigger creation of NamedBean
039     * @param cancelListener listener to attach to the cancel button
040     * @param rangeListener listener that controls if addRange is enabled
041     * @param statusBar area where status messages can be presented
042     */
043    public AddNewHardwareDevicePanel(@Nonnull JTextField sysAddress,
044            @Nonnull SystemNameValidator sysAddressValidator,
045            @Nonnull JTextField userName,
046            @Nonnull ManagerComboBox<?> prefixBox,
047            JSpinner endRange,
048            JCheckBox addRange,
049            @Nonnull JButton addButton,
050            @Nonnull ActionListener cancelListener,
051            @Nonnull ActionListener rangeListener,
052            @Nonnull JLabel statusBar) {
053        setLayout(new BoxLayout(this, BoxLayout.Y_AXIS));
054        this.statusBar = statusBar;
055        _endRange = endRange;
056        _range = addRange;
057        // directly using the addButton from the table action allows to disable it from there
058        // as long until a valid address is entered
059        JPanel p;
060        p = new JPanel();
061        p.setLayout(new FlowLayout());
062        p.setLayout(new java.awt.GridBagLayout());
063        java.awt.GridBagConstraints c = new java.awt.GridBagConstraints();
064        c.gridwidth = 1;
065        c.gridheight = 1;
066        c.gridx = 0;
067        c.gridy = 0;
068        c.anchor = java.awt.GridBagConstraints.EAST;
069        p.add(sysNameLabel, c);
070        c.gridx = 0;
071        c.gridy = 1;
072        p.add(sysAddressLabel, c);
073        sysAddressLabel.setLabelFor(sysAddress);
074        c.gridy = 2;
075        p.add(userNameLabel, c);
076        c.gridx = 2;
077        c.gridy = 1;
078        c.anchor = java.awt.GridBagConstraints.WEST;
079        c.weightx = 1.0;
080        c.fill = java.awt.GridBagConstraints.HORIZONTAL; // text field will expand
081        c.gridy = 0;
082        p.add(prefixBox, c);
083        c.gridx = 3;
084        p.add(addRange, c);
085        c.gridx = 2;
086        c.gridy = 1;
087        p.add(sysAddress, c);
088        sysAddress.setToolTipText(Bundle.getMessage("HardwareAddressToolTip")); // overridden in calling class
089        c.gridx = 3;
090        p.add(finishLabel, c);
091        c.gridx = 4;
092        p.add(endRange, c);
093        c.gridx = 2;
094        c.gridy = 2;
095        p.add(userName, c);
096        userName.setToolTipText(Bundle.getMessage("UserNameToolTip")); // fixed general instruction
097        add(p);
098
099        finishLabel.setEnabled(false);
100        _endRange.setEnabled(false);
101
102        // add status bar above buttons
103        JPanel panelStatus = new JPanel();
104        panelStatus.setLayout(new FlowLayout());
105        statusBar.setFont(statusBar.getFont().deriveFont(0.9f * sysAddressLabel.getFont().getSize())); // a bit smaller
106        statusBar.setForeground(Color.gray);
107        panelStatus.add(statusBar);
108        add(panelStatus);
109
110        // cancel + add buttons at bottom of window
111        JPanel panelBottom = new JPanel();
112        panelBottom.setLayout(new FlowLayout(FlowLayout.TRAILING));
113
114        panelBottom.add(cancel);
115        cancel.addActionListener(cancelListener);
116
117        panelBottom.add(addButton);
118
119        add(panelBottom);
120
121        addRange.addItemListener((ItemEvent e) -> {
122            rangeState();
123        });
124        prefixBox.addActionListener(rangeListener);
125        sysAddress.setInputVerifier(sysAddressValidator);
126        if (prefixBox.getSelectedItem() == null) {
127            prefixBox.setSelectedIndex(0);
128        }
129        prefixBox.addActionListener((evt) -> {
130            Manager<?> manager = prefixBox.getSelectedItem();
131            if (manager != null) {
132                sysAddress.setText("");     // Reset saved text before switching managers
133                sysAddressValidator.setManager(manager);
134            }
135        });
136        sysAddressValidator.addPropertyChangeListener("validation", (evt) -> { // NOI18N
137            Validation validation = sysAddressValidator.getValidation();
138            Validation.Type type = validation.getType();
139            addButton.setEnabled(type != Validation.Type.WARNING && type != Validation.Type.DANGER);
140            setStatusBarText(validation.getMessage());
141        });
142        sysAddressValidator.setManager(prefixBox.getSelectedItem());
143        sysAddressValidator.verify(sysAddress);
144    }
145
146    public void addLabels(String labelSystemName, String labelUserName) {
147        sysAddressLabel.setText(labelSystemName);
148        userNameLabel.setText(labelUserName);
149    }
150
151    private void rangeState() {
152        if (_range.isSelected()) {
153            finishLabel.setEnabled(true);
154            _endRange.setEnabled(true);
155        } else {
156            finishLabel.setEnabled(false);
157            _endRange.setEnabled(false);
158        }
159    }
160
161    /**
162     * Set the status bar text; if the input is multi-line HTML, get just the
163     * first line, assuming lines are separated with {@code <br>}.
164     *
165     * @param message the message to set
166     */
167    public void setStatusBarText(@CheckForNull String message) {
168        if (message == null) {
169            statusBar.setText("");
170        } else {
171            message = message.trim();
172            if (message.startsWith("<html>") && message.contains("<br>")) {
173                message = message.substring(0, message.indexOf("<br>"));
174                if (!message.endsWith("</html>")) {
175                    message = message + "</html>";
176                }
177            }
178            statusBar.setText(message);
179        }
180    }
181
182    JButton cancel = new JButton(Bundle.getMessage("ButtonClose")); // when Apply has been clicked at least once, this is not Revert/Cancel
183    JSpinner _endRange;
184    JCheckBox _range;
185    JLabel sysNameLabel = new JLabel(Bundle.getMessage("SystemConnectionLabel"));
186    JLabel sysAddressLabel = new JLabel(Bundle.getMessage("LabelHardwareAddress"));
187    JLabel userNameLabel = new JLabel(Bundle.getMessage("LabelUserName"));
188    JLabel finishLabel = new JLabel(Bundle.getMessage("LabelNumberToAdd"));
189    JLabel statusBar;
190
191}