001package jmri.jmrit.beantable;
002
003import java.awt.Container;
004import java.awt.FlowLayout;
005import java.awt.event.ItemEvent;
006import java.beans.PropertyVetoException;
007import java.util.List;
008import java.util.Map;
009
010import javax.annotation.Nonnull;
011import javax.swing.*;
012
013import jmri.*;
014import jmri.jmrit.logixng.*;
015import jmri.jmrit.logixng.SymbolTable.InitialValueType;
016import jmri.util.JmriJFrame;
017
018
019import jmri.jmrit.logixng.tools.swing.AbstractLogixNGEditor;
020import jmri.jmrit.logixng.tools.swing.LocalVariableTableModel;
021// import jmri.jmrit.logixng.tools.swing.GlobalVariableEditor;
022
023/**
024 * Swing action to create and register a LogixNG Global Variables Table.
025 * <p>
026 * Also contains the panes to create, edit, and delete a LogixNG Global Variable.
027 * <p>
028 * Most of the text used in this GUI is in BeanTableBundle.properties, accessed
029 * via Bundle.getMessage().
030 * <p>
031 *
032 * @author Dave Duchamp Copyright (C) 2007 (LogixTableAction)
033 * @author Pete Cressman Copyright (C) 2009, 2010, 2011 (LogixTableAction)
034 * @author Matthew Harris copyright (c) 2009 (LogixTableAction)
035 * @author Dave Sand copyright (c) 2017 (LogixTableAction)
036 * @author Daniel Bergqvist copyright (c) 2022
037 */
038public class LogixNGGlobalVariableTableAction extends AbstractLogixNGTableAction<GlobalVariable> {
039
040    /**
041     * Create a LogixNGGlobalVariablesTableAction instance.
042     *
043     * @param s the Action title, not the title of the resulting frame. Perhaps
044     *          this should be changed?
045     */
046    public LogixNGGlobalVariableTableAction(String s) {
047        super(s);
048    }
049
050    /**
051     * Create a LogixNGTableAction instance with default title.
052     */
053    public LogixNGGlobalVariableTableAction() {
054        this(Bundle.getMessage("TitleLogixNGGlobalVariablesTable"));
055    }
056
057    @Override
058    protected void setTitle() {
059        f.setTitle(Bundle.getMessage("TitleLogixNGGlobalVariablesTable"));
060    }
061
062    @Override
063    public String getClassDescription() {
064        return Bundle.getMessage("TitleLogixNGGlobalVariablesTable");        // NOI18N
065    }
066
067    @Override
068    protected AbstractLogixNGEditor<GlobalVariable> getEditor(BeanTableDataModel<GlobalVariable> m, String sName) {
069        return null;
070    }
071
072    @Override
073    protected boolean isEditSupported() {
074        return false;
075    }
076
077    @Override
078    protected Manager<GlobalVariable> getManager() {
079        return InstanceManager.getDefault(GlobalVariableManager.class);
080    }
081
082    @Override
083    public void setEnabled(GlobalVariable globalVariable, boolean enable) {
084    }
085
086    @Override
087    protected boolean isEnabled(GlobalVariable globalVariable) {
088        return true;
089    }
090
091    @Override
092    public void enableAll(boolean enable) {
093    }
094
095    @Override
096    protected GlobalVariable createBean(String userName) {
097        GlobalVariable globalVariable =
098                InstanceManager.getDefault(GlobalVariableManager.class)
099                        .createGlobalVariable(userName);
100        return globalVariable;
101    }
102
103    @Override
104    protected GlobalVariable createBean(String systemName, String userName) {
105        GlobalVariable globalVariable =
106                InstanceManager.getDefault(GlobalVariableManager.class)
107                        .createGlobalVariable(systemName, userName);
108        return globalVariable;
109    }
110
111    @Override
112    public void deleteBean(GlobalVariable globalVariable) {
113        try {
114            InstanceManager.getDefault(GlobalVariableManager.class).deleteBean(globalVariable, "DoDelete");
115        } catch (PropertyVetoException e) {
116            //At this stage the DoDelete shouldn't fail, as we have already done a can delete, which would trigger a veto
117            log.error("{} : Could not Delete.", e.getMessage());
118        }
119    }
120/*
121    @Override
122    protected void copyBean(@Nonnull LogixNG sourceBean, @Nonnull LogixNG targetBean) {
123        for (int i = 0; i < sourceBean.getNumConditionalNGs(); i++) {
124            copyConditionalNGToLogixNG(sourceBean.getConditionalNG(i), targetBean);
125        }
126    }
127*/
128    @Override
129    protected boolean isCopyBeanSupported() {
130        return false;
131    }
132
133    @SuppressWarnings("unchecked")  // Checked cast is not possible due to type erasure
134    @Override
135    protected String getBeanText(GlobalVariable e) {
136        var content = new StringBuilder(Bundle.getMessage("LogixNG_GlobalVar_Browse_Header",
137                e.getSystemName(),
138                e.getUserName(),
139                e.getInitialValueType()));
140        content.append(Bundle.getMessage("LogixNG_GlobalVar_Browse_Value"));
141        var value = e.getValue();
142
143        if (value instanceof Map) {
144            var map = ((Map<? extends Object, ? extends Object>)value);
145            for (var entry : map.entrySet()) {
146                var line = String.format("%n        %s -> %s",
147                        entry.getKey(),
148                        entry.getValue());
149                content.append(line);
150            }
151        } else if (value instanceof List) {
152            var list = ((List<? extends Object>)value);
153            for (int i=0; i < list.size(); i++) {
154                var line = String.format("%n        %s", list.get(i));
155                content.append(line);
156            }
157        } else {
158            content.append(value);
159        }
160        return content.toString();
161    }
162
163    @Override
164    protected String getBrowserTitle() {
165        return Bundle.getMessage("LogixNG_GlobalVar_Browse_Title");
166    }
167
168    @Override
169    protected String getAddTitleKey() {
170        return "TitleAddLogixNGGlobalVariable";
171    }
172
173    @Override
174    protected String getCreateButtonHintKey() {
175        return "LogixNGCreateGlobalVariableButtonHint";
176    }
177
178    /**
179     * Create or copy bean frame.
180     *
181     * @param titleId   property key to fetch as title of the frame (using Bundle)
182     * @param startMessageId part 1 of property key to fetch as user instruction on
183     *                  pane, either 1 or 2 is added to form the whole key
184     * @return the button JPanel
185     */
186    @Override
187    protected JPanel makeAddFrame(String titleId, String startMessageId) {
188        addLogixNGFrame = new JmriJFrame(Bundle.getMessage(titleId));
189//        addLogixNGFrame.addHelpMenu(
190//                "package.jmri.jmrit.beantable.LogixNGGlobalVariableTable", true);     // NOI18N
191        addLogixNGFrame.setLocation(50, 30);
192        Container contentPane = addLogixNGFrame.getContentPane();
193        contentPane.setLayout(new BoxLayout(contentPane, BoxLayout.Y_AXIS));
194
195        JPanel p;
196        p = new JPanel();
197        p.setLayout(new FlowLayout());
198        p.setLayout(new java.awt.GridBagLayout());
199        java.awt.GridBagConstraints c = new java.awt.GridBagConstraints();
200        c.gridwidth = 1;
201        c.gridheight = 1;
202        c.gridx = 0;
203        c.gridy = 0;
204        c.anchor = java.awt.GridBagConstraints.EAST;
205        p.add(_sysNameLabel, c);
206        _sysNameLabel.setLabelFor(_systemName);
207        c.gridy = 1;
208        p.add(_userNameLabel, c);
209        _userNameLabel.setLabelFor(_addUserName);
210        c.gridx = 1;
211        c.gridy = 0;
212        c.anchor = java.awt.GridBagConstraints.WEST;
213        c.weightx = 1.0;
214        c.fill = java.awt.GridBagConstraints.HORIZONTAL;  // text field will expand
215        p.add(_systemName, c);
216        c.gridy = 1;
217        p.add(_addUserName, c);
218        c.gridx = 2;
219        c.gridy = 1;
220        c.anchor = java.awt.GridBagConstraints.WEST;
221        c.weightx = 1.0;
222        c.fill = java.awt.GridBagConstraints.HORIZONTAL;  // text field will expand
223        c.gridy = 0;
224        p.add(_autoSystemName, c);
225        _addUserName.setToolTipText(Bundle.getMessage("LogixNGGlobalVariableUserNameHint"));    // NOI18N
226        _systemName.setToolTipText(Bundle.getMessage("LogixNGGlobalVariableSystemNameHint"));   // NOI18N
227        contentPane.add(p);
228        // set up message
229        JPanel panel3 = new JPanel();
230        panel3.setLayout(new BoxLayout(panel3, BoxLayout.Y_AXIS));
231        JPanel panel31 = new JPanel();
232        panel31.setLayout(new FlowLayout());
233        JLabel message1 = new JLabel(Bundle.getMessage(startMessageId + "LogixNGMessage1"));  // NOI18N
234        panel31.add(message1);
235        JPanel panel32 = new JPanel();
236        JLabel message2 = new JLabel(Bundle.getMessage(startMessageId + "LogixNGMessage2"));  // NOI18N
237        panel32.add(message2);
238        panel3.add(panel31);
239        panel3.add(panel32);
240        contentPane.add(panel3);
241
242        // set up create and cancel buttons
243        JPanel panel5 = new JPanel();
244        panel5.setLayout(new FlowLayout());
245        // Cancel
246        JButton cancel = new JButton(Bundle.getMessage("ButtonCancel"));    // NOI18N
247        panel5.add(cancel);
248        cancel.addActionListener(this::cancelAddPressed);
249        cancel.setToolTipText(Bundle.getMessage("CancelLogixNGGlobalVariableButtonHint"));      // NOI18N
250
251        addLogixNGFrame.addWindowListener(new java.awt.event.WindowAdapter() {
252            @Override
253            public void windowClosing(java.awt.event.WindowEvent e) {
254                cancelAddPressed(null);
255            }
256        });
257        contentPane.add(panel5);
258
259        _autoSystemName.addItemListener((ItemEvent e) -> {
260            autoSystemName();
261        });
262        return panel5;
263    }
264
265    @Override
266    protected void getListenerRefsIncludingChildren(GlobalVariable globalVariable, java.util.List<String> list) {
267        globalVariable.getListenerRefsIncludingChildren(list);
268    }
269
270    @Override
271    protected boolean hasChildren(GlobalVariable globalVariable) {
272        return false;
273    }
274
275    /**
276     * Create the JTable DataModel, along with the changes (overrides of
277     * BeanTableDataModel) for the specific case of a LogixNG table.
278     */
279    @Override
280    protected void createModel() {
281        m = new TableModel();
282    }
283
284    @Override
285    public void addToFrame(@Nonnull BeanTableFrame<GlobalVariable> f) {
286        f.addToBottomBox(new JLabel(Bundle.getMessage("LogixNGGlobalVariable_InfoAboutGlobalVariables")), null);
287    }
288
289    @Override
290    public void addToFrame(@Nonnull ListedTableFrame.TabbedTableItem<GlobalVariable> tti) {
291        tti.addToBottomBox(new JLabel(Bundle.getMessage("LogixNGGlobalVariable_InfoAboutGlobalVariables")));
292    }
293
294
295    protected class TableModel extends AbstractLogixNGTableAction<GlobalVariable>.TableModel {
296
297        // overlay the state column with the edit column
298        static private final int VARIABLE_TYPE_COL = NUMCOLUMN;
299        static private final int VARIABLE_INIT_VALUE_COL = NUMCOLUMN + 1;
300        static private final int SET_TO_INIT_VALUE_COL = VARIABLE_INIT_VALUE_COL + 1;
301        static private final int NUM_COLUMNS = SET_TO_INIT_VALUE_COL + 1;
302
303        @Override
304        protected boolean isClearUserNameAllowed() {
305            return false;
306        }
307
308        @Override
309        public int getColumnCount() {
310            return NUM_COLUMNS;
311        }
312
313        @Override
314        public String getColumnName(int col) {
315            switch (col) {
316                case VARIABLE_TYPE_COL:
317                    return Bundle.getMessage("LogixNGGlobalVariableColumnHeadInitialType");
318                case VARIABLE_INIT_VALUE_COL:
319                    return Bundle.getMessage("LogixNGGlobalVariableColumnHeadInitialValue");
320                case SET_TO_INIT_VALUE_COL:
321                    return Bundle.getMessage("LogixNGGlobalVariableColumnHeadSetToInitValue");
322                default:
323                    return super.getColumnName(col);
324            }
325        }
326
327        @Override
328        public Class<?> getColumnClass(int col) {
329            switch (col) {
330                case VARIABLE_TYPE_COL:
331                    return InitialValueType.class;
332                case VARIABLE_INIT_VALUE_COL:
333                    return String.class;
334                case SET_TO_INIT_VALUE_COL:
335                    return JButton.class;
336                default:
337                    return super.getColumnClass(col);
338            }
339        }
340
341        @Override
342        public int getPreferredWidth(int col) {
343            switch (col) {
344                case VARIABLE_TYPE_COL:
345                    return new JTextField(12).getPreferredSize().width;
346                case VARIABLE_INIT_VALUE_COL:
347                    return new JTextField(17).getPreferredSize().width;
348                case SET_TO_INIT_VALUE_COL:
349                    return new JButton(Bundle.getMessage(
350                            "LogixNGGlobalVariableColumnHeadSetToInitValue"))
351                            .getPreferredSize().width;
352                default:
353                    return super.getPreferredWidth(col);
354            }
355        }
356
357        @Override
358        public boolean isCellEditable(int row, int col) {
359            switch (col) {
360                case VARIABLE_TYPE_COL:
361                case VARIABLE_INIT_VALUE_COL:
362                case SET_TO_INIT_VALUE_COL:
363                    return true;
364                default:
365                    return super.isCellEditable(row, col);
366            }
367        }
368
369        @Override
370        public Object getValueAt(int row, int col) {
371            GlobalVariable gv;
372            switch (col) {
373                case VARIABLE_TYPE_COL:
374                    gv = (GlobalVariable) getValueAt(row, SYSNAMECOL);
375                    if (gv == null) { return null; }     // Error
376                    return gv.getInitialValueType();
377
378                case VARIABLE_INIT_VALUE_COL:
379                    gv = (GlobalVariable) getValueAt(row, SYSNAMECOL);
380                    if (gv == null) { return null; }     // Error
381                    return gv.getInitialValueData();
382
383                case SET_TO_INIT_VALUE_COL:
384                    return Bundle.getMessage(
385                            "LogixNGGlobalVariableColumnHeadSetToInitValue");
386
387                default:
388                    return super.getValueAt(row, col);
389            }
390        }
391
392        @SuppressWarnings("unchecked")  // Unchecked cast from Object to E
393        @Override
394        public void setValueAt(Object value, int row, int col) {
395            GlobalVariable gv;
396            switch (col) {
397                case VARIABLE_TYPE_COL:
398                    gv = (GlobalVariable) getValueAt(row, SYSNAMECOL);
399                    gv.setInitialValueType((InitialValueType) value);
400                    break;
401
402                case VARIABLE_INIT_VALUE_COL:
403                    gv = (GlobalVariable) getValueAt(row, SYSNAMECOL);
404                    gv.setInitialValueData((String) value);
405                    break;
406
407                case SET_TO_INIT_VALUE_COL:
408                    gv = (GlobalVariable) getValueAt(row, SYSNAMECOL);
409                    try {
410                        gv.initialize();
411                    } catch (JmriException | RuntimeException e) {
412                        JOptionPane.showMessageDialog(null,
413                                e.getLocalizedMessage(),
414                                Bundle.getMessage("ErrorTitle"), // NOI18N
415                                JOptionPane.ERROR_MESSAGE);
416                    }
417                    break;
418
419                default:
420                    super.setValueAt(value, row, col);
421                    break;
422            }
423        }
424
425        @Override
426        public void configureTable(JTable table) {
427            table.setDefaultRenderer(InitialValueType.class,
428                    new LocalVariableTableModel.TypeCellRenderer());
429            table.setDefaultEditor(InitialValueType.class,
430                    new LocalVariableTableModel.TypeCellEditor());
431
432            super.configureTable(table);
433        }
434    }
435
436
437    private final static org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(LogixNGGlobalVariableTableAction.class);
438
439}