001package jmri.jmrit.logixng.tools.swing;
002
003import java.awt.*;
004import java.awt.event.*;
005import java.util.*;
006
007import javax.swing.*;
008import javax.swing.table.AbstractTableModel;
009import javax.swing.table.TableCellEditor;
010import javax.swing.table.TableColumn;
011import javax.swing.table.TableColumnModel;
012
013import jmri.jmrit.logixng.*;
014import jmri.jmrit.logixng.util.LogixNG_Thread;
015import jmri.util.swing.JmriJOptionPane;
016import jmri.util.table.ButtonEditor;
017import jmri.util.table.ButtonRenderer;
018
019/**
020 *
021 * @author Daniel Bergqvist 2020
022 */
023public class EditThreadsDialog {
024    
025    private final ConditionalNG _conditionalNG;
026    private JDialog _editThreadsDialog;
027    private LogixNG_Thread _newStartupThread;
028    private JLabel _startupThreadNameLabel;
029    ThreadTableModel _threadTableModel = null;
030    
031    
032    public EditThreadsDialog(ConditionalNG conditionalNG) {
033        // Ensure that the predefined threads exist
034        LogixNG_Thread.getThread(LogixNG_Thread.DEFAULT_LOGIXNG_THREAD);
035        LogixNG_Thread.getThread(LogixNG_Thread.DEFAULT_LOGIXNG_DEBUG_THREAD);
036        
037        _conditionalNG = conditionalNG;
038        _newStartupThread = LogixNG_Thread.getThread(_conditionalNG.getStartupThreadId());
039    }
040    
041    public void showDialog() {
042        
043        _editThreadsDialog  = new JDialog(
044                (JDialog)null,
045                Bundle.getMessage("EditThreadsDialog_Title"),
046                true);
047        
048        
049        Container contentPane = _editThreadsDialog.getContentPane();
050        contentPane.setLayout(new BoxLayout(contentPane, BoxLayout.Y_AXIS));
051        
052        _startupThreadNameLabel = new JLabel(Bundle.getMessage(
053                "EditThreadsDialog_StartupThreadName",
054                _newStartupThread.getThreadName()));
055        contentPane.add(_startupThreadNameLabel);
056        
057        _threadTableModel = new ThreadTableModel();
058        JTable conditionalTable = new JTable(_threadTableModel);
059        conditionalTable.setRowSelectionAllowed(false);
060        TableColumnModel conditionalColumnModel = conditionalTable
061                .getColumnModel();
062        TableColumn sNameColumn = conditionalColumnModel
063                .getColumn(ThreadTableModel.THREAD_ID_COLUMN);
064        sNameColumn.setResizable(true);
065        sNameColumn.setMinWidth(100);
066        sNameColumn.setPreferredWidth(130);
067        TableColumn uNameColumn = conditionalColumnModel
068                .getColumn(ThreadTableModel.THREAD_NAME_COLUMN);
069        uNameColumn.setResizable(true);
070        uNameColumn.setMinWidth(210);
071        uNameColumn.setPreferredWidth(260);
072        TableColumn buttonColumn = conditionalColumnModel
073                .getColumn(ThreadTableModel.BUTTON_SELECT_THREAD_COLUMN);
074        TableColumn buttonDeleteColumn = conditionalColumnModel
075                .getColumn(ThreadTableModel.BUTTON_DELETE_COLUMN);
076
077        // install button renderer and editor
078        ButtonRenderer buttonRenderer = new ButtonRenderer();
079        conditionalTable.setDefaultRenderer(JButton.class, buttonRenderer);
080        TableCellEditor buttonEditor = new ButtonEditor(new JButton());
081        conditionalTable.setDefaultEditor(JButton.class, buttonEditor);
082        JButton testButton = new JButton("XXXXXX");  // NOI18N
083        conditionalTable.setRowHeight(testButton.getPreferredSize().height);
084        buttonColumn.setMinWidth(testButton.getPreferredSize().width);
085        buttonColumn.setMaxWidth(testButton.getPreferredSize().width);
086        buttonColumn.setResizable(false);
087        buttonDeleteColumn.setMinWidth(testButton.getPreferredSize().width);
088        buttonDeleteColumn.setMaxWidth(testButton.getPreferredSize().width);
089        buttonDeleteColumn.setResizable(false);
090
091        JScrollPane conditionalTableScrollPane = new JScrollPane(conditionalTable);
092        Dimension dim = conditionalTable.getPreferredSize();
093        dim.height = 450;
094        conditionalTableScrollPane.getViewport().setPreferredSize(dim);
095        contentPane.add(conditionalTableScrollPane);
096        
097        // set up message
098        JPanel panel3 = new JPanel();
099        panel3.setLayout(new BoxLayout(panel3, BoxLayout.Y_AXIS));
100        
101        contentPane.add(panel3);
102
103        // set up create and cancel buttons
104        JPanel panel5 = new JPanel();
105        panel5.setLayout(new FlowLayout());
106        
107        // Add thread
108        JButton addThread = new JButton(Bundle.getMessage("EditThreadsDialog_ButtonAddThread"));    // NOI18N
109        panel5.add(addThread);
110        addThread.addActionListener((ActionEvent e) -> {
111            String newName = "";
112            if (! LogixNG_Thread.validateNewThreadName(newName)) {
113                JmriJOptionPane.showMessageDialog(null,
114                        Bundle.getMessage("EditThreadsDialog_ErrorThreadNameAlreadyExists", newName),
115                        Bundle.getMessage("EditThreadsDialog_ErrorTitle"),
116                        JmriJOptionPane.ERROR_MESSAGE);
117                return;
118            }
119            LogixNG_Thread thread = LogixNG_Thread.createNewThread(newName);
120            int row = _threadTableModel._threads.size();
121            _threadTableModel._threads.add(thread);
122            _threadTableModel.fireTableRowsInserted(row, row);
123        });
124//        addThread.setToolTipText(Bundle.getMessage("CancelLogixButtonHint"));      // NOI18N
125        
126        // Cancel
127        JButton cancel = new JButton(Bundle.getMessage("ButtonCancel"));    // NOI18N
128        panel5.add(cancel);
129        cancel.addActionListener((ActionEvent e) -> {
130            abortPressed();
131        });
132//        cancel.setToolTipText(Bundle.getMessage("CancelLogixButtonHint"));      // NOI18N
133        
134        // OK
135        JButton ok = new JButton(Bundle.getMessage("ButtonOK"));    // NOI18N
136        panel5.add(ok);
137        ok.addActionListener((ActionEvent e) -> {
138            okPressed();
139        });
140//        ok.setToolTipText(Bundle.getMessage("OKLogixButtonHint"));      // NOI18N
141        
142        _editThreadsDialog.addWindowListener(new java.awt.event.WindowAdapter() {
143            @Override
144            public void windowClosing(java.awt.event.WindowEvent e) {
145                abortPressed();
146            }
147        });
148/*        
149        _create = new JButton(Bundle.getMessage("ButtonCreate"));  // NOI18N
150        panel5.add(_create);
151        _create.addActionListener((ActionEvent e) -> {
152            cancelAddPressed(null);
153            
154            SwingConfiguratorInterface swingConfiguratorInterface =
155                    _swingConfiguratorComboBox.getItemAt(_swingConfiguratorComboBox.getSelectedIndex());
156//            System.err.format("swingConfiguratorInterface: %s%n", swingConfiguratorInterface.getClass().getName());
157            createAddFrame(femaleSocket, path, swingConfiguratorInterface);
158        });
159*/        
160        contentPane.add(panel5);
161        
162//        addLogixNGFrame.setLocationRelativeTo(component);
163        _editThreadsDialog.setLocationRelativeTo(null);
164        _editThreadsDialog.pack();
165        _editThreadsDialog.setVisible(true);
166    }
167    
168    private void abortPressed() {
169        _editThreadsDialog.setVisible(false);
170        _editThreadsDialog.dispose();
171        _editThreadsDialog = null;
172    }
173    
174    private void okPressed() {
175        _editThreadsDialog.setVisible(false);
176        _editThreadsDialog.dispose();
177        _editThreadsDialog = null;
178        _conditionalNG.setStartupThreadId(_newStartupThread.getThreadId());
179    }
180    
181    
182    
183    
184    
185    
186    
187    
188    
189    // ------------ Table Models ------------
190
191    /**
192     * Table model for ConditionalNGs in the Edit LogixNG pane.
193     */
194    private final class ThreadTableModel extends AbstractTableModel {
195
196        public static final int THREAD_ID_COLUMN = 0;
197        public static final int THREAD_NAME_COLUMN = THREAD_ID_COLUMN + 1;
198        public static final int BUTTON_SELECT_THREAD_COLUMN = THREAD_NAME_COLUMN + 1;
199        public static final int BUTTON_DELETE_COLUMN = BUTTON_SELECT_THREAD_COLUMN + 1;
200        public static final int NUM_COLUMNS = BUTTON_DELETE_COLUMN + 1;
201        
202        private final java.util.List<LogixNG_Thread> _threads;
203        
204        
205        public ThreadTableModel() {
206            super();
207            _threads = new ArrayList<>(LogixNG_Thread.getThreads());
208        }
209
210        @Override
211        public Class<?> getColumnClass(int c) {
212            if ((c == BUTTON_SELECT_THREAD_COLUMN) || (c == BUTTON_DELETE_COLUMN)) {
213                return JButton.class;
214            } else if (c == THREAD_ID_COLUMN) {
215                return Integer.class;
216            }
217            return String.class;
218        }
219
220        @Override
221        public int getColumnCount() {
222            return NUM_COLUMNS;
223        }
224
225        @Override
226        public int getRowCount() {
227            return _threads.size();
228        }
229
230        @Override
231        public boolean isCellEditable(int r, int c) {
232            if ((c == THREAD_NAME_COLUMN) || (c == BUTTON_SELECT_THREAD_COLUMN)) {
233                return true;
234            }
235            return ((c == BUTTON_DELETE_COLUMN) && (! _threads.get(r).getThreadInUse()));
236        }
237
238        @Override
239        public String getColumnName(int col) {
240            switch (col) {
241                case THREAD_ID_COLUMN:
242                    return Bundle.getMessage("ColumnSystemName");  // NOI18N
243                case THREAD_NAME_COLUMN:
244                    return Bundle.getMessage("ColumnUserName");  // NOI18N
245                case BUTTON_SELECT_THREAD_COLUMN:
246                    return ""; // no label
247                case BUTTON_DELETE_COLUMN:
248                    return ""; // no label
249                default:
250                    throw new IllegalArgumentException("Unknown column");
251            }
252        }
253
254        @edu.umd.cs.findbugs.annotations.SuppressFBWarnings(value = "DB_DUPLICATE_SWITCH_CLAUSES",
255                justification = "better to keep cases in column order rather than to combine")
256        public int getPreferredWidth(int col) {
257            switch (col) {
258                case THREAD_ID_COLUMN:
259                    return new JTextField(6).getPreferredSize().width;
260                case THREAD_NAME_COLUMN:
261                    return new JTextField(17).getPreferredSize().width;
262                case BUTTON_SELECT_THREAD_COLUMN:
263                    return new JTextField(6).getPreferredSize().width;
264                case BUTTON_DELETE_COLUMN:
265                    return new JTextField(6).getPreferredSize().width;
266                default:
267                    throw new IllegalArgumentException("Unknown column");
268            }
269        }
270
271        @Override
272        public Object getValueAt(int row, int col) {
273            if (row > _threads.size()) {
274                return null;
275            }
276            switch (col) {
277                case BUTTON_SELECT_THREAD_COLUMN:
278                    return Bundle.getMessage("EditThreadsDialog_ButtonSelectThread");  // NOI18N
279                case BUTTON_DELETE_COLUMN:
280                    return Bundle.getMessage("ButtonDelete");  // NOI18N
281                case THREAD_ID_COLUMN:
282                    return _threads.get(row).getThreadId();
283                case THREAD_NAME_COLUMN: {
284                    return _threads.get(row).getThreadName();
285                }
286                default:
287                    throw new IllegalArgumentException("Unknown column");
288            }
289        }
290
291        private void deleteThread(int row) {
292            LogixNG_Thread thread = _threads.get(row);
293            LogixNG_Thread.deleteThread(thread);
294            fireTableRowsDeleted(row, row);
295        }
296        
297        private void changeThreadName(Object value, int row) {
298            String name = (String) value;
299            LogixNG_Thread thread = _threads.get(row);
300            if (!thread.getThreadName().equals(name)) {
301                if (! LogixNG_Thread.validateNewThreadName(name)) {
302                    JmriJOptionPane.showMessageDialog(null,
303                            Bundle.getMessage("EditThreadsDialog_ErrorThreadNameAlreadyExists", name),
304                            Bundle.getMessage("EditThreadsDialog_ErrorTitle"),
305                            JmriJOptionPane.ERROR_MESSAGE);
306                    return;
307                }
308                thread.setThreadName(name);
309                fireTableRowsUpdated(row, row);
310            }
311        }
312        
313        @Override
314        public void setValueAt(Object value, int row, int col) {
315            if (row > _threads.size()) {
316                return;
317            }
318            switch (col) {
319                case BUTTON_SELECT_THREAD_COLUMN:
320                    _newStartupThread = _threads.get(row);
321                    _startupThreadNameLabel.setText(Bundle.getMessage(
322                            "EditThreadsDialog_StartupThreadName",
323                            _newStartupThread.getThreadName()));
324                    break;
325                case BUTTON_DELETE_COLUMN:
326                    deleteThread(row);
327                    break;
328                case THREAD_ID_COLUMN:
329                    throw new IllegalArgumentException("Thread ID cannot be changed");
330                case THREAD_NAME_COLUMN: {
331                    changeThreadName(value, row);
332                    break;
333                }
334                default:
335                    throw new IllegalArgumentException("Unknown column");
336            }
337        }
338    }
339    
340    
341    
342}