source: trunk/src/org/expeditee/actions/Javascript.java@ 813

Last change on this file since 813 was 466, checked in by davidb, 11 years ago

initial cut at adding embedded Javascript support (fashioned after how Simple is implemented) in Expeditee

File size: 9.9 KB
Line 
1package org.expeditee.actions;
2
3import java.awt.Color;
4import java.util.LinkedList;
5import java.util.List;
6
7import org.expeditee.actions.Simple.Status;
8import org.expeditee.agents.Agent;
9import org.expeditee.agents.DefaultAgent;
10import org.expeditee.gui.DisplayIO;
11import org.expeditee.gui.Frame;
12import org.expeditee.gui.FrameGraphics;
13import org.expeditee.gui.FrameIO;
14import org.expeditee.gui.MessageBay;
15import org.expeditee.gui.FrameUtils;
16import org.expeditee.items.Item;
17import org.expeditee.items.Text;
18import org.expeditee.items.Item.HighlightMode;
19import org.expeditee.stats.AgentStats;
20import org.mozilla.javascript.Context;
21import org.mozilla.javascript.EvaluatorException;
22import org.mozilla.javascript.JavaScriptException;
23import org.mozilla.javascript.Scriptable;
24import org.mozilla.javascript.WrappedException;
25
26public class Javascript {
27
28 // Field largely based on Simple.java. Consider sharing code?
29
30
31 /**
32 * Keeps track of how many simple programs are running. Used to check if
33 * simple should read in keyboard input. Or if the keyboard input should be
34 * handled normally by Expeditee.
35 */
36 private static int _programsRunning = 0;
37
38 /**
39 * This flag is set to true if Simple should hijack keyboard input from
40 * Expeditee
41 */
42 private static boolean _consumeKeyboardInput = false;
43
44 public static void ProgramFinished() {
45 _programsRunning--;
46 _stop = false;
47 }
48
49 private static LinkedList<Character> _KeyStrokes = new LinkedList<Character>();
50
51 private static boolean _stop;
52
53 private static Agent _agent = null;
54
55 private static boolean _step;
56
57 private static int _stepPause = -1;
58
59 private static Color _stepColor;
60
61 private static boolean _nextStatement;
62
63 public static void KeyStroke(char c) {
64 _KeyStrokes.add(c);
65 }
66
67 public static boolean isProgramRunning() {
68 return _programsRunning > 0;
69 }
70
71 public static boolean consumeKeyboardInput() {
72 return _consumeKeyboardInput && _programsRunning > 0;
73 }
74
75 //Have changed parameters, so it takes an Item, not just a Text item.
76 private static void RunJavascriptFrame(Frame frame, Item current,
77 boolean acceptKeyboardInput, boolean step, int pause, Color color) {
78 try {
79 if (current != null) {
80 /*
81 * Changed the code from the line below because it caused
82 * problems when the "RunFrame" item was on the zero frame
83 */
84 // DisplayIO.addToBack(current.getParent());
85 DisplayIO.addToBack(DisplayIO.getCurrentFrame());
86 } else {
87 /* TODO we should not have to pass an item just to run a frame! */
88 current = new Text("Dummy");
89 current.setLink(frame.getName());
90 }
91
92 _stepColor = color == null ? Color.green : color;
93 _stepColor = new Color(_stepColor.getRed(), _stepColor.getGreen(),
94 _stepColor.getBlue(), 50);
95 _stepPause = pause;
96 _step = step;
97 _consumeKeyboardInput = acceptKeyboardInput;
98 FrameIO.SaveFrame(frame, true);
99
100 // an item without a link signals to run the current frame
101 if (current != null && current.getLink() == null) {
102 // Make a copy but hide it
103 current = current.copy();
104 current.setLink(frame.getName());
105 }
106
107 _KeyStrokes.clear();
108
109 Thread t = new Thread(current);
110 t.setPriority(Thread.MIN_PRIORITY);
111 t.start();
112 } catch (Exception e) {
113 e.printStackTrace();
114 }
115 }
116
117 public static void RunJavascriptFrame(Frame frame, Text current,
118 boolean acceptKeyboardInput) {
119 RunJavascriptFrame(frame, current, acceptKeyboardInput, false, 0, null);
120 }
121
122 /**
123 * Same as RunJavascriptFrame method above, except that it takes in
124 * any Item, not just a Text item. -kgas1
125 * @param frame - frame to run
126 * @param current - item selected
127 * @param acceptKeyboardInput
128 */
129 public static void RunJavascriptFrame(Frame frame, Item current,
130 boolean acceptKeyboardInput){
131 RunJavascriptFrame(frame, current, acceptKeyboardInput, false, 0, null);
132
133 }
134
135 public static void RunJavascriptFrame(Frame frame, Text current) {
136 RunJavascriptFrame(frame, current, false);
137 }
138
139 /**
140 * Same as RunJavascriptFrame method above, except it takes
141 * any Item as a parameter; not just Text Items. -kgas1
142 * @param frame
143 * @param current
144 */
145 public static void RunJavascriptFrame(Frame frame, Item current){
146 RunJavascriptFrame(frame, current, false);
147 }
148
149 private static void FlagError(Item item) {
150 FrameUtils.DisplayFrame(item.getParent().getName(), true, true);
151 item.setHighlightMode(HighlightMode.Normal);
152 item.setHighlightColor(Color.CYAN);
153 FrameIO.SaveFrame(item.getParent());
154 }
155
156 /**
157 * Runs a simple code beginning on a frame linked to by the specified item
158 * parameter.
159 *
160 * @param current
161 * the item that is linked to the frame to be run.
162 */
163 public static Status RunFrameAndReportError(Item current, Context context, Scriptable scope)
164 throws Exception {
165 // the item must link to a frame
166 if (current.getLink() == null) {
167 throw new Exception("Could not run unlinked item: "
168 + current.toString());
169 }
170
171 Frame child = FrameIO.LoadFrame(current.getAbsoluteLink());
172
173
174
175 if (_step) {
176 if (child != DisplayIO.getCurrentFrame()) {
177 DisplayIO.setCurrentFrame(child, true);
178 }
179 DisplayIO.addToBack(child);
180 }
181
182 AgentStats.FrameExecuted();
183
184 // if the frame could not be loaded
185 if (child == null) {
186 throw new Exception("Could not load item link: " + current.toString());
187 }
188
189 // loop through non-title, non-name, text items
190 List<Text> body = child.getBodyTextItems(false);
191
192 // if no item was found
193 if (body.size() == 0)
194 throw new Exception("No code to be executed: " + current.toString());
195
196 Status lastItemStatus = Status.OK;
197 for (Text item : body) {
198 AgentStats.ItemExecuted();
199 try {
200 Color oldColor = item.getBackgroundColor();
201 if (_step) {
202 pause(item);
203 }
204 lastItemStatus = RunItem(item, context, scope, lastItemStatus);
205 if (_step) {
206 if (item.getLink() == null) {
207 item.setBackgroundColor(oldColor);
208 } else {
209 item.setHighlightMode(Item.HighlightMode.None);
210 }
211 }
212
213 if (lastItemStatus != Status.OK) {
214 if (lastItemStatus != Status.TrueIf
215 && lastItemStatus != Status.FalseIf) {
216 if (_step) {
217 DisplayIO.removeFromBack();
218 }
219 return lastItemStatus;
220 }
221 }
222 } catch (ArrayIndexOutOfBoundsException e) {
223 FlagError(item);
224 throw new IncorrectUseOfStatementException(
225 "Too few parametres: " + item.toString(), item
226 .getStatement());
227 } catch (NullPointerException e) {
228 FlagError(item);
229 throw new Exception("Null pointer exception: "
230 + item.toString());
231 } catch (RuntimeException e) {
232 FlagError(item);
233 throw new IncorrectUseOfStatementException(e.getMessage() + " "
234 + item.toString(), item.getStatement());
235 } catch (Exception e) {
236 throw new Exception(e.getMessage());
237 }
238 }
239
240 if (_step) {
241 DisplayIO.removeFromBack();
242 if (DisplayIO.getCurrentFrame() != current.getParent())
243 DisplayIO.setCurrentFrame(current.getParent(), true);
244 }
245
246 return Status.OK;
247 }
248
249
250 /**
251 * @param item
252 * @param oldColor
253 * @throws Exception
254 * @throws InterruptedException
255 */
256 private static void pause(Text item) throws Exception, InterruptedException {
257 if (!_step)
258 return;
259
260 Color oldColor = item.getBackgroundColor();
261 item.setBackgroundColor(_stepColor);
262 item.setHighlightMode(Item.HighlightMode.None);
263
264 // Make sure we are on the frame with this item
265 Frame parent = item.getParentOrCurrentFrame();
266 if (!parent.equals(DisplayIO.getCurrentFrame())) {
267 DisplayIO.setCurrentFrame(parent, true);
268 }
269
270 FrameGraphics.Repaint();
271
272 int timeRemaining;
273 if (_stepPause < 0)
274 timeRemaining = Integer.MAX_VALUE;
275 else
276 timeRemaining = _stepPause;
277
278 while (timeRemaining > 0 && !_nextStatement) {
279 if (_stop) {
280 item.setBackgroundColor(oldColor);
281 item.setHighlightMode(HighlightMode.Normal, _stepColor);
282 throw new Exception("Program terminated");
283 }
284 Thread.sleep(DefaultAgent.TIMER_RESOLUTION);
285 timeRemaining -= DefaultAgent.TIMER_RESOLUTION;
286 }
287 _nextStatement = false;
288 // Turn off the highlighting
289 item.setBackgroundColor(oldColor);
290 }
291
292 private static void pause(double time) throws Exception {
293 for (int i = 0; i < time * 10; i++) {
294 if (_stop) {
295 throw new Exception("Program terminated");
296 }
297 Thread.yield();
298 Thread.sleep(100);
299 }
300 }
301
302
303
304 /**
305 * Runs a text item on a frame as a SIMPLE statement. The statement is
306 * parsed and if it is a recognised SIMPLE keyword or procedure the code is
307 * executed.
308 *
309 * @param code
310 * the item containing the code to be executed.
311 * @param context
312 * @return
313 * @throws Exception
314 */
315 private static Status RunItem(Text code, Context context, Scriptable scope, Status lastItemStatus) throws Exception {
316 if (_stop) {
317 throw new Exception("Program terminated");
318 }
319
320 if (code.getLink() != null) {
321 return RunFrameAndReportError(code, context, scope);
322 }
323 else {
324 String statement = code.getText().trim();
325
326 try {
327
328 Object result = context.evaluateString(scope, statement,"<expeditee item>", 0, null);
329 if (result != org.mozilla.javascript.Context.getUndefinedValue()) {
330 System.err.println(org.mozilla.javascript.Context.toString(result));
331 }
332 }
333
334 catch (WrappedException we) {
335 // Some form of exception was caught by JavaScript and
336 // propagated up.
337 System.err.println(we.getWrappedException().toString());
338 we.printStackTrace();
339 throw we;
340 }
341 catch (EvaluatorException ee) {
342 // Some form of JavaScript error.
343 System.err.println("js: " + ee.getMessage());
344 throw ee;
345 }
346 catch (JavaScriptException jse) {
347 // Some form of JavaScript error.
348 System.err.println("js: " + jse.getMessage());
349 throw jse;
350 }
351
352 }
353
354
355 return Status.OK;
356 }
357
358 public static void stop() {
359 _stop = true;
360 if (_agent != null) {
361 _agent.stop();
362 }
363 }
364
365 public static void nextStatement() {
366 _nextStatement = true;
367 }
368
369 public static void ProgramStarted() {
370 _programsRunning++;
371 AgentStats.reset();
372 MessageBay.displayMessage("Running Javascript Program ...", Color.BLUE);
373 }
374
375
376}
Note: See TracBrowser for help on using the repository browser.