xref: /trunk/main/rhino/rhino1_7R3.patch (revision 86e1cf34)
1Index: toolsrc/org/mozilla/javascript/tools/debugger/GuiCallback.java
2===================================================================
3--- toolsrc/org/mozilla/javascript/tools/debugger/GuiCallback.java	(revision 1)
4+++ misc/build/rhino1_7R3/toolsrc/org/mozilla/javascript/tools/debugger/GuiCallback.java	(working copy)
5@@ -56,6 +56,11 @@
6                         String threadTitle,
7                         String alertMessage);
8
9+	/**
10+	 * Called when the interrupt loop has been exited.
11+	 */
12+	void exitInterrupt();
13+
14     /**
15      * Returns whether the current thread is the GUI's event thread.
16      * This information is required to avoid blocking the event thread
17Index: toolsrc/org/mozilla/javascript/tools/debugger/Main.java
18===================================================================
19--- toolsrc/org/mozilla/javascript/tools/debugger/Main.java	(revision 1)
20+++ misc/build/rhino1_7R3/toolsrc/org/mozilla/javascript/tools/debugger/Main.java	(working copy)
21@@ -44,6 +44,8 @@
22 import java.io.InputStream;
23 import java.io.PrintStream;
24
25+import java.net.URL;
26+
27 import javax.swing.JFrame;
28
29 import org.mozilla.javascript.*;
30@@ -161,7 +163,7 @@
31      * Console window.
32      */
33     public InputStream getIn() {
34-        return debugGui.getConsole().getIn();
35+        return null;//return debugGui.getConsole().getIn();
36     }
37
38     /**
39@@ -169,7 +171,7 @@
40      * Console window.
41      */
42     public PrintStream getOut() {
43-        return debugGui.getConsole().getOut();
44+        return null;//return debugGui.getConsole().getOut();
45     }
46
47     /**
48@@ -177,7 +179,7 @@
49      * Console window.
50      */
51     public PrintStream getErr() {
52-        return debugGui.getConsole().getErr();
53+        return null;//return debugGui.getConsole().getErr();
54     }
55
56     /**
57@@ -437,4 +439,39 @@
58             return scope;
59         }
60     }
61+
62+    // shortcut methods
63+
64+    public void addWindowListener(java.awt.event.WindowListener l) {
65+        debugGui.addWindowListener(l);
66+    }
67+
68+    public void highlighLineInScriptWindow(URL url, int lineNum) {
69+		debugGui.highlighLineInScriptWindow(url, lineNum);
70+	}
71+
72+    public Object runScriptWindow(URL scriptUrl) throws Exception
73+    {
74+		return debugGui.runScriptWindow(scriptUrl);
75+	}
76+
77+    public void openFile(URL scriptUrl, Scriptable scope, Runnable closeCallback) {
78+		debugGui.openFile(scriptUrl, scope, closeCallback);
79+	}
80+
81+    public void toFront() {
82+		debugGui.toFront();
83+	}
84+
85+    public void showScriptWindow(URL url) {
86+		debugGui.showScriptWindow(url);
87+	}
88+
89+    public boolean isModified(URL url) {
90+		return debugGui.isModified(url);
91+	}
92+
93+	public String getText(URL url) {
94+		return debugGui.getText(url);
95+	}
96 }
97Index: toolsrc/org/mozilla/javascript/tools/debugger/Dim.java
98===================================================================
99--- toolsrc/org/mozilla/javascript/tools/debugger/Dim.java	(revision 1)
100+++ misc/build/rhino1_7R3/toolsrc/org/mozilla/javascript/tools/debugger/Dim.java	(working copy)
101@@ -69,6 +69,7 @@
102     private static final int IPROXY_OBJECT_TO_STRING = 5;
103     private static final int IPROXY_OBJECT_PROPERTY = 6;
104     private static final int IPROXY_OBJECT_IDS = 7;
105+    private static final int IPROXY_EVAL_SCRIPT_WITH_RETURN = 8;
106
107     /**
108      * Interface to the debugger GUI.
109@@ -433,7 +434,7 @@
110      */
111     private String getNormalizedUrl(DebuggableScript fnOrScript) {
112         String url = fnOrScript.getSourceName();
113-        if (url == null) { url = "<stdin>"; }
114+        if (url == null) { url = "document"; }
115         else {
116             // Not to produce window for eval from different lines,
117             // strip line numbers, i.e. replace all #[0-9]+\(eval\) by
118@@ -622,6 +623,17 @@
119     }
120
121     /**
122+     * Evaluates the given script with scope and return value.
123+     */
124+    public Object evalScriptWithReturn(final String url, final String text, Scriptable scope) {
125+        DimIProxy action = new DimIProxy(this, IPROXY_EVAL_SCRIPT_WITH_RETURN);
126+        action.url = url;
127+        action.text = text;
128+        action.scope = scope;
129+        return contextFactory.call(action);
130+    }
131+
132+    /**
133      * Converts the given script object to a string.
134      */
135     public String objectToString(Object object) {
136@@ -869,6 +881,7 @@
137                 interruptedContextData = null;
138                 eventThreadMonitor.notifyAll();
139             }
140+            callback.exitInterrupt();
141         }
142
143     }
144@@ -966,6 +979,11 @@
145         private Object[] objectArrayResult;
146
147         /**
148+         * The Scriptable as arguments.
149+         */
150+        private Scriptable scope;
151+
152+        /**
153          * Creates a new DimIProxy.
154          */
155         private DimIProxy(Dim dim, int type) {
156@@ -1021,6 +1039,9 @@
157                 objectArrayResult = dim.getObjectIdsImpl(cx, object);
158                 break;
159
160+              case IPROXY_EVAL_SCRIPT_WITH_RETURN:
161+                return cx.evaluateString(this.scope, text, url, 1, null);
162+
163               default:
164                 throw Kit.codeBug();
165             }
166Index: toolsrc/org/mozilla/javascript/tools/debugger/SwingGui.java
167===================================================================
168--- toolsrc/org/mozilla/javascript/tools/debugger/SwingGui.java	(revision 1)
169+++ misc/build/rhino1_7R3/toolsrc/org/mozilla/javascript/tools/debugger/SwingGui.java	(working copy)
170@@ -68,6 +68,8 @@
171 import java.awt.Toolkit;
172 import java.awt.event.*;
173
174+import java.net.URL;
175+
176 import java.util.List;
177 import java.util.ArrayList;
178 import java.util.Arrays;
179@@ -84,6 +86,7 @@
180 import java.lang.reflect.Method;
181
182 import org.mozilla.javascript.Kit;
183+import org.mozilla.javascript.Scriptable;
184 import org.mozilla.javascript.SecurityUtilities;
185
186 import org.mozilla.javascript.tools.shell.ConsoleTextArea;
187@@ -178,6 +181,16 @@
188      */
189     private EventQueue awtEventQueue;
190
191+    private boolean sourceEditingEnabled = true;
192+
193+    public boolean isSourceEditingEnabled() {
194+        return sourceEditingEnabled;
195+    }
196+
197+    public void setSourceEditingEnabled(boolean b) {
198+        sourceEditingEnabled = b;
199+    }
200+
201     /**
202      * Creates a new SwingGui.
203      */
204@@ -218,13 +231,13 @@
205         super.setVisible(b);
206         if (b) {
207             // this needs to be done after the window is visible
208-            console.consoleTextArea.requestFocus();
209+            // console.consoleTextArea.requestFocus();
210             context.split.setDividerLocation(0.5);
211             try {
212-                console.setMaximum(true);
213-                console.setSelected(true);
214-                console.show();
215-                console.consoleTextArea.requestFocus();
216+                // console.setMaximum(true);
217+                // console.setSelected(true);
218+                // console.show();
219+                // console.consoleTextArea.requestFocus();
220             } catch (Exception exc) {
221             }
222         }
223@@ -320,7 +333,7 @@
224         desk = new JDesktopPane();
225         desk.setPreferredSize(new Dimension(600, 300));
226         desk.setMinimumSize(new Dimension(150, 50));
227-        desk.add(console = new JSInternalConsole("JavaScript Console"));
228+        // desk.add(console = new JSInternalConsole("JavaScript Console"));
229         context = new ContextWindow(this);
230         context.setPreferredSize(new Dimension(600, 120));
231         context.setMinimumSize(new Dimension(50, 50));
232@@ -540,7 +553,7 @@
233         if (line != -1) {
234             currentWindow = w;
235         }
236-        menubar.addFile(url);
237+        // menubar.addFile(url);
238         w.setVisible(true);
239
240         if (activate) {
241@@ -800,9 +813,17 @@
242             proxy.alertMessage = alertMessage;
243             SwingUtilities.invokeLater(proxy);
244         }
245+        setSourceEditingEnabled(false);
246     }
247
248     /**
249+     * Called when the interrupt loop has been exited.
250+     */
251+    public void exitInterrupt() {
252+        setSourceEditingEnabled(true);
253+    }
254+
255+    /**
256      * Returns whether the current thread is the GUI event thread.
257      */
258     public boolean isGuiEventThread() {
259@@ -879,6 +900,14 @@
260                     new Thread(proxy).start();
261                 }
262             }
263+        } else if (cmd.equals("Run")) {
264+            FileWindow w = (FileWindow)getSelectedFrame();
265+            if (w != null)
266+                w.load();
267+        } else if (cmd.equals("Save")) {
268+            FileWindow w = (FileWindow)getSelectedFrame();
269+            if (w != null)
270+                w.save();
271         } else if (cmd.equals("More Windows...")) {
272             MoreWindows dlg = new MoreWindows(this, fileWindows,
273                                               "Window", "Files");
274@@ -972,6 +1001,120 @@
275             dim.setReturnValue(returnValue);
276         }
277     }
278+
279+    private String getFileName(URL url) {
280+        if (url.getProtocol().startsWith("vnd.sun.star."))
281+            return url.toString();
282+        return url.getPath();
283+    }
284+
285+    public void openFile(URL scriptUrl, Scriptable scope, Runnable closeCallback) {
286+        if (scope == null) {
287+            MessageDialogWrapper.showMessageDialog(this,
288+                "Can't compile scripts: no scope available",
289+                "Open", JOptionPane.ERROR_MESSAGE);
290+        } else {
291+            if (scriptUrl != null) {
292+                try
293+                {
294+                    InputStreamReader reader = new InputStreamReader(scriptUrl.openStream());
295+                    String fileName = getFileName(scriptUrl);
296+                    officeScripts.addScript( fileName, scriptUrl, scope, closeCallback  );
297+                    RunProxy proxy = new RunProxy(this, RunProxy.OPEN_FILE);
298+                    proxy.fileName = fileName;
299+                    proxy.text = Kit.readReader(reader);
300+                    new Thread(proxy).start();
301+                }
302+                catch ( IOException e )
303+                {
304+                    MessageDialogWrapper.showMessageDialog(this,
305+                        "Can't open stream for script: " + e.toString(),
306+                        "Open", JOptionPane.ERROR_MESSAGE);
307+                }
308+            }
309+        }
310+        split1.setDividerLocation(1.0);
311+    }
312+
313+    // patched Office specific interface
314+    OfficeScriptInfo officeScripts = new OfficeScriptInfo();
315+
316+    void removeScript(String url) {
317+        officeScripts.deleteScript(url);
318+    }
319+
320+    public void showScriptWindow(URL url) {
321+        String key = getFileName(url);
322+        FileWindow w = (FileWindow)getFileWindow(key);
323+        if (w != null)
324+        {
325+            desk.getDesktopManager().deiconifyFrame(w);
326+            desk.getDesktopManager().activateFrame(w);
327+            w.show();
328+            w.toFront();
329+        }
330+    }
331+
332+    public void highlighLineInScriptWindow(URL url, int lineNum) {
333+        String key = getFileName(url);
334+        FileWindow w = (FileWindow)getFileWindow(key);
335+        if (w != null)
336+        {
337+            showFileWindow(key, lineNum);
338+        }
339+    }
340+
341+    public Object runScriptWindow(URL scriptUrl) throws Exception
342+    {
343+        String key = getFileName(scriptUrl);
344+        FileWindow w = (FileWindow)getFileWindow(key);
345+        Object result = null;
346+        w.toFront();
347+        if (w != null)
348+        {
349+            Scriptable scope = officeScripts.getScriptScope(key);
350+            if (scope == null)
351+            {
352+                MessageDialogWrapper.showMessageDialog(this, "Can't load scripts: no scope available", "Run", JOptionPane.ERROR_MESSAGE);
353+            }
354+            else
355+            {
356+                String url = w.getUrl();
357+                if (url != null)
358+                {
359+                    if (officeScripts.isScriptRunning(key))
360+                    {
361+                        return result;
362+                    }
363+                    officeScripts.setScriptRunning(key, true);
364+                    try {
365+                        result = dim.evalScriptWithReturn(url, w.textArea.getText(), scope);
366+                    } catch (Exception exc) {
367+                        exc.printStackTrace();
368+                        throw exc;
369+                    } finally {
370+                        officeScripts.setScriptRunning(key, false);
371+                    }
372+                }
373+            }
374+        }
375+        return result;
376+    }
377+
378+    public boolean isModified(URL url)
379+    {
380+        String key = getFileName(url);
381+        FileWindow w = (FileWindow)getFileWindow(key);
382+        return w.isModified();
383+    }
384+
385+    public String getText(URL url)
386+    {
387+        String key = getFileName(url);
388+        FileWindow w = (FileWindow)getFileWindow(key);
389+        return w.getText();
390+    }
391+
392 }
393
394 /**
395@@ -1590,7 +1733,9 @@
396         case KeyEvent.VK_ENTER:
397         case KeyEvent.VK_DELETE:
398         case KeyEvent.VK_TAB:
399-            e.consume();
400+            if (! w.isEditable()) {
401+                e.consume();
402+            }
403             break;
404         }
405     }
406@@ -1599,14 +1744,18 @@
407      * Called when a key is typed.
408      */
409     public void keyTyped(KeyEvent e) {
410-        e.consume();
411+        if (! w.isEditable()) {
412+            e.consume();
413+        }
414     }
415
416     /**
417      * Called when a key is released.
418      */
419     public void keyReleased(KeyEvent e) {
420-        e.consume();
421+        if (! w.isEditable()) {
422+            e.consume();
423+        }
424     }
425 }
426
427@@ -2089,7 +2238,7 @@
428 /**
429  * An internal frame for script files.
430  */
431-class FileWindow extends JInternalFrame implements ActionListener {
432+class FileWindow extends JInternalFrame implements ActionListener, DocumentListener {
433
434     /**
435      * Serializable magic number.
436@@ -2126,6 +2275,7 @@
437      */
438     int currentPos;
439
440+    boolean isModified = false;
441     /**
442      * Loads the file.
443      */
444@@ -2134,11 +2284,62 @@
445         if (url != null) {
446             RunProxy proxy = new RunProxy(debugGui, RunProxy.LOAD_FILE);
447             proxy.fileName = url;
448-            proxy.text = sourceInfo.source();
449+            proxy.text = textArea.getText();
450+            proxy.scope = debugGui.officeScripts.getScriptScope(url);
451             new Thread(proxy).start();
452         }
453     }
454
455+    void save() {
456+        String url = getUrl();
457+        if (url != null) {
458+            OutputStream os = null;
459+            try {
460+                if (url.startsWith("vnd.sun.star"))
461+                {
462+                    URL scriptUrl = debugGui.officeScripts.getScriptUrl(url);
463+                    if ( scriptUrl == null )
464+                    {
465+                        throw new IOException("Can't optain stream for " + url);
466+                    }
467+                    os = scriptUrl.openConnection().getOutputStream();
468+                }
469+                else
470+                {
471+                   os = new FileOutputStream(url);
472+                }
473+                String s = textArea.getText();
474+                os.write(s.getBytes(), 0, s.length());
475+
476+                this.isModified = false;
477+            } catch (IOException ioe) {
478+                MessageDialogWrapper.showMessageDialog(this,
479+                    "Error saving file: " + ioe.getMessage(),
480+                    "Error", JOptionPane.ERROR_MESSAGE);
481+            }
482+            finally
483+            {
484+                if ( os != null )
485+                {
486+                    try
487+                    {
488+                        os.close();
489+                        os = null;
490+                    }
491+                    catch( IOException ioe )
492+                    {
493+                        System.err.println("Error closing stream: " + ioe.getMessage() );
494+                        ioe.printStackTrace();
495+                    }
496+                }
497+            }
498+        }
499+    }
500+
501+    public boolean isEditable() {
502+        return debugGui.isSourceEditingEnabled();
503+    }
504+
505     /**
506      * Returns the offset position for the given line.
507      */
508@@ -2214,7 +2415,16 @@
509         pack();
510         updateText(sourceInfo);
511         textArea.select(0);
512+        addInternalFrameListener( new InternalFrameAdapter() {
513+            public void internalFrameClosed(InternalFrameEvent e) {
514+                getDebugGui().removeScript( getUrl() );
515+            }
516+        } );
517     }
518+
519+    public SwingGui getDebugGui() {
520+        return debugGui;
521+    }
522
523     /**
524      * Updates the tool tip contents.
525@@ -2249,7 +2459,10 @@
526         this.sourceInfo = sourceInfo;
527         String newText = sourceInfo.source();
528         if (!textArea.getText().equals(newText)) {
529+            textArea.getDocument().removeDocumentListener(this);
530             textArea.setText(newText);
531+            this.isModified = false;
532+            textArea.getDocument().addDocumentListener(this);
533             int pos = 0;
534             if (currentPos != -1) {
535                 pos = currentPos;
536@@ -2260,6 +2473,31 @@
537         fileHeader.repaint();
538     }
539
540+    /* Implementation of DocumentListener interface */
541+    public void insertUpdate(DocumentEvent e) {
542+        doChanged(e);
543+    }
544+
545+    public void removeUpdate(DocumentEvent e) {
546+        doChanged(e);
547+    }
548+
549+    public void changedUpdate(DocumentEvent e) {
550+        doChanged(e);
551+    }
552+
553+    public void doChanged(DocumentEvent e) {
554+        this.isModified = true;
555+    }
556+
557+    public boolean isModified() {
558+        return this.isModified;
559+    }
560+
561+    public String getText() {
562+        return textArea.getText();
563+    }
564+
565     /**
566      * Sets the cursor position.
567      */
568@@ -2295,11 +2533,11 @@
569     public void actionPerformed(ActionEvent e) {
570         String cmd = e.getActionCommand();
571         if (cmd.equals("Cut")) {
572-            // textArea.cut();
573+             textArea.cut();
574         } else if (cmd.equals("Copy")) {
575             textArea.copy();
576         } else if (cmd.equals("Paste")) {
577-            // textArea.paste();
578+             textArea.paste();
579         }
580     }
581 }
582@@ -2920,7 +3158,7 @@
583      */
584     public ContextWindow(final SwingGui debugGui) {
585         this.debugGui = debugGui;
586-        enabled = false;
587+        enabled = true;
588         JPanel left = new JPanel();
589         JToolBar t1 = new JToolBar();
590         t1.setName("Variables");
591@@ -3161,6 +3399,10 @@
592     public void enableUpdate() {
593         enabled = true;
594     }
595+
596+    public boolean isEnabled() {
597+        return enabled;
598+    }
599
600     // ActionListener
601
602@@ -3249,8 +3491,10 @@
603     Menubar(SwingGui debugGui) {
604         super();
605         this.debugGui = debugGui;
606-        String[] fileItems  = {"Open...", "Run...", "", "Exit"};
607-        String[] fileCmds  = {"Open", "Load", "", "Exit"};
608+        // String[] fileItems  = {"Open...", "Run...", "", "Exit"};
609+        // String[] fileCmds  = {"Open", "Load", "", "Exit"};
610+        String[] fileItems  = {"Run", "Save", "", "Exit"};
611+        String[] fileCmds  = {"Run", "Save", "", "Exit"};
612         char[] fileShortCuts = {'0', 'N', 0, 'X'};
613         int[] fileAccelerators = {KeyEvent.VK_O,
614                                   KeyEvent.VK_N,
615@@ -3299,6 +3543,8 @@
616                                            editShortCuts[i]);
617             item.addActionListener(this);
618             editMenu.add(item);
619+            if (i < 3)
620+                runOnlyItems.add(item);
621         }
622         for (int i = 0; i < plafItems.length; ++i) {
623             JMenuItem item = new JMenuItem(plafItems[i],
624@@ -3348,9 +3594,9 @@
625         item.addActionListener(this);
626         windowMenu.add(item = new JMenuItem("Tile", 'T'));
627         item.addActionListener(this);
628-        windowMenu.addSeparator();
629-        windowMenu.add(item = new JMenuItem("Console", 'C'));
630-        item.addActionListener(this);
631+        // windowMenu.addSeparator();
632+        // windowMenu.add(item = new JMenuItem("Console", 'C'));
633+        // item.addActionListener(this);
634         add(windowMenu);
635
636         updateEnabled(false);
637@@ -3530,6 +3776,11 @@
638      * interruption, if any.
639      */
640     String alertMessage;
641+
642+    /**
643+     * The arguments for evaluation.
644+     */
645+    Scriptable scope;
646
647     /**
648      * Creates a new RunProxy.
649@@ -3556,7 +3807,10 @@
650
651           case LOAD_FILE:
652             try {
653-                debugGui.dim.evalScript(fileName, text);
654+                if (scope != null)
655+                    debugGui.dim.evalScriptWithReturn(fileName, text, scope);
656+                else
657+                    debugGui.dim.evalScript(fileName, text);
658             } catch (RuntimeException ex) {
659                 MessageDialogWrapper.showMessageDialog(
660                     debugGui, ex.getMessage(), "Run error for "+fileName,
661Index: toolsrc/org/mozilla/javascript/tools/debugger/OfficeScriptInfo.java
662===================================================================
663--- toolsrc/org/mozilla/javascript/tools/debugger/OfficeScriptInfo.java	(revision 2)
664+++ misc/build/rhino1_7R3/toolsrc/org/mozilla/javascript/tools/debugger/OfficeScriptInfo.java	(working copy)
665@@ -1 +1,124 @@
666-dummy
667+/**************************************************************
668+ *
669+ * Licensed to the Apache Software Foundation (ASF) under one
670+ * or more contributor license agreements.  See the NOTICE file
671+ * distributed with this work for additional information
672+ * regarding copyright ownership.  The ASF licenses this file
673+ * to you under the Apache License, Version 2.0 (the
674+ * "License"); you may not use this file except in compliance
675+ * with the License.  You may obtain a copy of the License at
676+ *
677+ *   http://www.apache.org/licenses/LICENSE-2.0
678+ *
679+ * Unless required by applicable law or agreed to in writing,
680+ * software distributed under the License is distributed on an
681+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
682+ * KIND, either express or implied.  See the License for the
683+ * specific language governing permissions and limitations
684+ * under the License.
685+ *
686+ *************************************************************/
687+
688+
689+package org.mozilla.javascript.tools.debugger;
690+import java.net.URL;
691+import java.util.Hashtable;
692+import org.mozilla.javascript.Scriptable;
693+
694+public class OfficeScriptInfo
695+{
696+    private Hashtable<String, SFScriptInfo> loadedSFScripts = new Hashtable<String, SFScriptInfo>();
697+
698+    public void addScript( URL url, Scriptable scope, Runnable closeCallback )
699+    {
700+        addScript( url.toString(), url, scope, closeCallback );
701+    }
702+
703+    public void addScript( String key, URL url, Scriptable scope, Runnable closeCallback )
704+    {
705+        SFScriptInfo si = (SFScriptInfo)loadedSFScripts.get( key );
706+        if ( si == null )
707+        {
708+            si = new SFScriptInfo();
709+            si.url = url;
710+            si.scope = scope;
711+            si.closeCallback = closeCallback;
712+            loadedSFScripts.put( key, si );
713+        }
714+    }
715+
716+    public void deleteScript( String key )
717+    {
718+        SFScriptInfo info = (SFScriptInfo)loadedSFScripts.remove( key );
719+        if ( info != null )
720+        {
721+            if ( info.closeCallback != null )
722+            {
723+                System.out.println("** In removeSFScriptInfo  have callback for " + key );
724+                info.closeCallback.run(); // really need to do this in separate thread????
725+            }
726+        }
727+    }
728+
729+    public Scriptable getScriptScope( String key )
730+    {
731+        Scriptable result = null;
732+        SFScriptInfo info = (SFScriptInfo)loadedSFScripts.get( key );
733+        if ( info != null )
734+        {
735+            result = info.scope;
736+        }
737+        return result;
738+    }
739+
740+    public URL getScriptUrl( String key )
741+    {
742+        URL result = null;
743+        SFScriptInfo info = (SFScriptInfo)loadedSFScripts.get( key );
744+        if ( info != null )
745+        {
746+            result = info.url;
747+        }
748+        return result;
749+    }
750+    public boolean hasScript( String key )
751+    {
752+        boolean result = true;
753+        SFScriptInfo info = (SFScriptInfo)loadedSFScripts.get( key );
754+        if ( info == null )
755+        {
756+            result = false;
757+        }
758+        return result;
759+    }
760+
761+    public void setScriptRunning( String key, boolean running )
762+    {
763+        SFScriptInfo info = (SFScriptInfo)loadedSFScripts.get( key );
764+        if ( info != null )
765+        {
766+            info.isExecuting = running;
767+        }
768+    }
769+
770+    public boolean isScriptRunning( String key )
771+    {
772+        boolean result = false;
773+        SFScriptInfo info = (SFScriptInfo)loadedSFScripts.get( key );
774+        if ( info != null )
775+        {
776+            result = info.isExecuting;
777+        }
778+        return result;
779+    }
780+
781+
782+
783+    class SFScriptInfo
784+    {
785+        Scriptable scope;
786+        boolean isExecuting;
787+        URL url;
788+        Runnable closeCallback;
789+    }
790+}
791Index: toolsrc/build.xml
792===================================================================
793--- toolsrc/build.xml	(revision 1)
794+++ misc/build/rhino1_7R3/toolsrc/build.xml	(working copy)
795@@ -40,6 +40,24 @@
796 -->
797 <project name="toolsrc" default="compile" basedir="..">
798
799+  <condition property="boot_refID" value="macPath" else="nonMacPath">
800+    <and>
801+      <os family="mac"/>
802+      <os family="unix"/>
803+    </and>
804+  </condition>
805+  <path id="macPath" location="${java.home}/../Classes/classes.jar"/>
806+  <!-- rhino.jar from OpenJDK breaks build -->
807+  <path id="nonMacPath">
808+    <fileset dir="${java.home}/">
809+       <include name="jre/lib/*.jar"/>
810+       <include name="lib/*.jar"/>
811+       <exclude name="jre/lib/rhino.jar"/>
812+       <exclude name="lib/rhino.jar"/>
813+     </fileset>
814+  </path>
815+  <path id="my.bootstrap.classpath" refID="${boot_refID}"/>
816+
817   <target name="properties">
818     <property file="build.properties"/>
819   </target>
820Index: src/org/mozilla/javascript/DefiningClassLoader.java
821===================================================================
822--- src/org/mozilla/javascript/DefiningClassLoader.java	(revision 1)
823+++ misc/build/rhino1_7R3/src/org/mozilla/javascript/DefiningClassLoader.java	(working copy)
824@@ -39,6 +39,8 @@
825
826 package org.mozilla.javascript;
827
828+import java.lang.reflect.Method;
829+import java.lang.reflect.InvocationTargetException;
830 /**
831  * Load generated classes.
832  *
833@@ -48,13 +50,33 @@
834     implements GeneratedClassLoader
835 {
836     public DefiningClassLoader() {
837-        this.parentLoader = getClass().getClassLoader();
838+		this.parentLoader = getClass().getClassLoader();
839+        init();
840     }
841
842     public DefiningClassLoader(ClassLoader parentLoader) {
843-        this.parentLoader = parentLoader;
844+		this.parentLoader = parentLoader;
845+        init();
846     }
847
848+    private void init() {
849+        this.contextLoader = null;
850+        if (method_getContextClassLoader != null) {
851+            try {
852+                this.contextLoader = (ClassLoader)
853+                    method_getContextClassLoader.invoke(
854+                        Thread.currentThread(),
855+                        ScriptRuntime.emptyArgs);
856+            } catch (IllegalAccessException ex) {
857+            } catch (InvocationTargetException ex) {
858+            } catch (SecurityException ex) {
859+            }
860+            if (this.contextLoader == this.parentLoader) {
861+                this.contextLoader = null;
862+            }
863+        }
864+    }
865+
866     public Class<?> defineClass(String name, byte[] data) {
867         // Use our own protection domain for the generated classes.
868         // TODO: we might want to use a separate protection domain for classes
869@@ -73,10 +95,14 @@
870     {
871         Class<?> cl = findLoadedClass(name);
872         if (cl == null) {
873-            if (parentLoader != null) {
874-                cl = parentLoader.loadClass(name);
875+            if (contextLoader == null) {
876+                cl = loadFromParent(name);
877             } else {
878-                cl = findSystemClass(name);
879+                try {
880+                    cl = loadFromParent(name);
881+                } catch (ClassNotFoundException ex) {
882+                    cl = contextLoader.loadClass(name);
883+                }
884             }
885         }
886         if (resolve) {
887@@ -85,5 +111,36 @@
888         return cl;
889     }
890
891+    private Class loadFromParent(String name)
892+        throws ClassNotFoundException
893+    {
894+        if (parentLoader != null) {
895+            return parentLoader.loadClass(name);
896+        } else {
897+            return findSystemClass(name);
898+        }
899+    }
900+
901     private final ClassLoader parentLoader;
902+
903+    private ClassLoader contextLoader;
904+
905+    // We'd like to use "Thread.getContextClassLoader", but
906+    // that's only available on Java2.
907+    private static Method method_getContextClassLoader;
908+
909+    static {
910+        try {
911+            // Don't use "Thread.class": that performs the lookup
912+            // in the class initializer, which doesn't allow us to
913+            // catch possible security exceptions.
914+            Class threadClass = Class.forName("java.lang.Thread");
915+            method_getContextClassLoader =
916+                threadClass.getDeclaredMethod("getContextClassLoader",
917+                                               new Class[0]);
918+        } catch (ClassNotFoundException e) {
919+        } catch (NoSuchMethodException e) {
920+        } catch (SecurityException e) {
921+        }
922+    }
923 }
924