001package jmri.jmrit.beantable;
002
003import java.awt.Color;
004import java.awt.event.ActionEvent;
005import java.awt.event.ActionListener;
006
007import javax.swing.BoxLayout;
008import javax.swing.JCheckBox;
009import javax.swing.JLabel;
010import javax.swing.JSpinner;
011import javax.swing.JTextField;
012import javax.swing.SpinnerNumberModel;
013
014import jmri.InstanceManager;
015import jmri.Memory;
016import jmri.MemoryManager;
017import jmri.NamedBean;
018import jmri.UserPreferencesManager;
019import jmri.util.JmriJFrame;
020import jmri.util.swing.JmriJOptionPane;
021
022// import org.slf4j.Logger;
023// import org.slf4j.LoggerFactory;
024
025/**
026 * Swing action to create and register a MemoryTable GUI.
027 *
028 * @author Bob Jacobsen Copyright (C) 2003
029 */
030public class MemoryTableAction extends AbstractTableAction<Memory> {
031
032    /**
033     * Create an action with a specific title.
034     * <p>
035     * Note that the argument is the Action title, not the title of the
036     * resulting frame. Perhaps this should be changed?
037     *
038     * @param actionName title of the action
039     */
040    public MemoryTableAction(String actionName) {
041        super(actionName);
042
043        // disable ourself if there is no primary Memory manager available
044        if (InstanceManager.getNullableDefault(MemoryManager.class) == null) {
045            super.setEnabled(false);
046        }
047
048    }
049
050    public MemoryTableAction() {
051        this(Bundle.getMessage("TitleMemoryTable"));
052    }
053
054    /**
055     * Create the JTable DataModel, along with the changes for the specific case
056     * of Memory objects
057     */
058    @Override
059    protected void createModel() {
060        m = new MemoryTableDataModel(InstanceManager.getDefault(MemoryManager.class));
061    }
062
063    /** {@inheritDoc} */
064    @Override
065    protected void setTitle() {
066        f.setTitle(Bundle.getMessage("TitleMemoryTable"));
067    }
068
069    /** {@inheritDoc} */
070    @Override
071    protected String helpTarget() {
072        return "package.jmri.jmrit.beantable.MemoryTable";
073    }
074
075    JmriJFrame addFrame = null;
076    JTextField sysNameField = new JTextField(20);
077    JTextField userNameField = new JTextField(20);
078    JLabel sysNameLabel = new JLabel(Bundle.getMessage("LabelSystemName"));
079    JLabel userNameLabel = new JLabel(Bundle.getMessage("LabelUserName"));
080    SpinnerNumberModel rangeSpinner = new SpinnerNumberModel(1, 1, 100, 1); // maximum 100 items
081    JSpinner numberToAddSpinner = new JSpinner(rangeSpinner);
082    JCheckBox rangeBox = new JCheckBox(Bundle.getMessage("AddRangeBox"));
083    JCheckBox autoSystemNameBox = new JCheckBox(Bundle.getMessage("LabelAutoSysName"));
084    JLabel statusBarLabel = new JLabel(Bundle.getMessage("AddBeanStatusEnter"), JLabel.LEADING);
085    UserPreferencesManager p;
086
087    /** {@inheritDoc} */
088    @Override
089    protected void addPressed(ActionEvent e) {
090        p = InstanceManager.getDefault(UserPreferencesManager.class);
091        if (addFrame == null) {
092            addFrame = new JmriJFrame(Bundle.getMessage("TitleAddMemory"), false, true);
093            addFrame.addHelpMenu("package.jmri.jmrit.beantable.MemoryAddEdit", true);
094            addFrame.getContentPane().setLayout(new BoxLayout(addFrame.getContentPane(), BoxLayout.Y_AXIS));
095
096            ActionListener okListener = (ActionEvent e1) -> {
097                okPressed(e1);
098            };
099            ActionListener cancelListener = (ActionEvent e1) -> {
100                cancelPressed(e1);
101            };
102            AddNewBeanPanel anbp = new AddNewBeanPanel(sysNameField, userNameField, numberToAddSpinner, rangeBox, autoSystemNameBox, "ButtonCreate", okListener, cancelListener, statusBarLabel);
103            addFrame.add(anbp);
104            addFrame.getRootPane().setDefaultButton(anbp.ok);
105            addFrame.setEscapeKeyClosesWindow(true);
106            sysNameField.setToolTipText(Bundle.getMessage("SysNameToolTip", "M")); // override tooltip with bean specific letter
107        }
108        sysNameField.setBackground(Color.white);
109        // reset status bar text
110        statusBarLabel.setText(Bundle.getMessage("AddBeanStatusEnter"));
111        statusBarLabel.setForeground(Color.gray);
112        if (p.getSimplePreferenceState(systemNameAuto)) {
113            autoSystemNameBox.setSelected(true);
114        }
115        addFrame.pack();
116        addFrame.setVisible(true);
117    }
118
119    String systemNameAuto = this.getClass().getName() + ".AutoSystemName";
120
121    void cancelPressed(ActionEvent e) {
122        addFrame.setVisible(false);
123        addFrame.dispose();
124        addFrame = null;
125    }
126
127    void okPressed(ActionEvent e) {
128
129        int numberOfMemory = 1;
130
131        if (rangeBox.isSelected()) {
132            numberOfMemory = (Integer) numberToAddSpinner.getValue();
133        }
134
135        if (numberOfMemory >= 65) { // limited by JSpinnerModel to 100
136            if (JmriJOptionPane.showConfirmDialog(addFrame,
137                    Bundle.getMessage("WarnExcessBeans", Bundle.getMessage("Memories"), numberOfMemory),
138                    Bundle.getMessage("WarningTitle"),
139                    JmriJOptionPane.YES_NO_OPTION) != JmriJOptionPane.YES_OPTION) {
140                return;
141            }
142        }
143
144        String uName = NamedBean.normalizeUserName(userNameField.getText());
145        if (uName == null || uName.isEmpty()) {
146            uName = null;
147        }
148        String sName = sysNameField.getText();
149        // initial check for empty entry
150        if (sName.isEmpty() && !autoSystemNameBox.isSelected()) {
151            statusBarLabel.setText(Bundle.getMessage("WarningSysNameEmpty"));
152            statusBarLabel.setForeground(Color.red);
153            sysNameField.setBackground(Color.red);
154            return;
155        } else {
156            sysNameField.setBackground(Color.white);
157        }
158
159        // Add some entry pattern checking, before assembling sName and handing it to the memoryManager
160        String statusMessage = Bundle.getMessage("ItemCreateFeedback", Bundle.getMessage("BeanNameMemory"));
161        String errorMessage = null;
162        for (int x = 0; x < numberOfMemory; x++) {
163            if (uName != null && !uName.isEmpty()
164                && InstanceManager.getDefault(MemoryManager.class).getByUserName(uName) != null
165                && !p.getPreferenceState(getClassName(), "duplicateUserName")) {
166                InstanceManager.getDefault(UserPreferencesManager.class).
167                        showErrorMessage(Bundle.getMessage("ErrorTitle"), Bundle.getMessage("ErrorDuplicateUserName", uName), getClassName(), "duplicateUserName", false, true);
168                // show in status bar
169                errorMessage = Bundle.getMessage("ErrorDuplicateUserName", uName);
170                statusBarLabel.setText(errorMessage);
171                statusBarLabel.setForeground(Color.red);
172                uName = null; // new Memory objects always receive a valid system name using the next free index, but uName names must not be in use so use none in that case
173            }
174            if (!sName.isEmpty()
175                && InstanceManager.getDefault(MemoryManager.class).getBySystemName(sName) != null
176                && !p.getPreferenceState(getClassName(), "duplicateSystemName")) {
177                InstanceManager.getDefault(UserPreferencesManager.class).
178                        showErrorMessage(Bundle.getMessage("ErrorTitle"), Bundle.getMessage("ErrorDuplicateSystemName", sName), getClassName(), "duplicateSystemName", false, true);
179                // show in status bar
180                errorMessage = Bundle.getMessage("ErrorDuplicateSystemName", sName);
181                statusBarLabel.setText(errorMessage);
182                statusBarLabel.setForeground(Color.red);
183                return; // new Memory objects are always valid, but system names must not be in use so skip in that case
184            }
185            try {
186                if (autoSystemNameBox.isSelected()) {
187                    InstanceManager.getDefault(MemoryManager.class).newMemory(uName);
188                } else {
189                    InstanceManager.getDefault(MemoryManager.class).newMemory(sName, uName);
190                }
191            } catch (IllegalArgumentException ex) {
192                // uName input no good
193                handleCreateException(sName);
194                errorMessage = Bundle.getMessage("ErrorAddFailedCheck");
195                statusBarLabel.setText(errorMessage);
196                statusBarLabel.setForeground(Color.red);
197                return; // without creating
198            }
199
200            // add first and last names to statusMessage uName feedback string
201            // only mention first and last of rangeBox added
202            if (x == 0 || x == numberOfMemory - 1) {
203                statusMessage = statusMessage + " " + sName + " (" + uName + ")";
204            }
205            if (x == numberOfMemory - 2) {
206                statusMessage = statusMessage + " " + Bundle.getMessage("ItemCreateUpTo") + " ";
207            }
208
209            // bump system & uName names
210            if (!autoSystemNameBox.isSelected()) {
211                sName = nextName(sName);
212            }
213            if (uName != null) {
214                uName = nextName(uName);
215            }
216        } // end of for loop creating rangeBox of Memories
217
218        // provide feedback to uName
219        if (errorMessage == null) {
220            statusBarLabel.setText(statusMessage);
221            statusBarLabel.setForeground(Color.gray);
222        } else {
223            statusBarLabel.setText(errorMessage);
224            // statusBarLabel.setForeground(Color.red); // handled when errorMassage is set to differentiate urgency
225        }
226
227        p.setSimplePreferenceState(systemNameAuto, autoSystemNameBox.isSelected());
228    }
229
230    void handleCreateException(String sysName) {
231        JmriJOptionPane.showMessageDialog(addFrame,
232                Bundle.getMessage("ErrorMemoryAddFailed", sysName) + "\n" + Bundle.getMessage("ErrorAddFailedCheck"),
233                Bundle.getMessage("ErrorTitle"),
234                JmriJOptionPane.ERROR_MESSAGE);
235    }
236
237    /** {@inheritDoc} */
238    @Override
239    public String getClassDescription() {
240        return Bundle.getMessage("TitleMemoryTable");
241    }
242
243    @Override
244    public void setMessagePreferencesDetails() {
245        InstanceManager.getDefault(jmri.UserPreferencesManager.class).
246                setPreferenceItemDetails(getClassName(), "duplicateUserName", Bundle.getMessage("HideDupUserError"));  // NOI18N
247        InstanceManager.getDefault(jmri.UserPreferencesManager.class).
248                setPreferenceItemDetails(getClassName(), "duplicateSystemName", Bundle.getMessage("HideDupSysError"));  // NOI18N
249        super.setMessagePreferencesDetails();
250    }
251
252    /** {@inheritDoc} */
253    @Override
254    protected String getClassName() {
255        return MemoryTableAction.class.getName();
256    }
257
258    // private final static Logger log = LoggerFactory.getLogger(MemoryTableAction.class);
259
260}