/** * This file Copyright (c) 2005-2008 Aptana, Inc. This program is * dual-licensed under both the Aptana Public License and the GNU General * Public license. You may elect to use one or the other of these licenses. * * This program is distributed in the hope that it will be useful, but * AS-IS and WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, TITLE, or * NONINFRINGEMENT. Redistribution, except as permitted by whichever of * the GPL or APL you select, is prohibited. * * 1. For the GPL license (GPL), you can redistribute and/or modify this * program under the terms of the GNU General Public License, * Version 3, as published by the Free Software Foundation. You should * have received a copy of the GNU General Public License, Version 3 along * with this program; if not, write to the Free Software Foundation, Inc., 51 * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Aptana provides a special exception to allow redistribution of this file * with certain other free and open source software ("FOSS") code and certain additional terms * pursuant to Section 7 of the GPL. You may view the exception and these * terms on the web at http://www.aptana.com/legal/gpl/. * * 2. For the Aptana Public License (APL), this program and the * accompanying materials are made available under the terms of the APL * v1.0 which accompanies this distribution, and is available at * http://www.aptana.com/legal/apl/. * * You may view the GPL, Aptana's exception and additional terms, and the * APL in the file titled license.html at the root of the corresponding * plugin containing this source file. * * Any modifications to this file must keep this entire header intact. */ package com.aptana.ide.scripting; import java.io.BufferedReader; import java.io.ByteArrayInputStream; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.StringWriter; import java.lang.reflect.InvocationTargetException; import java.util.HashMap; import java.util.Set; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException; import org.eclipse.core.runtime.Platform; import org.eclipse.jface.dialogs.InputDialog; import org.eclipse.jface.dialogs.MessageDialog; import org.eclipse.jface.preference.IPreferenceStore; import org.eclipse.jface.window.Window; import org.eclipse.swt.layout.GridData; import org.eclipse.swt.widgets.Display; import org.eclipse.swt.widgets.Shell; import org.eclipse.ui.IWorkbench; import org.eclipse.ui.PlatformUI; import org.eclipse.ui.console.MessageConsoleStream; import org.mozilla.javascript.Context; import org.mozilla.javascript.Function; import org.mozilla.javascript.Script; import org.mozilla.javascript.Scriptable; import org.mozilla.javascript.ScriptableObject; import org.osgi.framework.Bundle; import org.w3c.dom.Document; import org.xml.sax.SAXException; import com.aptana.ide.core.IdeLog; import com.aptana.ide.core.StringUtils; import com.aptana.ide.editor.css.CSSPlugin; import com.aptana.ide.editor.html.HTMLPlugin; import com.aptana.ide.editor.js.JSPlugin; import com.aptana.ide.editor.xml.XMLPlugin; import com.aptana.ide.editors.UnifiedEditorsPlugin; import com.aptana.ide.editors.preferences.IPreferenceConstants; import com.aptana.ide.editors.views.actions.ActionsViewEventTypes; import com.aptana.ide.editors.views.profiles.ProfilesViewEventTypes; import com.aptana.ide.scripting.editors.Editors; import com.aptana.ide.scripting.editors.Region; import com.aptana.ide.scripting.io.File; import com.aptana.ide.scripting.io.PrintStream; import com.aptana.ide.scripting.io.WebRequest; import com.aptana.ide.scripting.menus.Menus; import com.aptana.ide.scripting.parsing.CSSTokenTypes; import com.aptana.ide.scripting.parsing.HTMLTokenTypes; import com.aptana.ide.scripting.parsing.JSTokenTypes; import com.aptana.ide.scripting.parsing.ScriptDocTokenTypes; import com.aptana.ide.scripting.parsing.TokenCategories; import com.aptana.ide.scripting.parsing.XMLTokenTypes; import com.aptana.ide.scripting.views.Views; /** * @author Kevin Lindsey */ public class Global extends ScriptableObject { /* * Fields */ private static final long serialVersionUID = 1996593475808707552L; private static int scriptIndex = 0; /** * The property name used to store a libraries unique id */ public static final String idPropertyName = "__sid__"; //$NON-NLS-1$ private Menus _menus; private Editors _editors; private Views _views; private PrintStream _err; // private PrintStream _out; private HashMap _scriptInfo; private HashMap _idXref; private HashMap _runningSetTimeouts; private int _setTimeoutIndex; /* * Properties */ /** * getClassName * * @return String */ public String getClassName() { return "Global"; //$NON-NLS-1$ } /* * Constructors */ /** * GlobalBase * * @param cx */ public Global(Context cx) { this._scriptInfo = new HashMap(); this._idXref = new HashMap(); this._runningSetTimeouts = new HashMap(); // create local instances this._menus = new Menus(this); this._editors = new Editors(this); this._views = new Views(this); // wrap output streams // CHECKSTYLE:OFF this._err = new PrintStream(this, System.err); // CHECKSTYLE:ON // this._out = new PrintStream(this, System.out); // create unsealed standard objects cx.initStandardObjects(this, false); // make list of functions String[] names = { "alert", //$NON-NLS-1$ "clearTimeout", //$NON-NLS-1$ "confirm", //$NON-NLS-1$ "execute", //$NON-NLS-1$ "getPreference", //$NON-NLS-1$ "getProperty", //$NON-NLS-1$ "include", //$NON-NLS-1$ "loadBundle", //$NON-NLS-1$ "loadLibrary", //$NON-NLS-1$ "parseXML", //$NON-NLS-1$ "prompt", //$NON-NLS-1$ "reloadLibrary", //$NON-NLS-1$ "runOnUIThread", //$NON-NLS-1$ "setPreference", //$NON-NLS-1$ "setTimeout", //$NON-NLS-1$ "share" //$NON-NLS-1$ }; // define functions this.defineFunctionProperties(names, Global.class, READONLY | PERMANENT); // define properties this.defineProperty("global", this, READONLY | PERMANENT); //$NON-NLS-1$ this.defineProperty("editors", this._editors, READONLY | PERMANENT); //$NON-NLS-1$ this.defineProperty("window", this, READONLY | PERMANENT); //$NON-NLS-1$ // this.defineProperty("document", this, READONLY | PERMANENT); this.defineProperty("menus", this._menus, READONLY | PERMANENT); //$NON-NLS-1$ this.defineProperty("views", this._views, READONLY | PERMANENT); //$NON-NLS-1$ MessageConsoleStream stream = ScriptingEngine.getInstance().getConsoleStream(); // this.defineProperty("err", stream, READONLY | PERMANENT); this.defineProperty("err", _err, READONLY | PERMANENT); //$NON-NLS-1$ this.defineProperty("out", stream, READONLY | PERMANENT); //$NON-NLS-1$ this.defineProperty("TokenCategories", new TokenCategories(this), READONLY | PERMANENT); //$NON-NLS-1$ this.defineProperty("CSSTokenTypes", new CSSTokenTypes(this), READONLY | PERMANENT); //$NON-NLS-1$ this.defineProperty("HTMLTokenTypes", new HTMLTokenTypes(this), READONLY | PERMANENT); //$NON-NLS-1$ this.defineProperty("JSTokenTypes", new JSTokenTypes(this), READONLY | PERMANENT); //$NON-NLS-1$ this.defineProperty("ScriptDocTokenTypes", new ScriptDocTokenTypes(this), READONLY | PERMANENT); //$NON-NLS-1$ this.defineProperty("XMLTokenTypes", new XMLTokenTypes(this), READONLY | PERMANENT); //$NON-NLS-1$ this.defineProperty("IPreferenceConstants", new IPreferenceConstants() {}, READONLY | PERMANENT); //$NON-NLS-1$ this.defineProperty("ProfilesViewEventTypes", new ProfilesViewEventTypes(), READONLY | PERMANENT); //$NON-NLS-1$ this.defineProperty("ActionsViewEventTypes", new ActionsViewEventTypes(), READONLY | PERMANENT); //$NON-NLS-1$ this.defineProperty("SWT", new org.eclipse.swt.SWT(), READONLY | PERMANENT); //$NON-NLS-1$ this.defineProperty("GridData", new GridData(), READONLY | PERMANENT); //$NON-NLS-1$ try { ScriptableObject.defineClass(this, File.class); ScriptableObject.defineClass(this, WebRequest.class); ScriptableObject.defineClass(this, Region.class); ScriptableObject.defineClass(this, com.aptana.ide.scripting.swt.Shell.class); ScriptableObject.defineClass(this, com.aptana.ide.scripting.swt.Button.class); ScriptableObject.defineClass(this, com.aptana.ide.scripting.swt.Text.class); ScriptableObject.defineClass(this, com.aptana.ide.scripting.swt.Label.class); } catch (IllegalAccessException e) { IdeLog.logError(ScriptingPlugin.getDefault(), Messages.Global_Error, e); } catch (InstantiationException e) { IdeLog.logError(ScriptingPlugin.getDefault(), Messages.Global_Error, e); } catch (InvocationTargetException e) { IdeLog.logError(ScriptingPlugin.getDefault(), Messages.Global_Error, e); } } /* * Methods */ /** * Execute a command-line in the system shell * * @param cx * @param thisObj * @param args * The string command to execute * @param funObj * @return Returns an object array where the first object is the return code, the second object is the text from * stdout, and the third object is the text from stderr */ public static Scriptable execute(Context cx, Scriptable thisObj, Object[] args, Function funObj) { Scriptable result = null; if (args.length > 0) { String command = args[0].toString(); String input = StringUtils.EMPTY; if (args.length > 1) { input = args[1].toString(); } Process p = null; int retCode = 0; String stdout = StringUtils.EMPTY; String stderr = StringUtils.EMPTY; try { p = Runtime.getRuntime().exec(command); p.getOutputStream().write(input.getBytes()); p.getOutputStream().flush(); p.getOutputStream().close(); retCode = p.waitFor(); // retCode = p.exitValue(); stdout = getText(p.getInputStream()); stderr = getText(p.getErrorStream()); } catch (IOException e) { if (p != null) { retCode = p.exitValue(); } } catch (InterruptedException e) { IdeLog.logError(ScriptingPlugin.getDefault(), Messages.Global_Error, e); } // create Object Scriptable scope = ScriptableObject.getTopLevelScope(thisObj); result = cx.newObject(scope, "Object"); //$NON-NLS-1$ // set property values result.put("code", result, new Integer(retCode)); //$NON-NLS-1$ result.put("stdout", result, stdout); //$NON-NLS-1$ result.put("stderr", result, stderr); //$NON-NLS-1$ } // return result return result; } /** * export * * @param obj */ public void share(ScriptableObject obj) { if (obj != null) { Object[] ids = obj.getIds(); for (int i = 0; i < ids.length; i++) { Object id = ids[i]; if (id instanceof String) { String propertyName = (String) id; this.put(propertyName, this, obj.get(propertyName, obj)); } } } } /** * runOnUIThread * * @param cx * @param thisObj * @param args * @param funObj */ public static void runOnUIThread(Context cx, Scriptable thisObj, Object[] args, Function funObj) { if (args.length > 0 && args[0] instanceof Function) { Function f = (Function) args[0]; // get display final IWorkbench workbench = PlatformUI.getWorkbench(); Display display = workbench.getDisplay(); // execute callback in the correct thread display.syncExec(new ScriptThread(f.getParentScope(), f, new Object[0])); } } /** * runOnUIThreadAsync * * @param cx * @param thisObj * @param args * @param funObj */ public static void runOnUIThreadAsync(Context cx, Scriptable thisObj, Object[] args, Function funObj) { if (args.length > 0 && args[0] instanceof Function) { Function f = (Function) args[0]; // get display final IWorkbench workbench = PlatformUI.getWorkbench(); Display display = workbench.getDisplay(); // execute callback in the correct thread display.asyncExec(new ScriptThread(f.getParentScope(), f, new Object[0])); } } /** * parseXML * * @param xml * @return Document */ public Document parseXML(String xml) { Document result = null; if (xml != null && xml.length() > 0) { DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); DocumentBuilder builder; try { builder = factory.newDocumentBuilder(); // parse XML to create our document element InputStream in = new ByteArrayInputStream(xml.getBytes()); result = builder.parse(in); } catch (ParserConfigurationException e) { IdeLog.logError(ScriptingPlugin.getDefault(), Messages.Global_Error, e); } catch (SAXException e) { IdeLog.logError(ScriptingPlugin.getDefault(), Messages.Global_Error, e); } catch (IOException e) { IdeLog.logError(ScriptingPlugin.getDefault(), Messages.Global_Error, e); } } return result; } /** * Get a string array of all script ids that have been registered * * @return String[] */ public String[] getScriptIds() { Set keySet = _scriptInfo.keySet(); return (String[]) keySet.toArray(new String[keySet.size()]); } /** * Get the script info object for the specified script id * * @param id * The script id to lookup * @return The ScriptInfo for the specified id */ public ScriptInfo getScriptInfo(String id) { ScriptInfo result = null; if (this._scriptInfo.containsKey(id)) { result = (ScriptInfo) this._scriptInfo.get(id); } return result; } /** * Determine if we have ScriptInfo for the given id * * @param id * The id to lookup * @return Returns true if we have a ScriptInfo entry for the given id */ public boolean hasScriptInfo(String id) { return this._scriptInfo.containsKey(id); } /** * Get all text from the given input stream * * @param stream * The input stream * @return Returns all text from the input stream * @throws IOException */ protected static String getText(InputStream stream) throws IOException { // create output buffer StringWriter sw = new StringWriter(); // read contents into a string buffer try { // get buffered reader InputStreamReader isr = new InputStreamReader(stream); BufferedReader reader = new BufferedReader(isr); // create temporary buffer char[] buf = new char[1024]; // fill buffer int numRead = reader.read(buf); // keep reading until the end of the stream while (numRead != -1) { // output temp buffer to output buffer sw.write(buf, 0, numRead); // fill buffer numRead = reader.read(buf); } } finally { if (stream != null) { stream.close(); } } // return string buffer's content return sw.toString(); } /** * Perform any steps required to reset the global scope when reloading the scripting engine */ public void shutdown() { this._scriptInfo.clear(); } /** * Popup an alert box with the specified message * * @param message * The message to display in an alert dialog */ public void alert(final String message) { final Display currentDisplay = Display.getCurrent(); if (currentDisplay != null) { currentDisplay.syncExec(new Runnable() { public void run() { Shell shell = currentDisplay.getActiveShell(); if (shell != null) { MessageDialog.openWarning(shell, "Aptana Studio", message); //$NON-NLS-1$ } } }); } } /** * Popup an confirm box with the specified message * * @param message * The message to display at the confirmation prompt * @return boolean */ public boolean confirm(final String message) { /** * inner class for result */ class Answer { public boolean result = false; } // create instance of inner class final Answer a = new Answer(); // get reply from user final Display currentDisplay = Display.getCurrent(); if (currentDisplay != null) { currentDisplay.syncExec(new Runnable() { public void run() { Shell shell = currentDisplay.getActiveShell(); if (shell != null) { a.result = MessageDialog.openConfirm(shell, "Aptana Studio", message); //$NON-NLS-1$ } } }); } return a.result; } /** * Popup an prompt box with the specified message * * @param cx * @param thisObj * @param args * The message to display in the prompt dialog * @param funObj * @return boolean */ public static Object prompt(Context cx, Scriptable thisObj, Object[] args, Function funObj) { final Display currentDisplay = Display.getCurrent(); String messageArg = Messages.Global_Prompt; String defaultValueArg = StringUtils.EMPTY; if (args.length > 0) { messageArg = Context.toString(args[0]); } if (args.length > 1) { defaultValueArg = Context.toString(args[1]); } /** * Answer */ class Answer { public Object result = StringUtils.EMPTY; } final String message = messageArg; final String defaultValue = defaultValueArg; final Answer a = new Answer(); if (currentDisplay != null) { currentDisplay.syncExec(new Runnable() { public void run() { Shell shell = currentDisplay.getActiveShell(); if (shell != null) { InputDialog dialog = new InputDialog(null, "Aptana Prompt", message, defaultValue, null); //$NON-NLS-1$ int dialogResult = dialog.open(); if (dialogResult == Window.OK) { a.result = dialog.getValue(); } else { a.result = Context.getUndefinedValue(); } } } }); } return a.result; } /** * Get a list of the full paths of all files in the Active Library view * * @param property * The system property name to retrieve * @return Returns a string array of full paths */ public String getProperty(String property) { String result = null; if (property != null && property.length() > 0) { result = System.getProperty(property, "undefined"); //$NON-NLS-1$ } return result; } /** * Get preference * * @param cx * @param thisObj * @param args * @param funObj * @return Returns a string array of full paths */ public static String getPreference(Context cx, Scriptable thisObj, Object[] args, Function funObj) { String result = StringUtils.EMPTY; if (args.length > 0) { String name = Context.toString(args[0]); int pluginIndex = Editors.UNIFIED_EDITOR; IPreferenceStore prefStore; if (args.length > 1) { pluginIndex = (int) Context.toNumber(args[1]); } switch (pluginIndex) { case Editors.CSS_EDITOR: prefStore = CSSPlugin.getDefault().getPreferenceStore(); break; case Editors.HTML_EDITOR: prefStore = HTMLPlugin.getDefault().getPreferenceStore(); break; case Editors.JAVASCRIPT_EDITOR: prefStore = JSPlugin.getDefault().getPreferenceStore(); break; case Editors.XML_EDITOR: prefStore = XMLPlugin.getDefault().getPreferenceStore(); break; case Editors.UNIFIED_EDITOR: default: prefStore = UnifiedEditorsPlugin.getDefault().getPreferenceStore(); break; } result = prefStore.getString(name); } return result; } /** * Set a preference * * @param name * The name of the preference to set * @param value * The new value for the specified preference */ public void setPreference(String name, String value) { if (name != null && name.length() > 0 && value != null && value.length() > 0) { IPreferenceStore prefStore = UnifiedEditorsPlugin.getDefault().getPreferenceStore(); prefStore.setValue(name, value); UnifiedEditorsPlugin.getDefault().savePluginPreferences(); } } /** * Load a script into a currently executing library * * @param cx * @param thisObj * @param args * @param funObj */ public static void include(Context cx, Scriptable thisObj, Object[] args, Function funObj) { if (args.length > 0) { String id = Context.toString(thisObj.get(idPropertyName, thisObj.getParentScope())); Global global = (Global) funObj.getParentScope(); ScriptInfo info = global.getScriptInfo(id); String libraryName = Context.toString(args[0]); java.io.File library = new java.io.File(libraryName); if (library.exists() == false) { java.io.File parent = info.getFile().getParentFile(); String name = parent.getAbsolutePath() + java.io.File.separator + libraryName; library = new java.io.File(name); } if (library.exists()) { try { // grab the script's source String source = FileUtilities.getStreamText(new FileInputStream(library)); // get script where this is executing Scriptable scope = info.getScope(); // compile the script Script script = cx.compileString(source, library.getAbsolutePath(), 1, null); // exec script.exec(cx, scope); } catch (FileNotFoundException e) { IdeLog.logError(ScriptingPlugin.getDefault(), Messages.Global_Error, e); } } else { String message = StringUtils.format(Messages.Global_Cannot_Locate_File, new Object[] {info.getFile().getAbsolutePath(), libraryName}); IdeLog.logError(ScriptingPlugin.getDefault(), message); } } else { IdeLog.logError(ScriptingPlugin.getDefault(), Messages.Global_Filename_Not_Defined); } } /** * loadBundle * * @param cx * @param thisObj * @param args * @param funObj */ public static void loadBundle(Context cx, Scriptable thisObj, Object[] args, Function funObj) { if (args.length > 0) { String id = Context.toString(thisObj.get(idPropertyName, thisObj.getParentScope())); Global global = (Global) funObj.getParentScope(); ScriptInfo info = global.getScriptInfo(id); String bundleName = Context.toString(args[0]); Bundle bundle = Platform.getBundle(bundleName); if (bundle == null) { throw new RuntimeException(Messages.Global_Bundle_Not_Found + bundleName); } ScriptClassLoader classLoader = info.getClassLoader(); classLoader.addBundle(bundle); } } /** * Load a library into the script engine. Libraries maintain their own scope. As a result, each script's global will * not collide with other library globals. However, each library's global is linked with the ScriptEngine's global. * This reduces duplicate definition of built-in objects like Object, Function, Array, etc. Libraries can access the * ScriptEngine global via the "global" property. Libraries can share data using "global" * * @param cx * The script's Context * @param thisObj * The object or scope where this function was invoked * @param args * The library path to load * @param funObj * @return Returns the script's id or undefined if the script failed to load */ public static Object loadLibrary(Context cx, Scriptable thisObj, Object[] args, Function funObj) { Object result = null; if (args.length > 0) { Global instance = ScriptingEngine.getInstance().getGlobal(); String libraryPath = Context.toString(args[0]); String onLoadFunction = (args.length > 1) ? Context.toString(args[1]) : "onload"; //$NON-NLS-1$ try { // grab the script's source String source = FileUtilities.getStreamText(new FileInputStream(libraryPath)); // compile the script Script script = cx.compileString(source, libraryPath, 1, null); // build script's local global scope Scriptable scope = cx.newObject(instance); scope.setPrototype(instance); scope.setParentScope(null); // store script state info String id = instance.storeScriptState(libraryPath, script, scope); // create local global to script's location scope.put("location", scope, libraryPath); //$NON-NLS-1$ // execute script to load its definitions into its scope Context.toBoolean(script.exec(cx, scope)); // grab the init function used to perform any needed load-time initialization Object fObj = scope.get(onLoadFunction, scope); // call the init function if (fObj instanceof Function) { Function f = (Function) fObj; ScriptInfo info = instance.getScriptInfo(id); ClassLoader oldClassLoader = cx.getApplicationClassLoader(); cx.setApplicationClassLoader(info.getClassLoader()); try { f.call(cx, scope, scope, new Object[0]); } catch (Exception e) { cx.setApplicationClassLoader(oldClassLoader); } } else { IdeLog.logError(ScriptingPlugin.getDefault(), onLoadFunction + Messages.Global_Function_Does_Not_Exist + libraryPath); } // set result result = scope; } catch (FileNotFoundException e) { IdeLog.logError(ScriptingPlugin.getDefault(), Messages.Global_Error, e); } } if (result == null) { result = Context.getUndefinedValue(); } return result; } /** * reloadLibrary * * @param filename */ public void reloadLibrary(String filename) { if (filename != null && filename.length() > 0) { String key = this.getXrefId(filename); ScriptInfo info = this.getScriptInfo(key); Scriptable scope = info.getScope(); Object onunload = scope.get("onunload", scope); //$NON-NLS-1$ if (onunload instanceof Function) { Function unloadFunction = (Function) onunload; Context cx = Context.enter(); try { unloadFunction.call(cx, scope, scope, new Object[0]); this.removeScriptInfo(key); this.removeXrefId(filename); Global.loadLibrary(cx, this, new Object[] { filename, "onload" }, null); //$NON-NLS-1$ } catch (Exception e1) { IdeLog.logError(ScriptingPlugin.getDefault(), Messages.Global_Error, e1); } Context.exit(); } } } /** * clearTimeout * * @param timeoutId */ public void clearTimeout(int timeoutId) { synchronized (this._runningSetTimeouts) { Integer id = new Integer(timeoutId); if (this._runningSetTimeouts.containsKey(id)) { this._runningSetTimeouts.remove(id); } } } /** * setTimeout * * @param f * @param timeout * @return int */ public int setTimeout(final Function f, final int timeout) { final Global self = this; final int timeoutIndex = self._setTimeoutIndex++; Thread thread = new Thread(new Runnable() { public void run() { boolean active = true; try { // sleep Thread.sleep(timeout); // check if this was canceled while sleeping synchronized (self._runningSetTimeouts) { active = self._runningSetTimeouts.containsKey(new Integer(timeoutIndex)); } // call the associated function if this is still active if (active) { // get display final IWorkbench workbench = PlatformUI.getWorkbench(); if (workbench == null) { return; } Display display = workbench.getDisplay(); if (display == null || display.isDisposed()) { return; } // execute callback in the correct thread display.asyncExec(new Runnable() { public void run() { Scriptable scope = f.getParentScope(); Context cx = Context.enter(); f.call(cx, scope, scope, new Object[0]); Context.exit(); self.clearTimeout(timeoutIndex); } }); } } catch (InterruptedException e) { IdeLog.logError(ScriptingPlugin.getDefault(), Messages.Global_Error, e); } } }, "Aptana: Script setTimeout"); //$NON-NLS-1$ // save reference to this thread to indicate that it should run. Note that clearTimeout will // remove this entry // and if that is down before the thread wakes, then the action in the thread will not // execute this._runningSetTimeouts.put(new Integer(timeoutIndex), thread); thread.setDaemon(true); // start the thread thread.start(); // return the timeout index in case the thread wants to abort this timeout return timeoutIndex; } /** * removeScriptInfo * * @param id */ public void removeScriptInfo(String id) { if (this._scriptInfo.containsKey(id)) { this._scriptInfo.remove(id); } } /** * storeScriptState * * @param uri * @param script * @param scope * @return String */ public synchronized String storeScriptState(String uri, Script script, Scriptable scope) { // inject the script id // NOTE: we do this before executing the script so it can have access to this value String id = "_" + (++scriptIndex) + "_"; //$NON-NLS-1$ //$NON-NLS-2$ ScriptableObject.defineProperty(scope, idPropertyName, id, READONLY | DONTENUM); // save reference to script info // NOTE: we save script info before executing so we can call "include" in the script's // global scope. Doing // this after "exec" will cause "include" to get a null reference when trying to lookup this // script ScriptInfo info = new ScriptInfo(script, id, new java.io.File(uri), scope); this._scriptInfo.put(id, info); this._idXref.put(uri, id); return id; } /** * getXrefId * * @param path * @return String */ public String getXrefId(String path) { String result = null; if (this._idXref.containsKey(path)) { result = (String) this._idXref.get(path); } return result; } /** * removeXrefId * * @param path */ public void removeXrefId(String path) { if (this._idXref.containsKey(path)) { this._idXref.remove(path); } } /** * Get a reference to the editors instance * * @return Editors */ public Editors getEditors() { return this._editors; } /** * Get a reference to the menus instance * * @return Menus */ public Menus getMenus() { return this._menus; } /** * Get a reference to the views instance * * @return Views */ public Views getViews() { return this._views; } }