source: trunk/src/org/expeditee/items/JSItem.java@ 1080

Last change on this file since 1080 was 1080, checked in by davidb, 7 years ago

Updates to cope with changes in Java ScriptEngine

File size: 7.1 KB
Line 
1/**
2 * JSItem.java
3 * Copyright (C) 2010 New Zealand Digital Library, http://expeditee.org
4 *
5 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, either version 3 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 */
18
19package org.expeditee.items;
20
21import java.awt.Graphics2D;
22import java.awt.Polygon;
23import java.util.LinkedList;
24import java.util.List;
25
26import javax.script.Invocable;
27import javax.script.ScriptEngine;
28import javax.script.ScriptEngineManager;
29import javax.script.ScriptException;
30
31import org.expeditee.gui.DisplayIO;
32import org.expeditee.items.widgets.InteractiveWidget;
33
34public class JSItem extends XRayable implements JSThreadable {
35
36 private static ScriptEngineManager scriptEngineManager = null;
37 private static ScriptEngine globalScriptEngine = null;
38 private static Object global = null;
39
40 // a method to run that will set up and return the root JComponent for this Widget
41 private final String init;
42 // a method to run to populate a List<String> with our state
43 private final String save;
44 // a method to run that will load state from a String[]
45 private final String load;
46 // a method to run that will paint our item using a Graphics2D object
47 private final String paint;
48
49 // we have our own script context since it needs to have some global variables which are specific to each widget
50 private final ScriptEngine scriptEngine;
51 private final Invocable invocable;
52
53 private int _width, _height;
54
55 static {
56 try {
57 scriptEngineManager = new ScriptEngineManager();
58 globalScriptEngine = scriptEngineManager.getEngineByMimeType("application/javascript");
59 global = globalScriptEngine.eval("new Object()");
60 } catch (ScriptException e) {
61 e.printStackTrace();
62 }
63 }
64
65 private static Text getSauce(int width, int height) {
66 Text source = new Text(DisplayIO.getCurrentFrame().getNextItemID(), "@js: " + width + " " + height);
67 source.setParent(DisplayIO.getCurrentFrame());
68 return source;
69 }
70
71 private JSItem(Text source, String init, String save, String load, String paint) throws Exception {
72 super(source);
73 this.init = init;
74 this.save = save;
75 this.load = load;
76 this.paint = paint;
77 this.scriptEngine = scriptEngineManager.getEngineByMimeType("application/javascript");
78 this.invocable = (Invocable) this.scriptEngine;
79 this.scriptEngine.put("global", global);
80 this.scriptEngine.put("invocable", this.invocable);
81 this.scriptEngine.put("item", this);
82 this.scriptEngine.put("source", this._source);
83 this.parseSource();
84 System.out.println(this.init);
85 this.scriptEngine.eval("var init = " + this.init + "\ninit()");
86 this.scriptEngine.eval("save = " + this.save);
87 this.scriptEngine.eval("paint = " + this.paint);
88 this.updateSource();
89 }
90
91 public JSItem(Text source) throws Exception {
92 this(source, source.getData().get(0).replaceAll("\\\\n", "\n"),
93 source.getData().get(1).replaceAll("\\\\n", "\n"),
94 source.getData().get(2).replaceAll("\\\\n", "\n"),
95 source.getData().get(3).replaceAll("\\\\n", "\n"));
96 }
97
98 public JSItem(int width, int height, String init, String save, String load, String paint) throws Exception {
99 this(getSauce(width, height), init, save, load, paint);
100 }
101
102 public JSItem(String init, String save, String load, String paint) throws Exception {
103 this(100, 100, init, save, load, paint);
104 }
105
106 @Override
107 public Item copy() {
108 try {
109 return new JSItem(_source.copy());
110 } catch (Exception e) {
111 e.printStackTrace();
112 }
113 return null;
114 }
115
116 @Override
117 public void paint(Graphics2D g) {
118 try {
119 this.invocable.invokeFunction("paint", (Object)g);
120 } catch (Exception e) {
121 e.printStackTrace();
122 }
123 }
124
125 @Override
126 public void setAnnotation(boolean val) {
127 // TODO Auto-generated method stub
128
129 }
130
131 @Override
132 public void updatePolygon() {
133 _poly = new Polygon();
134 _poly.addPoint(getX(), getY());
135 _poly.addPoint(getX() + _width, getY());
136 _poly.addPoint(getX() + _width, getY() + _height);
137 _poly.addPoint(getX(), getY() + _height);
138 }
139
140 private void parseSource() {
141 String text = _source.getText();
142 text = text.replaceFirst("@js:", "");
143 text = text.replaceAll("\n", "");
144 text = text.trim();
145 int index = text.indexOf(':');
146 String[] values;
147 if(index != -1) {
148 values = text.substring(0, index).split("\\s+");
149 } else {
150 values = text.split("\\s+");
151 }
152 if(values.length >= 2) {
153 _width = Integer.parseInt(values[0]);
154 _height = Integer.parseInt(values[1]);
155 }
156
157 if(index == -1) {
158 return;
159 }
160 String[] args = InteractiveWidget.parseArgs(text.substring(index));
161 try {
162 this.scriptEngine.eval("load = " + this.load);
163 this.invocable.invokeFunction("load", (Object) args);
164 } catch (Exception e) {
165 e.printStackTrace();
166 }
167 }
168
169 private String[] saveArgs() {
170 try {
171 List<String> args = new LinkedList<String>();
172 this.invocable.invokeFunction("save", (Object)args);
173 return args.toArray(new String[0]);
174 } catch (Exception e) {
175 e.printStackTrace();
176 }
177 return null;
178 }
179
180 private void updateSource() {
181 List<String> data = new LinkedList<String>();
182 data.add(this.init.replaceAll("[\n\r]", "\\\\n"));
183 data.add(this.save.replaceAll("[\n\r]", "\\\\n"));
184 data.add(this.load.replaceAll("[\n\r]", "\\\\n"));
185 data.add(this.paint.replaceAll("[\n\r]", "\\\\n"));
186 _source.setData(data);
187
188 StringBuffer newText = new StringBuffer("@js: ");
189 newText.append(_width).append(" ").append(_height);
190
191 String stateArgs = InteractiveWidget.formatArgs(saveArgs());
192 if (stateArgs != null) {
193 newText.append(':');
194 newText.append(stateArgs);
195 }
196
197 _source.setText(newText.toString());
198 }
199
200 @Override
201 public Integer getWidth() {
202 return this._width;
203 }
204
205 @Override
206 public int getHeight() {
207 return this._height;
208 }
209
210 private List<JSThread> threads = new LinkedList<JSThread>();
211
212 public JSThread addThread(String code) {
213 JSThread t = new JSThread(scriptEngine, code);
214 this.threads.add(t);
215 return t;
216 }
217
218 @Override
219 public void onParentStateChanged(ItemParentStateChangedEvent e) {
220 switch (e.getEventType()) {
221 case ItemParentStateChangedEvent.EVENT_TYPE_REMOVED:
222 case ItemParentStateChangedEvent.EVENT_TYPE_REMOVED_VIA_OVERLAY:
223 case ItemParentStateChangedEvent.EVENT_TYPE_HIDDEN:
224 for(JSThread t : this.threads) {
225 t.kill();
226 }
227 break;
228
229 case ItemParentStateChangedEvent.EVENT_TYPE_ADDED:
230 case ItemParentStateChangedEvent.EVENT_TYPE_ADDED_VIA_OVERLAY:
231 case ItemParentStateChangedEvent.EVENT_TYPE_SHOWN:
232 case ItemParentStateChangedEvent.EVENT_TYPE_SHOWN_VIA_OVERLAY:
233 for(JSThread t : this.threads) {
234 t.resume();
235 }
236 break;
237
238 }
239 }
240
241}
Note: See TracBrowser for help on using the repository browser.