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}