001package jmri.jmrit.beantable; 002 003import java.awt.Color; 004import java.awt.event.ActionEvent; 005import java.awt.event.ActionListener; 006import javax.annotation.Nonnull; 007import javax.swing.*; 008 009import jmri.InstanceManager; 010import jmri.Manager; 011import jmri.Reporter; 012import jmri.ReporterManager; 013import jmri.UserPreferencesManager; 014import jmri.swing.ManagerComboBox; 015import jmri.swing.SystemNameValidator; 016import jmri.util.JmriJFrame; 017import jmri.util.swing.JmriJOptionPane; 018 019/** 020 * Swing action to create and register a ReporterTable GUI. 021 * 022 * @author Bob Jacobsen Copyright (C) 2003 023 */ 024public class ReporterTableAction extends AbstractTableAction<Reporter> { 025 026 /** 027 * Create an action with a specific title. 028 * <p> 029 * Note that the argument is the Action title, not the title of the 030 * resulting frame. Perhaps this should be changed? 031 * 032 * @param actionName title of the action 033 */ 034 public ReporterTableAction(String actionName) { 035 super(actionName); 036 037 // disable ourself if there is no primary Reporter manager available 038 if (reporterManager == null) { 039 super.setEnabled(false); 040 } 041 } 042 043 protected ReporterManager reporterManager = InstanceManager.getDefault(ReporterManager.class); 044 045 /** 046 * {@inheritDoc} 047 */ 048 @Override 049 public void setManager(@Nonnull Manager<Reporter> man) { 050 if (man instanceof ReporterManager) { 051 reporterManager = (ReporterManager) man; 052 } 053 } 054 055 public ReporterTableAction() { 056 this(Bundle.getMessage("TitleReporterTable")); 057 } 058 059 /** 060 * Create the JTable DataModel, along with the changes for the specific case 061 * of Reporters. 062 */ 063 @Override 064 protected void createModel() { 065 m = new ReporterTableDataModel(reporterManager); 066 } 067 068 /** 069 * {@inheritDoc} 070 */ 071 @Override 072 protected void setTitle() { 073 f.setTitle(Bundle.getMessage("TitleReporterTable")); 074 } 075 076 /** 077 * {@inheritDoc} 078 */ 079 @Override 080 protected String helpTarget() { 081 return "package.jmri.jmrit.beantable.ReporterTable"; 082 } 083 084 private JmriJFrame addFrame = null; 085 private final JTextField hardwareAddressTextField = new JTextField(20); 086 private final JTextField userNameTextField = new JTextField(20); 087 private final ManagerComboBox<Reporter> prefixBox = new ManagerComboBox<>(); 088 private final SpinnerNumberModel rangeSpinner = new SpinnerNumberModel(1, 1, 100, 1); // maximum 100 items 089 private final JSpinner numberToAddSpinner = new JSpinner(rangeSpinner); 090 private final JCheckBox rangeCheckBox = new JCheckBox(Bundle.getMessage("AddRangeBox")); 091 private final String systemSelectionCombo = this.getClass().getName() + ".SystemSelected"; 092 private JButton addButton; 093 private final JLabel statusBarLabel = new JLabel(Bundle.getMessage("HardwareAddStatusEnter"), JLabel.LEADING); 094 private Manager<Reporter> connectionChoice = null; 095 private UserPreferencesManager pref; 096 private SystemNameValidator hardwareAddressValidator; 097 098 /** 099 * {@inheritDoc} 100 */ 101 @Override 102 protected void addPressed(ActionEvent e) { 103 pref = InstanceManager.getDefault(UserPreferencesManager.class); 104 if (addFrame == null) { 105 addFrame = new JmriJFrame(Bundle.getMessage("TitleAddReporter"), false, true); 106 addFrame.addHelpMenu("package.jmri.jmrit.beantable.ReporterAddEdit", true); 107 ActionListener createListener = this::createPressed; 108 ActionListener cancelListener = this::cancelPressed; 109 ActionListener rangeListener = this::canAddRange; 110 configureManagerComboBox(prefixBox, reporterManager, ReporterManager.class); 111 userNameTextField.setName("userName"); // NOI18N 112 prefixBox.setName("prefixBox"); // NOI18N 113 addButton = new JButton(Bundle.getMessage("ButtonCreate")); 114 addButton.addActionListener(createListener); 115 116 if (hardwareAddressValidator==null){ 117 hardwareAddressValidator = new SystemNameValidator(hardwareAddressTextField, java.util.Objects.requireNonNull(prefixBox.getSelectedItem()), true); 118 } else { 119 hardwareAddressValidator.setManager(prefixBox.getSelectedItem()); 120 } 121 122 // create panel 123 addFrame.add(new AddNewHardwareDevicePanel(hardwareAddressTextField, hardwareAddressValidator, userNameTextField, prefixBox, 124 numberToAddSpinner, rangeCheckBox, addButton, cancelListener, rangeListener, statusBarLabel)); 125 // tooltip for hardwareAddressTextField will be assigned next by canAddRange() 126 canAddRange(null); 127 } 128 hardwareAddressTextField.setName("sysName"); // for GUI test NOI18N 129 hardwareAddressTextField.setName("hwAddressTextField"); // for GUI test NOI18N 130 addButton.setName("createButton"); // for GUI test NOI18N 131 // reset statusBarLabel text 132 statusBarLabel.setText(Bundle.getMessage("HardwareAddStatusEnter")); 133 statusBarLabel.setForeground(Color.gray); 134 addFrame.setEscapeKeyClosesWindow(true); 135 addFrame.getRootPane().setDefaultButton(addButton); 136 addFrame.pack(); 137 addFrame.setVisible(true); 138 } 139 140 void cancelPressed(ActionEvent e) { 141 removePrefixBoxListener(prefixBox); 142 addFrame.setVisible(false); 143 addFrame.dispose(); 144 addFrame = null; 145 } 146 147 /** 148 * Respond to Create new item button pressed on Add Reporter pane. 149 * 150 * @param e the click event 151 */ 152 void createPressed(ActionEvent e) { 153 154 int numberOfReporters = 1; 155 156 if (rangeCheckBox.isSelected()) { 157 numberOfReporters = (Integer) numberToAddSpinner.getValue(); 158 } 159 if (numberOfReporters >= 65 // limited by JSpinnerModel to 100 160 && JmriJOptionPane.showConfirmDialog(addFrame, 161 Bundle.getMessage("WarnExcessBeans", Bundle.getMessage("Reporters"), numberOfReporters), 162 Bundle.getMessage("WarningTitle"), 163 JmriJOptionPane.YES_NO_OPTION ) != JmriJOptionPane.YES_OPTION ) { 164 return; 165 } 166 String rName; 167 String reporterPrefix = prefixBox.getSelectedItem().getSystemPrefix(); // Add "R" later 168 String curAddress = hardwareAddressTextField.getText(); 169 // initial check for empty entry 170 if (curAddress.isEmpty()) { 171 statusBarLabel.setText(Bundle.getMessage("WarningEmptyHardwareAddress")); 172 statusBarLabel.setForeground(Color.red); 173 hardwareAddressTextField.setBackground(Color.red); 174 return; 175 } else { 176 hardwareAddressTextField.setBackground(Color.white); 177 } 178 179 // Add some entry pattern checking, before assembling sName and handing it to the ReporterManager 180 StringBuilder statusMessage = new StringBuilder( 181 Bundle.getMessage("ItemCreateFeedback", Bundle.getMessage("BeanNameReporter"))); 182 String uName = userNameTextField.getText(); 183 184 185 // Compose the proposed system name from parts: 186 rName = reporterPrefix + reporterManager.typeLetter() + curAddress; 187 188 for (int x = 0; x < numberOfReporters; x++) { 189 190 // create the next reporter 191 Reporter r; 192 try { 193 r = reporterManager.provideReporter(rName); 194 } catch (IllegalArgumentException ex) { 195 // user input no good 196 handleCreateException(ex, rName); // displays message dialog to the user 197 return; // without creating 198 } 199 200 // handle setting user name 201 if (!uName.isEmpty()) { 202 if ((reporterManager.getByUserName(uName) == null)) { 203 r.setUserName(uName); 204 } else { 205 pref.showErrorMessage(Bundle.getMessage("ErrorTitle"), 206 Bundle.getMessage("ErrorDuplicateUserName", uName), 207 getClassName(), "duplicateUserName", false, true); 208 } 209 } 210 211 // add first and last names to statusMessage user feedback string 212 // only mention first and last of rangeCheckBox added 213 if (x == 0 || x == numberOfReporters - 1) { 214 statusMessage.append(" ").append(rName).append(" (").append(uName).append(")"); 215 } 216 if (x == numberOfReporters - 2) { 217 statusMessage.append(" ").append(Bundle.getMessage("ItemCreateUpTo")).append(" "); 218 } 219 220 // except on last pass 221 if (x < numberOfReporters-1) { 222 // bump system name 223 try { 224 rName = InstanceManager.getDefault(ReporterManager.class).getNextValidSystemName(r); 225 } catch (jmri.JmriException ex) { 226 displayHwError(r.getSystemName(), ex); 227 // directly add to statusBarLabel (but never called?) 228 statusBarLabel.setText(Bundle.getMessage("ErrorConvertHW", rName)); 229 statusBarLabel.setForeground(Color.red); 230 return; 231 } 232 233 // bump user name 234 if (!uName.isEmpty()) { 235 uName = nextName(uName); 236 } 237 } 238 // end of for loop creating rangeCheckBox of Reporters 239 } 240 // provide success feedback to uName 241 statusBarLabel.setText(statusMessage.toString()); 242 statusBarLabel.setForeground(Color.gray); 243 244 pref.setComboBoxLastSelection(systemSelectionCombo, prefixBox.getSelectedItem().getMemo().getUserName()); 245 removePrefixBoxListener(prefixBox); 246 addFrame.setVisible(false); 247 addFrame.dispose(); 248 addFrame = null; 249 } 250 251 private String addEntryToolTip; 252 253 /** 254 * Activate Add a rangeCheckBox option if manager accepts adding more than 1 255 * Reporter and set a manager specific tooltip on the AddNewHardwareDevice 256 * pane. 257 */ 258 private void canAddRange(ActionEvent e) { 259 rangeCheckBox.setEnabled(false); 260 rangeCheckBox.setSelected(false); 261 if (prefixBox.getSelectedIndex() == -1) { 262 prefixBox.setSelectedIndex(0); 263 } 264 connectionChoice = prefixBox.getSelectedItem(); // store in Field for CheckedTextField 265 String systemPrefix = connectionChoice.getSystemPrefix(); 266 rangeCheckBox.setEnabled(((ReporterManager) connectionChoice).allowMultipleAdditions(systemPrefix)); 267 addEntryToolTip = connectionChoice.getEntryToolTip(); 268 // show hwAddressTextField field tooltip in the Add Reporter pane that matches system connection selected from combobox 269 hardwareAddressTextField.setToolTipText( 270 Bundle.getMessage("AddEntryToolTipLine1", 271 connectionChoice.getMemo().getUserName(), 272 Bundle.getMessage("Reporters"), 273 addEntryToolTip)); 274 hardwareAddressValidator.setToolTipText(hardwareAddressTextField.getToolTipText()); 275 hardwareAddressValidator.verify(hardwareAddressTextField); 276 } 277 278 void handleCreateException(Exception ex, String sysName) { 279 statusBarLabel.setText(ex.getLocalizedMessage()); 280 statusBarLabel.setForeground(Color.red); 281 String err = Bundle.getMessage("ErrorBeanCreateFailed", 282 InstanceManager.getDefault(ReporterManager.class).getBeanTypeHandled(),sysName); 283 JmriJOptionPane.showMessageDialog(addFrame, err + "\n" + ex.getLocalizedMessage(), 284 err, JmriJOptionPane.ERROR_MESSAGE); 285 } 286 287 /** 288 * {@inheritDoc} 289 */ 290 @Override 291 protected String getClassName() { 292 return ReporterTableAction.class.getName(); 293 } 294 295 /** 296 * {@inheritDoc} 297 */ 298 @Override 299 public String getClassDescription() { 300 return Bundle.getMessage("TitleReporterTable"); 301 } 302 303 @Override 304 public void setMessagePreferencesDetails() { 305 InstanceManager.getDefault(jmri.UserPreferencesManager.class). 306 setPreferenceItemDetails(getClassName(), "duplicateUserName", Bundle.getMessage("DuplicateUserNameWarn")); // NOI18N 307 super.setMessagePreferencesDetails(); 308 } 309 310 // private final static org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(ReporterTableAction.class); 311 312}