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