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 final String userNameError = this.getClass().getName() + ".DuplicateUserName"; // only used in this package 095 private Manager<Reporter> connectionChoice = null; 096 private UserPreferencesManager pref; 097 private SystemNameValidator hardwareAddressValidator; 098 099 /** 100 * {@inheritDoc} 101 */ 102 @Override 103 protected void addPressed(ActionEvent e) { 104 pref = InstanceManager.getDefault(UserPreferencesManager.class); 105 if (addFrame == null) { 106 addFrame = new JmriJFrame(Bundle.getMessage("TitleAddReporter"), false, true); 107 addFrame.addHelpMenu("package.jmri.jmrit.beantable.ReporterAddEdit", true); 108 ActionListener createListener = this::createPressed; 109 ActionListener cancelListener = this::cancelPressed; 110 ActionListener rangeListener = this::canAddRange; 111 configureManagerComboBox(prefixBox, reporterManager, ReporterManager.class); 112 userNameTextField.setName("userName"); // NOI18N 113 prefixBox.setName("prefixBox"); // NOI18N 114 addButton = new JButton(Bundle.getMessage("ButtonCreate")); 115 addButton.addActionListener(createListener); 116 117 if (hardwareAddressValidator==null){ 118 hardwareAddressValidator = new SystemNameValidator(hardwareAddressTextField, java.util.Objects.requireNonNull(prefixBox.getSelectedItem()), true); 119 } else { 120 hardwareAddressValidator.setManager(prefixBox.getSelectedItem()); 121 } 122 123 // create panel 124 addFrame.add(new AddNewHardwareDevicePanel(hardwareAddressTextField, hardwareAddressValidator, userNameTextField, prefixBox, 125 numberToAddSpinner, rangeCheckBox, addButton, cancelListener, rangeListener, statusBarLabel)); 126 // tooltip for hardwareAddressTextField will be assigned next by canAddRange() 127 canAddRange(null); 128 } 129 hardwareAddressTextField.setName("sysName"); // for GUI test NOI18N 130 hardwareAddressTextField.setName("hwAddressTextField"); // for GUI test NOI18N 131 addButton.setName("createButton"); // for GUI test NOI18N 132 // reset statusBarLabel text 133 statusBarLabel.setText(Bundle.getMessage("HardwareAddStatusEnter")); 134 statusBarLabel.setForeground(Color.gray); 135 addFrame.setEscapeKeyClosesWindow(true); 136 addFrame.getRootPane().setDefaultButton(addButton); 137 addFrame.pack(); 138 addFrame.setVisible(true); 139 } 140 141 void cancelPressed(ActionEvent e) { 142 removePrefixBoxListener(prefixBox); 143 addFrame.setVisible(false); 144 addFrame.dispose(); 145 addFrame = null; 146 } 147 148 /** 149 * Respond to Create new item button pressed on Add Reporter pane. 150 * 151 * @param e the click event 152 */ 153 void createPressed(ActionEvent e) { 154 155 int numberOfReporters = 1; 156 157 if (rangeCheckBox.isSelected()) { 158 numberOfReporters = (Integer) numberToAddSpinner.getValue(); 159 } 160 if (numberOfReporters >= 65 // limited by JSpinnerModel to 100 161 && JmriJOptionPane.showConfirmDialog(addFrame, 162 Bundle.getMessage("WarnExcessBeans", Bundle.getMessage("Reporters"), numberOfReporters), 163 Bundle.getMessage("WarningTitle"), 164 JmriJOptionPane.YES_NO_OPTION ) != JmriJOptionPane.YES_OPTION ) { 165 return; 166 } 167 String rName; 168 String reporterPrefix = prefixBox.getSelectedItem().getSystemPrefix(); // Add "R" later 169 String curAddress = hardwareAddressTextField.getText(); 170 // initial check for empty entry 171 if (curAddress.isEmpty()) { 172 statusBarLabel.setText(Bundle.getMessage("WarningEmptyHardwareAddress")); 173 statusBarLabel.setForeground(Color.red); 174 hardwareAddressTextField.setBackground(Color.red); 175 return; 176 } else { 177 hardwareAddressTextField.setBackground(Color.white); 178 } 179 180 // Add some entry pattern checking, before assembling sName and handing it to the ReporterManager 181 StringBuilder statusMessage = new StringBuilder( 182 Bundle.getMessage("ItemCreateFeedback", Bundle.getMessage("BeanNameReporter"))); 183 String uName = userNameTextField.getText(); 184 185 186 // Compose the proposed system name from parts: 187 rName = reporterPrefix + reporterManager.typeLetter() + curAddress; 188 189 for (int x = 0; x < numberOfReporters; x++) { 190 191 // create the next reporter 192 Reporter r; 193 try { 194 r = reporterManager.provideReporter(rName); 195 } catch (IllegalArgumentException ex) { 196 // user input no good 197 handleCreateException(ex, rName); // displays message dialog to the user 198 return; // without creating 199 } 200 201 // handle setting user name 202 if (!uName.isEmpty()) { 203 if ((reporterManager.getByUserName(uName) == null)) { 204 r.setUserName(uName); 205 } else { 206 pref.showErrorMessage(Bundle.getMessage("ErrorTitle"), 207 Bundle.getMessage("ErrorDuplicateUserName", uName), userNameError, "", 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 // private final static org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(ReporterTableAction.class); 304 305}