001package jmri.jmrit.logixng.actions.swing; 002 003import java.awt.event.ActionEvent; 004import java.util.List; 005 006import javax.annotation.CheckForNull; 007import javax.annotation.Nonnull; 008import javax.swing.*; 009 010import jmri.InstanceManager; 011import jmri.jmrit.logixng.*; 012import jmri.jmrit.logixng.actions.ActionScript; 013import jmri.jmrit.logixng.swing.SwingConfiguratorInterface; 014import jmri.jmrit.logixng.util.parser.ParserException; 015import jmri.script.ScriptEngineSelector; 016import jmri.script.swing.ScriptEngineSelectorSwing; 017import jmri.script.swing.ScriptFileChooser; 018import jmri.util.FileUtil; 019import jmri.util.swing.JComboBoxUtil; 020 021/** 022 * Configures an ActionScript object with a Swing JPanel. 023 * 024 * @author Daniel Bergqvist 2021 025 */ 026public class ActionScriptSwing extends AbstractDigitalActionSwing { 027 028 public static final int NUM_COLUMNS_TEXT_FIELDS = 20; 029 030 private JTabbedPane _tabbedPaneOperationType; 031 private JPanel _panelOperationTypeDirect; 032 private JPanel _panelOperationTypeReference; 033 private JPanel _panelOperationTypeLocalVariable; 034 private JPanel _panelOperationTypeFormula; 035 036 private JComboBox<ActionScript.OperationType> _operationComboBox; 037 private JTextField _scriptOperationReferenceTextField; 038 private JTextField _scriptOperationLocalVariableTextField; 039 private JTextField _scriptOperationFormulaTextField; 040 041 private JTabbedPane _tabbedPaneScriptType; 042 private JPanel _panelScriptTypeDirect; 043 private JPanel _panelScriptTypeReference; 044 private JPanel _panelScriptTypeLocalVariable; 045 private JPanel _panelScriptTypeFormula; 046 047 private ScriptFileChooser scriptFileChooser; 048 private JTextField _scriptTextField; 049 private JTextField _scriptReferenceTextField; 050 private JTextField _scriptLocalVariableTextField; 051 private JTextField _scriptFormulaTextField; 052 053 private ScriptEngineSelectorSwing _scriptEngineSelectorSwing; 054 055 056 @Override 057 protected void createPanel(@CheckForNull Base object, @Nonnull JPanel buttonPanel) { 058 ActionScript action = (ActionScript)object; 059 060 if (action != null) { 061 _scriptEngineSelectorSwing = new ScriptEngineSelectorSwing(action.getScriptEngineSelector()); 062 } else { 063 _scriptEngineSelectorSwing = new ScriptEngineSelectorSwing(new ScriptEngineSelector()); 064 } 065 066 panel = new JPanel(); 067 panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS)); 068 069 JPanel actionPanel = new JPanel(); 070 071 072 // Set up the tabbed pane for selecting the operation 073 _tabbedPaneOperationType = new JTabbedPane(); 074 _panelOperationTypeDirect = new javax.swing.JPanel(); 075 _panelOperationTypeDirect.setLayout(new BoxLayout(_panelOperationTypeDirect, BoxLayout.Y_AXIS)); 076 _panelOperationTypeReference = new javax.swing.JPanel(); 077 _panelOperationTypeReference.setLayout(new BoxLayout(_panelOperationTypeReference, BoxLayout.Y_AXIS)); 078 _panelOperationTypeLocalVariable = new javax.swing.JPanel(); 079 _panelOperationTypeLocalVariable.setLayout(new BoxLayout(_panelOperationTypeLocalVariable, BoxLayout.Y_AXIS)); 080 _panelOperationTypeFormula = new javax.swing.JPanel(); 081 _panelOperationTypeFormula.setLayout(new BoxLayout(_panelOperationTypeFormula, BoxLayout.Y_AXIS)); 082 083 _tabbedPaneOperationType.addTab(NamedBeanAddressing.Direct.toString(), _panelOperationTypeDirect); 084 _tabbedPaneOperationType.addTab(NamedBeanAddressing.Reference.toString(), _panelOperationTypeReference); 085 _tabbedPaneOperationType.addTab(NamedBeanAddressing.LocalVariable.toString(), _panelOperationTypeLocalVariable); 086 _tabbedPaneOperationType.addTab(NamedBeanAddressing.Formula.toString(), _panelOperationTypeFormula); 087 088 _operationComboBox = new JComboBox<>(); 089 for (ActionScript.OperationType e : ActionScript.OperationType.values()) { 090 _operationComboBox.addItem(e); 091 } 092 JComboBoxUtil.setupComboBoxMaxRows(_operationComboBox); 093 _panelOperationTypeDirect.add(new JLabel(Bundle.getMessage("ActionScript_Operation"))); 094 _panelOperationTypeDirect.add(_operationComboBox); 095 096 _scriptOperationReferenceTextField = new JTextField(); 097 _scriptOperationReferenceTextField.setColumns(NUM_COLUMNS_TEXT_FIELDS); 098 _panelOperationTypeReference.add(new JLabel(Bundle.getMessage("ActionScript_Operation"))); 099 _panelOperationTypeReference.add(_scriptOperationReferenceTextField); 100 101 _scriptOperationLocalVariableTextField = new JTextField(); 102 _scriptOperationLocalVariableTextField.setColumns(NUM_COLUMNS_TEXT_FIELDS); 103 _panelOperationTypeLocalVariable.add(new JLabel(Bundle.getMessage("ActionScript_Operation"))); 104 _panelOperationTypeLocalVariable.add(_scriptOperationLocalVariableTextField); 105 106 _scriptOperationFormulaTextField = new JTextField(); 107 _scriptOperationFormulaTextField.setColumns(NUM_COLUMNS_TEXT_FIELDS); 108 _panelOperationTypeFormula.add(new JLabel(Bundle.getMessage("ActionScript_Operation"))); 109 _panelOperationTypeFormula.add(_scriptOperationFormulaTextField); 110 111 112 // Set up the tabbed pane for selecting the appearance 113 _tabbedPaneScriptType = new JTabbedPane(); 114 _panelScriptTypeDirect = new javax.swing.JPanel(); 115// _panelScriptTypeDirect.setLayout(new BoxLayout(_panelScriptTypeDirect, BoxLayout.Y_AXIS)); 116 _panelScriptTypeReference = new javax.swing.JPanel(); 117 _panelScriptTypeReference.setLayout(new BoxLayout(_panelScriptTypeReference, BoxLayout.Y_AXIS)); 118 _panelScriptTypeLocalVariable = new javax.swing.JPanel(); 119 _panelScriptTypeLocalVariable.setLayout(new BoxLayout(_panelScriptTypeLocalVariable, BoxLayout.Y_AXIS)); 120 _panelScriptTypeFormula = new javax.swing.JPanel(); 121 _panelScriptTypeFormula.setLayout(new BoxLayout(_panelScriptTypeFormula, BoxLayout.Y_AXIS)); 122 123 _tabbedPaneScriptType.addTab(NamedBeanAddressing.Direct.toString(), _panelScriptTypeDirect); 124 _tabbedPaneScriptType.addTab(NamedBeanAddressing.Reference.toString(), _panelScriptTypeReference); 125 _tabbedPaneScriptType.addTab(NamedBeanAddressing.LocalVariable.toString(), _panelScriptTypeLocalVariable); 126 _tabbedPaneScriptType.addTab(NamedBeanAddressing.Formula.toString(), _panelScriptTypeFormula); 127 128 JButton _actionSelectFileButton = new JButton("..."); // "File" replaced by ... 129 _actionSelectFileButton.setMaximumSize(_actionSelectFileButton.getPreferredSize()); 130 _actionSelectFileButton.setToolTipText(Bundle.getMessage("FileButtonHint")); // NOI18N 131 _actionSelectFileButton.addActionListener((ActionEvent e) -> { 132 scriptFileChooser = new ScriptFileChooser(FileUtil.getScriptsPath()); 133 scriptFileChooser.rescanCurrentDirectory(); 134 int retVal = scriptFileChooser.showOpenDialog(null); 135 // handle selection or cancel 136 if (retVal == JFileChooser.APPROVE_OPTION) { 137 // set selected file location 138 try { 139 _scriptTextField.setText(FileUtil.getPortableFilename(scriptFileChooser.getSelectedFile().getCanonicalPath())); 140 } catch (java.io.IOException ex) { 141 log.error("exception setting file location", ex); // NOI18N 142 _scriptTextField.setText(""); 143 } 144 } 145 }); 146 _panelScriptTypeDirect.add(_actionSelectFileButton); 147 JPanel _scriptTextPanel = new JPanel(); 148 _scriptTextPanel.setLayout(new BoxLayout(_scriptTextPanel, BoxLayout.Y_AXIS)); 149 _scriptTextField = new JTextField(30); 150 _scriptTextPanel.add(new JLabel(Bundle.getMessage("ActionScript_Script"))); 151 _scriptTextPanel.add(_scriptTextField); 152 _panelScriptTypeDirect.add(_scriptTextPanel); 153 154 _scriptReferenceTextField = new JTextField(); 155 _scriptReferenceTextField.setColumns(NUM_COLUMNS_TEXT_FIELDS); 156 _panelScriptTypeReference.add(new JLabel(Bundle.getMessage("ActionScript_Script"))); 157 _panelScriptTypeReference.add(_scriptReferenceTextField); 158 159 _scriptLocalVariableTextField = new JTextField(); 160 _scriptLocalVariableTextField.setColumns(NUM_COLUMNS_TEXT_FIELDS); 161 _panelScriptTypeLocalVariable.add(new JLabel(Bundle.getMessage("ActionScript_Script"))); 162 _panelScriptTypeLocalVariable.add(_scriptLocalVariableTextField); 163 164 _scriptFormulaTextField = new JTextField(); 165 _scriptFormulaTextField.setColumns(NUM_COLUMNS_TEXT_FIELDS); 166 _panelScriptTypeFormula.add(new JLabel(Bundle.getMessage("ActionScript_Script"))); 167 _panelScriptTypeFormula.add(_scriptFormulaTextField); 168 169 170 if (action != null) { 171 switch (action.getOperationAddressing()) { 172 case Direct: _tabbedPaneOperationType.setSelectedComponent(_panelOperationTypeDirect); break; 173 case Reference: _tabbedPaneOperationType.setSelectedComponent(_panelOperationTypeReference); break; 174 case LocalVariable: _tabbedPaneOperationType.setSelectedComponent(_panelOperationTypeLocalVariable); break; 175 case Formula: _tabbedPaneOperationType.setSelectedComponent(_panelOperationTypeFormula); break; 176 default: throw new IllegalArgumentException("invalid _addressing state: " + action.getOperationAddressing().name()); 177 } 178 _operationComboBox.setSelectedItem(action.getOperationType()); 179 _scriptOperationReferenceTextField.setText(action.getOperationReference()); 180 _scriptOperationLocalVariableTextField.setText(action.getOperationLocalVariable()); 181 _scriptOperationFormulaTextField.setText(action.getOperationFormula()); 182 183 switch (action.getScriptAddressing()) { 184 case Direct: _tabbedPaneScriptType.setSelectedComponent(_panelScriptTypeDirect); break; 185 case Reference: _tabbedPaneScriptType.setSelectedComponent(_panelScriptTypeReference); break; 186 case LocalVariable: _tabbedPaneScriptType.setSelectedComponent(_panelScriptTypeLocalVariable); break; 187 case Formula: _tabbedPaneScriptType.setSelectedComponent(_panelScriptTypeFormula); break; 188 default: throw new IllegalArgumentException("invalid _addressing state: " + action.getScriptAddressing().name()); 189 } 190 _scriptTextField.setText(action.getScript()); 191 _scriptReferenceTextField.setText(action.getScriptReference()); 192 _scriptLocalVariableTextField.setText(action.getScriptLocalVariable()); 193 _scriptFormulaTextField.setText(action.getScriptFormula()); 194 } 195 196 JComponent[] components = new JComponent[]{ 197 _tabbedPaneOperationType, 198 _tabbedPaneScriptType 199 }; 200 201 List<JComponent> componentList = SwingConfiguratorInterface.parseMessage( 202 Bundle.getMessage("ActionScript_Components"), components); 203 204 for (JComponent c : componentList) actionPanel.add(c); 205 panel.add(actionPanel); 206 207 JPanel scriptSelectorPanel = new JPanel(); 208 scriptSelectorPanel.add(new JLabel(Bundle.getMessage("ActionScript_ScriptSelector"))); 209 scriptSelectorPanel.add(_scriptEngineSelectorSwing.getComboBox()); 210 211 panel.add(scriptSelectorPanel); 212 } 213 214 /** {@inheritDoc} */ 215 @Override 216 public boolean validate(@Nonnull List<String> errorMessages) { 217 // Create a temporary action to test formula 218 ActionScript action = new ActionScript("IQDA1", null); 219 220 try { 221 if (_tabbedPaneOperationType.getSelectedComponent() == _panelOperationTypeReference) { 222 action.setOperationReference(_scriptOperationReferenceTextField.getText()); 223 } 224 } catch (IllegalArgumentException e) { 225 errorMessages.add(e.getMessage()); 226 return false; 227 } 228 229 try { 230 action.setScriptFormula(_scriptFormulaTextField.getText()); 231 if (_tabbedPaneScriptType.getSelectedComponent() == _panelScriptTypeDirect) { 232 action.setScriptAddressing(NamedBeanAddressing.Direct); 233 } else if (_tabbedPaneScriptType.getSelectedComponent() == _panelScriptTypeReference) { 234 action.setScriptAddressing(NamedBeanAddressing.Reference); 235 } else if (_tabbedPaneScriptType.getSelectedComponent() == _panelScriptTypeLocalVariable) { 236 action.setScriptAddressing(NamedBeanAddressing.LocalVariable); 237 } else if (_tabbedPaneScriptType.getSelectedComponent() == _panelScriptTypeFormula) { 238 action.setScriptAddressing(NamedBeanAddressing.Formula); 239 } else { 240 throw new IllegalArgumentException("_tabbedPaneScriptType has unknown selection"); 241 } 242 } catch (ParserException e) { 243 errorMessages.add("Cannot parse formula: " + e.getMessage()); 244 return false; 245 } 246 return true; 247 } 248 249 /** {@inheritDoc} */ 250 @Override 251 public MaleSocket createNewObject(@Nonnull String systemName, @CheckForNull String userName) { 252 ActionScript action = new ActionScript(systemName, userName); 253 updateObject(action); 254 return InstanceManager.getDefault(DigitalActionManager.class).registerAction(action); 255 } 256 257 /** {@inheritDoc} */ 258 @Override 259 public void updateObject(@Nonnull Base object) { 260 if (! (object instanceof ActionScript)) { 261 throw new IllegalArgumentException("object must be an ActionScript but is a: "+object.getClass().getName()); 262 } 263 ActionScript action = (ActionScript)object; 264 265 try { 266 if (_tabbedPaneOperationType.getSelectedComponent() == _panelOperationTypeDirect) { 267 action.setOperationAddressing(NamedBeanAddressing.Direct); 268 action.setOperationType((ActionScript.OperationType)_operationComboBox.getSelectedItem()); 269 } else if (_tabbedPaneOperationType.getSelectedComponent() == _panelOperationTypeReference) { 270 action.setOperationAddressing(NamedBeanAddressing.Reference); 271 action.setOperationReference(_scriptOperationReferenceTextField.getText()); 272 } else if (_tabbedPaneOperationType.getSelectedComponent() == _panelOperationTypeLocalVariable) { 273 action.setOperationAddressing(NamedBeanAddressing.LocalVariable); 274 action.setOperationLocalVariable(_scriptOperationLocalVariableTextField.getText()); 275 } else if (_tabbedPaneOperationType.getSelectedComponent() == _panelOperationTypeFormula) { 276 action.setOperationAddressing(NamedBeanAddressing.Formula); 277 action.setOperationFormula(_scriptOperationFormulaTextField.getText()); 278 } else { 279 throw new IllegalArgumentException("_tabbedPaneOperationType has unknown selection"); 280 } 281 282 if (_tabbedPaneScriptType.getSelectedComponent() == _panelScriptTypeDirect) { 283 action.setScriptAddressing(NamedBeanAddressing.Direct); 284 action.setScript(_scriptTextField.getText()); 285 } else if (_tabbedPaneScriptType.getSelectedComponent() == _panelScriptTypeReference) { 286 action.setScriptAddressing(NamedBeanAddressing.Reference); 287 action.setScriptReference(_scriptReferenceTextField.getText()); 288 } else if (_tabbedPaneScriptType.getSelectedComponent() == _panelScriptTypeLocalVariable) { 289 action.setScriptAddressing(NamedBeanAddressing.LocalVariable); 290 action.setScriptLocalVariable(_scriptLocalVariableTextField.getText()); 291 } else if (_tabbedPaneScriptType.getSelectedComponent() == _panelScriptTypeFormula) { 292 action.setScriptAddressing(NamedBeanAddressing.Formula); 293 action.setScriptFormula(_scriptFormulaTextField.getText()); 294 } else { 295 throw new IllegalArgumentException("_tabbedPaneAspectType has unknown selection"); 296 } 297 } catch (ParserException e) { 298 throw new RuntimeException("ParserException: "+e.getMessage(), e); 299 } 300 301 _scriptEngineSelectorSwing.update(); 302 } 303 304 /** {@inheritDoc} */ 305 @Override 306 public String toString() { 307 return Bundle.getMessage("ActionScript_Short"); 308 } 309 310 @Override 311 public void dispose() { 312 } 313 314 315 private final static org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(ActionScriptSwing.class); 316 317}