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

Last change on this file since 919 was 919, checked in by jts21, 10 years ago

Added license headers to all files, added full GPL3 license file, moved license header generator script to dev/bin/scripts

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