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}