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("LogixNG_CancelButtonHint")); // 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("LogixNG_CancelButtonHint")); // 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}