001package jmri.jmrit.jython; 002 003import java.awt.event.ActionEvent; 004import java.io.File; 005import javax.script.ScriptException; 006import javax.swing.Icon; 007import javax.swing.JFileChooser; 008import jmri.script.JmriScriptEngineManager; 009import jmri.script.swing.ScriptFileChooser; 010import jmri.util.FileUtil; 011import jmri.util.swing.JmriAbstractAction; 012import jmri.util.swing.WindowInterface; 013import org.slf4j.Logger; 014import org.slf4j.LoggerFactory; 015 016/** 017 * This Action runs a script using an available script engine. 018 * <p> 019 * The script engine to use is determined by the script's extension. 020 * <p> 021 * There are two constructors. One, without a script file name, will open a 022 * FileDialog to prompt for the file to use. The other, with a File object, will 023 * directly invoke that file. 024 * 025 * @author Bob Jacobsen Copyright (C) 2004, 2007 026 */ 027public class RunJythonScript extends JmriAbstractAction { 028 029 public RunJythonScript(String s, WindowInterface wi) { 030 super(s, wi); 031 } 032 033 public RunJythonScript(String s, Icon i, WindowInterface wi) { 034 super(s, i, wi); 035 } 036 037 /** 038 * Constructor that, when action is invoked, opens a JFileChooser to select 039 * file to invoke. 040 * 041 * @param name Action name 042 */ 043 public RunJythonScript(String name) { 044 super(name); 045 configuredFile = null; 046 } 047 048 /** 049 * Constructor that, when action is invoked, directly invokes the provided 050 * File. 051 * 052 * @param name Action name 053 * @param file the script file to invoke 054 */ 055 public RunJythonScript(String name, File file) { 056 super(name); 057 this.configuredFile = file; 058 } 059 060 File configuredFile; 061 062 /** 063 * We always use the same file chooser in this class, so that the user's 064 * last-accessed directory remains available. 065 */ 066 static JFileChooser fci = null; 067 068 private static synchronized void setFileChooser(JFileChooser chooser) { 069 fci = chooser; 070 } 071 072 /** 073 * Invoking this action via an event triggers display of a file dialog. If a 074 * file is selected, it's then invoked as a script. 075 * 076 */ 077 @Override 078 public void actionPerformed(ActionEvent e) { 079 File thisFile; 080 if (configuredFile != null) { 081 thisFile = configuredFile; 082 } else { 083 thisFile = selectFile(); 084 } 085 086 // and invoke that file 087 if (thisFile != null) { 088 invoke(thisFile); 089 } else { 090 log.info("No file selected"); 091 } 092 } 093 094 File selectFile() { 095 if (fci == null) { 096 setFileChooser( new ScriptFileChooser(FileUtil.getScriptsPath()) ); 097 RunJythonScript.fci.setDialogTitle(Bundle.getMessage("FindDesiredScriptFile")); 098 } else { 099 // when reusing the chooser, make sure new files are included 100 fci.rescanCurrentDirectory(); 101 } 102 103 int retVal = fci.showOpenDialog(null); 104 // handle selection or cancel 105 if (retVal == JFileChooser.APPROVE_OPTION) { 106 File file = fci.getSelectedFile(); 107 // Run the script from its filename 108 return file; 109 } 110 return null; 111 } 112 113 void invoke(File file) { 114 try { 115 JmriScriptEngineManager.getDefault().eval(file); 116 } catch (ScriptException | java.io.IOException ex) { 117 log.error("Unable to execute script.", ex); 118 } 119 } 120 121 // never invoked, because we overrode actionPerformed above 122 @Override 123 public jmri.util.swing.JmriPanel makePanel() { 124 throw new IllegalArgumentException("Should not be invoked"); 125 } 126 127 // initialize logging 128 private final static Logger log = LoggerFactory.getLogger(RunJythonScript.class); 129 130}