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