/** * JSWidget.java * Copyright (C) 2010 New Zealand Digital Library, http://expeditee.org * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ package org.expeditee.items.widgets; import java.awt.BorderLayout; import java.awt.Component; import java.awt.Graphics2D; import java.util.LinkedList; import java.util.List; import javax.script.Invocable; import javax.script.ScriptEngine; import javax.script.ScriptEngineManager; import javax.script.ScriptException; import javax.swing.JPanel; import org.expeditee.gui.DisplayIO; import org.expeditee.items.ItemParentStateChangedEvent; import org.expeditee.items.JSThreadable; import org.expeditee.items.Text; /** * Class for extending Expeditee with widgets coded in Javascript * * @author jts21 * */ public class JSWidget extends DataFrameWidget implements JSThreadable { private static ScriptEngineManager scriptEngineManager = null; private static ScriptEngine globalScriptEngine = null; private static Object global = null; // a method to run that will set up and return the root JComponent for this Widget private final String init; // a method to run to populate a List with our state private final String save; // a method to run that will load state from a String[] private final String load; // we have our own script context since it needs to have some global variables which are specific to each widget private final ScriptEngine scriptEngine; private final Invocable invocable; // component created by running our constructor private final Component component; // container for our component private final JPanel container; static { try { scriptEngineManager = new ScriptEngineManager(); globalScriptEngine = scriptEngineManager.getEngineByMimeType("application/javascript"); global = globalScriptEngine.eval("new Object()"); } catch (ScriptException e) { e.printStackTrace(); } } private static Text getSauce() { Text source = new Text(DisplayIO.getCurrentFrame().getNextItemID(), "@iw: org.expeditee.items.widgets.JSWidget"); source.setParent(DisplayIO.getCurrentFrame()); return source; } private JSWidget(Text source, int width, int height, String init, String save, String load) throws Exception { super(source, new JPanel(new BorderLayout()), -1, width, -1, -1, height, -1); this.init = init; this.save = save; this.load = load; this.container = (JPanel) super._swingComponent; this.scriptEngine = scriptEngineManager.getEngineByMimeType("application/javascript"); this.invocable = (Invocable) this.scriptEngine; this.scriptEngine.put("global", global); this.scriptEngine.put("invocable", this.invocable); this.scriptEngine.put("widget", this); this.scriptEngine.put("container", this.container); System.out.println(this.init); this.component = (Component) this.scriptEngine.eval("var init = " + this.init + "\ninit()"); this.container.add(component); this.scriptEngine.put("component", this.component); this.scriptEngine.eval("save = " + this.save); this.scriptEngine.eval("load = " + this.load); } private JSWidget(Text source, String init, String save, String load) throws Exception { this(source, 100, 100, init, save, load); } public JSWidget(Text source, String[] args) throws Exception { this(source, source.getData().get(0).replaceAll("\\\\n", "\n"), source.getData().get(1).replaceAll("\\\\n", "\n"), source.getData().get(2).replaceAll("\\\\n", "\n")); this.invocable.invokeFunction("load", (Object) args); } public JSWidget(int width, int height, String init, String save, String load) throws Exception { this(getSauce(), width, height, init, save, load); } public JSWidget(String init, String save, String load) throws Exception { this(100, 100, init, save, load); } @Override protected List getData() { List value = new LinkedList(); value.add(this.init.replaceAll("[\n\r]", "\\\\n")); value.add(this.save.replaceAll("[\n\r]", "\\\\n")); value.add(this.load.replaceAll("[\n\r]", "\\\\n")); return value; } @Override protected String[] getArgs() { try { List args = new LinkedList(); this.invocable.invokeFunction("save", (Object)args); return args.toArray(new String[0]); } catch (Exception e) { e.printStackTrace(); return null; } } private List threads = new LinkedList(); public JSThread addThread(String code) { JSThread t = new JSThread(scriptEngine, code); this.threads.add(t); return t; } @Override public void onParentStateChanged(int e) { switch (e) { case ItemParentStateChangedEvent.EVENT_TYPE_REMOVED: case ItemParentStateChangedEvent.EVENT_TYPE_REMOVED_VIA_OVERLAY: case ItemParentStateChangedEvent.EVENT_TYPE_HIDDEN: for(JSThread t : this.threads) { t.kill(); } break; case ItemParentStateChangedEvent.EVENT_TYPE_ADDED: case ItemParentStateChangedEvent.EVENT_TYPE_ADDED_VIA_OVERLAY: case ItemParentStateChangedEvent.EVENT_TYPE_SHOWN: case ItemParentStateChangedEvent.EVENT_TYPE_SHOWN_VIA_OVERLAY: for(JSThread t : this.threads) { t.resume(); } break; } } @Override protected void paintLink(Graphics2D g) { return; } }