diff options
author | Tomas O'Connor <toconnor@openoffice.org> | 2003-10-15 16:18:31 +0000 |
---|---|---|
committer | Tomas O'Connor <toconnor@openoffice.org> | 2003-10-15 16:18:31 +0000 |
commit | 8adddd008908ddb49d80f63279b7f475f0035d21 (patch) | |
tree | 79a0c09e4f4d4858c00ef030af89b5e6a29eb6ed /scripting | |
parent | 35644b06ea95a418518ceb722da80c0b3aa7842d (diff) |
#i19258# - add java script selector prototype, add edit functionality
Diffstat (limited to 'scripting')
4 files changed, 680 insertions, 8 deletions
diff --git a/scripting/java/com/sun/star/script/framework/browse/ParcelBrowseNode.java b/scripting/java/com/sun/star/script/framework/browse/ParcelBrowseNode.java index 2c28e3d326b2..daf48ccea02c 100644 --- a/scripting/java/com/sun/star/script/framework/browse/ParcelBrowseNode.java +++ b/scripting/java/com/sun/star/script/framework/browse/ParcelBrowseNode.java @@ -2,9 +2,9 @@ * * $RCSfile: ParcelBrowseNode.java,v $ * - * $Revision: 1.2 $ + * $Revision: 1.3 $ * - * last change: $Author: dfoster $ $Date: 2003-10-09 14:37:43 $ + * last change: $Author: toconnor $ $Date: 2003-10-15 17:18:29 $ * * The Contents of this file are made available subject to the terms of * either of the following licenses @@ -74,6 +74,7 @@ import java.util.*; public class ParcelBrowseNode extends PropertySet implements XBrowseNode { private ParcelDescriptor pd; + private File dir; private String name; private String location; private Collection browsenodes; @@ -91,6 +92,7 @@ public class ParcelBrowseNode extends PropertySet implements XBrowseNode { public ParcelBrowseNode(XComponentContext ctx, File dir) { this(dir.getName()); + this.dir = dir; this.m_XCtx = ctx; this.location = PathUtils.toScriptLocation( m_XCtx, dir.getAbsolutePath() ); this.pd = ParcelDescriptor.getParcelDescriptor(dir); @@ -146,7 +148,14 @@ public class ParcelBrowseNode extends PropertySet implements XBrowseNode { if (entries != null) { for (int i = 0; i < entries.length; i++) { - browsenodes.add(new ScriptBrowseNode(entries[i], location)); + ScriptBrowseNode sbn; + if (dir != null) { + sbn = new ScriptBrowseNode(entries[i], location, dir); + } + else { + sbn = new ScriptBrowseNode(entries[i], location); + } + browsenodes.add(sbn); } } } diff --git a/scripting/java/com/sun/star/script/framework/browse/ScriptBrowseNode.java b/scripting/java/com/sun/star/script/framework/browse/ScriptBrowseNode.java index e695055d228a..63646d55bb94 100644 --- a/scripting/java/com/sun/star/script/framework/browse/ScriptBrowseNode.java +++ b/scripting/java/com/sun/star/script/framework/browse/ScriptBrowseNode.java @@ -2,9 +2,9 @@ * * $RCSfile: ScriptBrowseNode.java,v $ * - * $Revision: 1.5 $ + * $Revision: 1.6 $ * - * last change: $Author: npower $ $Date: 2003-10-15 15:03:41 $ + * last change: $Author: toconnor $ $Date: 2003-10-15 17:18:29 $ * * The Contents of this file are made available subject to the terms of * either of the following licenses @@ -63,26 +63,35 @@ package com.sun.star.script.framework.browse; import drafts.com.sun.star.script.framework.browse.XBrowseNode; import drafts.com.sun.star.script.framework.browse.BrowseNodeTypes; +import drafts.com.sun.star.script.framework.runtime.XScriptContext; + import com.sun.star.beans.PropertyAttribute; import com.sun.star.lib.uno.helper.PropertySet; import com.sun.star.uno.Type; -import java.util.*; +import com.sun.star.beans.XIntrospectionAccess; +import com.sun.star.script.XInvocation; -public class ScriptBrowseNode extends PropertySet implements XBrowseNode { +import java.io.File; +public class ScriptBrowseNode extends PropertySet + implements XBrowseNode, XInvocation +{ private String name; + private ScriptEntry entry; + private File basedir; public String uri; public boolean editable = false; public boolean deletable = false; public ScriptBrowseNode(ScriptEntry entry, String location) { + this.entry = entry; + uri = "vnd.sun.star.script://" + entry.getLanguageName() + "?" + "language=" + entry.getLanguage() + "&location=" + location; - System.out.println("Creating ScriptBrowseNode: " + uri); name = entry.getLanguageName(); if (!entry.getLanguage().toLowerCase().equals("java") && @@ -100,6 +109,11 @@ public class ScriptBrowseNode extends PropertySet implements XBrowseNode { (short)0, "uri"); } + public ScriptBrowseNode(ScriptEntry entry, String location, File basedir) { + this(entry, location); + this.basedir = basedir; + } + public String getName() { return name; } @@ -119,4 +133,134 @@ public class ScriptBrowseNode extends PropertySet implements XBrowseNode { public String toString() { return getName(); } + + // implementation of XInvocation interface + public XIntrospectionAccess getIntrospection() { + return null; + } + + public Object invoke(String aFunctionName, Object[] aParams, + short[][] aOutParamIndex, Object[][] aOutParam) + throws com.sun.star.lang.IllegalArgumentException, + com.sun.star.script.CannotConvertException, + com.sun.star.reflection.InvocationTargetException + { + System.out.println("in ScriptBrowseNode.invoke"); + + if (aFunctionName.equals("Editable")) { + if (!editable) { + throw new com.sun.star.reflection.InvocationTargetException( + "Script not editable"); + } + + if (basedir == null || !basedir.exists()) { + throw new com.sun.star.lang.IllegalArgumentException( + "Cannot find script directory: " + + basedir.getAbsolutePath()); + } + + File sourcefile = new File(basedir, entry.getLanguageName()); + if (!sourcefile.exists()) { + throw new com.sun.star.lang.IllegalArgumentException( + "Cannot find script source file: " + + sourcefile.getAbsolutePath()); + } + + if (aParams == null || aParams.length < 1) { + throw new com.sun.star.lang.IllegalArgumentException( + "XScriptContext not provided"); + } + + XScriptContext ctxt; + try { + ctxt = (XScriptContext) aParams[0]; + } + catch (ClassCastException cce) { + throw new com.sun.star.lang.IllegalArgumentException( + "Wrong type for editor parameter: " + + aParams[0].getClass().getName()); + } + + String name = "com.sun.star.script.framework.provider." + + entry.getLanguage().toLowerCase() + ".ScriptEditorFor" + + entry.getLanguage(); + + try + { + Class c = Class.forName(name); + Class[] types = + new Class[] { XScriptContext.class, String.class }; + + java.lang.reflect.Method m = c.getMethod("edit", types); + + if (m != null) { + System.out.println("got a script editor"); + Object[] args = new Object[] { + ctxt, sourcefile.getAbsolutePath() }; + m.invoke(c.newInstance(), args); + } + else { + throw new com.sun.star.reflection.InvocationTargetException( + "No edit method found for Editor"); + } + } + catch ( ClassNotFoundException cnfe ) + { + throw new com.sun.star.reflection.InvocationTargetException( + "Exception getting Editor: " + cnfe.getMessage()); + } + catch ( NoSuchMethodException nsme ) + { + throw new com.sun.star.reflection.InvocationTargetException( + "Exception getting Editor: " + nsme.getMessage()); + } + catch ( InstantiationException ie ) + { + throw new com.sun.star.reflection.InvocationTargetException( + "Exception getting Editor: " + ie.getMessage()); + } + catch ( IllegalAccessException iae ) + { + throw new com.sun.star.reflection.InvocationTargetException( + "Exception getting Editor: " + iae.getMessage()); + } + catch ( java.lang.IllegalArgumentException iarge ) + { + throw new com.sun.star.reflection.InvocationTargetException( + "Exception getting Editor: " + iarge.getMessage()); + } + catch ( java.lang.reflect.InvocationTargetException ite ) + { + throw new com.sun.star.reflection.InvocationTargetException( + "Exception getting Editor: " + ite.getMessage()); + } + } + else { + throw new com.sun.star.lang.IllegalArgumentException( + "Function " + aFunctionName + " not supported."); + } + + return null; + } + + public void setValue(String aPropertyName, Object aValue) + throws com.sun.star.beans.UnknownPropertyException, + com.sun.star.script.CannotConvertException, + com.sun.star.reflection.InvocationTargetException + { + } + + public Object getValue(String aPropertyName) + throws com.sun.star.beans.UnknownPropertyException + { + return null; + } + + public boolean hasMethod(String aName) { + return false; + } + + public boolean hasProperty(String aName) { + return false; + } } diff --git a/scripting/java/com/sun/star/script/framework/provider/beanshell/ScriptEditorForBeanShell.java b/scripting/java/com/sun/star/script/framework/provider/beanshell/ScriptEditorForBeanShell.java new file mode 100644 index 000000000000..d5fcdd72c28c --- /dev/null +++ b/scripting/java/com/sun/star/script/framework/provider/beanshell/ScriptEditorForBeanShell.java @@ -0,0 +1,381 @@ +package com.sun.star.script.framework.provider.beanshell; + +import javax.swing.JFrame; +import javax.swing.JTextArea; +import javax.swing.JPanel; +import javax.swing.JScrollPane; +import javax.swing.JButton; +import javax.swing.JComponent; +import javax.swing.JFileChooser; +import javax.swing.JOptionPane; +import javax.swing.text.Document; +import javax.swing.event.DocumentListener; +import javax.swing.event.DocumentEvent; + +import java.awt.FlowLayout; +import java.awt.Graphics; +import java.awt.Color; +import java.awt.Font; +import java.awt.FontMetrics; +import java.awt.Polygon; +import java.awt.Rectangle; +import java.awt.Dimension; +import java.awt.event.ActionListener; +import java.awt.event.ActionEvent; + +import java.io.File; +import java.io.InputStream; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; + +import drafts.com.sun.star.script.framework.runtime.XScriptContext; +import bsh.Interpreter; + +public class ScriptEditorForBeanShell + implements ActionListener, DocumentListener { + + private JFrame frame; + private JTextArea ta; + private GlyphGutter gg; + private XScriptContext context; + private int currentPosition = -1; + private int linecount; + private Interpreter sessionInterpreter; + private Thread execThread = null; + private String filename = null; + + public void edit(XScriptContext context, String path) { + go(context, path); + } + + /* Entry point for script execution */ + public void go(XScriptContext context, String filename) { + if (filename != null && filename != "") { + try { + FileInputStream fis = new FileInputStream(filename); + this.filename = filename; + go(context, fis); + } + catch (IOException ioe) { + JOptionPane.showMessageDialog(frame, + "Error loading file: " + ioe.getMessage(), + "Error", JOptionPane.ERROR_MESSAGE); + } + } + } + + /* Entry point for script execution */ + public void go(XScriptContext context, InputStream in) { + this.context = context; + initUI(); + + if (in != null) { + try { + loadFile(in); + } + catch (IOException ioe) { + JOptionPane.showMessageDialog(frame, + "Error loading stream: " + ioe.getMessage(), + "Error", JOptionPane.ERROR_MESSAGE); + } + } + } + + public void loadFile(InputStream in) throws IOException { + + /* Remove ourselves as a DocumentListener while loading the file + so we don't get a storm of DocumentEvents during loading */ + ta.getDocument().removeDocumentListener(this); + + byte[] contents = new byte[1024]; + int len = 0, pos = 0; + + while ((len = in.read(contents, 0, 1024)) != -1) { + ta.insert(new String(contents, 0, len), pos); + pos += len; + } + + try { + in.close(); + } + catch (IOException ignore) { + } + + /* Update the GlyphGutter and add back the DocumentListener */ + gg.update(); + ta.getDocument().addDocumentListener(this); + } + + private void initUI() { + frame = new JFrame("BeanShell Debug Window"); + ta = new JTextArea(); + ta.setRows(15); + ta.setColumns(40); + ta.setLineWrap(false); + linecount = ta.getLineCount(); + + gg = new GlyphGutter(this); + + final JScrollPane sp = new JScrollPane(); + sp.setViewportView(ta); + sp.setRowHeaderView(gg); + + ta.getDocument().addDocumentListener(this); + String[] labels = {"Run", "Clear", "Save", "Close"}; + JPanel p = new JPanel(); + p.setLayout(new FlowLayout()); + + for (int i = 0; i < labels.length; i++) { + JButton b = new JButton(labels[i]); + b.addActionListener(this); + p.add(b); + + if (labels[i].equals("Save") && filename == null) { + b.setEnabled(false); + } + } + + frame.getContentPane().add(sp, "Center"); + frame.getContentPane().add(p, "South"); + frame.pack(); + frame.show(); + } + + /* Implementation of DocumentListener interface */ + public void insertUpdate(DocumentEvent e) { + doChanged(e); + } + + public void removeUpdate(DocumentEvent e) { + doChanged(e); + } + + public void changedUpdate(DocumentEvent e) { + doChanged(e); + } + + /* If the number of lines in the JTextArea has changed then update the + GlyphGutter */ + public void doChanged(DocumentEvent e) { + if (linecount != ta.getLineCount()) { + gg.update(); + linecount = ta.getLineCount(); + } + } + + private void startExecution() { + execThread = new Thread() { + public void run() { + Interpreter interpreter = new Interpreter(); + interpreter.getNameSpace().clear(); + + // reset position and repaint gutter so no red arrow appears + currentPosition = -1; + gg.repaint(); + + try { + interpreter.set("context", context); + interpreter.eval(ta.getText()); + } + catch (bsh.EvalError err) { + currentPosition = err.getErrorLineNumber() - 1; + try { + // scroll to line of the error + int line = ta.getLineStartOffset(currentPosition); + Rectangle rect = ta.modelToView(line); + ta.scrollRectToVisible(rect); + } + catch (Exception e) { + // couldn't scroll to line, do nothing + } + gg.repaint(); + + JOptionPane.showMessageDialog(frame, "Error at line " + + String.valueOf(err.getErrorLineNumber()) + + "\n\n: " + err.getErrorText(), + "Error", JOptionPane.ERROR_MESSAGE); + } + catch (Exception e) { + JOptionPane.showMessageDialog(frame, + "Error: " + e.getMessage(), + "Error", JOptionPane.ERROR_MESSAGE); + } + } + }; + execThread.start(); + } + + private void promptForSaveName() { + JFileChooser chooser = new JFileChooser(); + chooser.setFileFilter(new javax.swing.filechooser.FileFilter() { + public boolean accept(File f) { + if (f.isDirectory() || f.getName().endsWith(".bsh")) { + return true; + } + return false; + } + + public String getDescription() { + return ("BeanShell files: *.bsh"); + } + }); + + int ret = chooser.showSaveDialog(frame); + + if (ret == JFileChooser.APPROVE_OPTION) { + filename = chooser.getSelectedFile().getAbsolutePath(); + if (!filename.endsWith(".bsh")) { + filename += ".bsh"; + } + } + + } + + private void saveTextArea() { + if (filename == null) { + promptForSaveName(); + } + + FileOutputStream fos = null; + if (filename != null) { + try { + File f = new File(filename); + fos = new FileOutputStream(f); + String s = ta.getText(); + fos.write(s.getBytes(), 0, s.length()); + } + catch (IOException ioe) { + JOptionPane.showMessageDialog(frame, + "Error saving file: " + ioe.getMessage(), + "Error", JOptionPane.ERROR_MESSAGE); + } + finally { + if (fos != null) { + try { + fos.close(); + } + catch (IOException ignore) { + } + } + } + } + } + + public void actionPerformed(ActionEvent e) { + if (e.getActionCommand().equals("Run")) { + startExecution(); + } + else if (e.getActionCommand().equals("Close")) { + frame.dispose(); + } + else if (e.getActionCommand().equals("Save")) { + saveTextArea(); + } + else if (e.getActionCommand().equals("Clear")) { + ta.setText(""); + } + } + + public JTextArea getTextArea() { + return ta; + } + + public int getCurrentPosition() { + return currentPosition; + } +} + +class GlyphGutter extends JComponent { + + private ScriptEditorForBeanShell debugger; + private final String DUMMY_STRING = "99"; + + GlyphGutter(ScriptEditorForBeanShell debugger) { + this.debugger = debugger; + update(); + } + + public void update() { + JTextArea textArea = debugger.getTextArea(); + Font font = textArea.getFont(); + setFont(font); + + FontMetrics metrics = getFontMetrics(font); + int h = metrics.getHeight(); + int lineCount = textArea.getLineCount() + 1; + + String dummy = Integer.toString(lineCount); + if (dummy.length() < 2) { + dummy = DUMMY_STRING; + } + + Dimension d = new Dimension(); + d.width = metrics.stringWidth(dummy) + 16; + d.height = lineCount * h + 100; + setPreferredSize(d); + setSize(d); + } + + public void paintComponent(Graphics g) { + JTextArea textArea = debugger.getTextArea(); + + Font font = textArea.getFont(); + g.setFont(font); + + FontMetrics metrics = getFontMetrics(font); + Rectangle clip = g.getClipBounds(); + + g.setColor(getBackground()); + g.fillRect(clip.x, clip.y, clip.width, clip.height); + + int ascent = metrics.getMaxAscent(); + int h = metrics.getHeight(); + int lineCount = textArea.getLineCount() + 1; + + int startLine = clip.y / h; + int endLine = (clip.y + clip.height) / h + 1; + int width = getWidth(); + if (endLine > lineCount) { + endLine = lineCount; + } + + for (int i = startLine; i < endLine; i++) { + String text; + text = Integer.toString(i + 1) + " "; + int w = metrics.stringWidth(text); + int y = i * h; + g.setColor(Color.blue); + g.drawString(text, 0, y + ascent); + int x = width - ascent; + + // if currentPosition is not -1 then a red arrow will be drawn + if (i == debugger.getCurrentPosition()) { + drawArrow(g, ascent, x, y); + } + } + } + + private void drawArrow(Graphics g, int ascent, int x, int y) { + Polygon arrow = new Polygon(); + int dx = x; + y += ascent - 10; + int dy = y; + arrow.addPoint(dx, dy + 3); + arrow.addPoint(dx + 5, dy + 3); + for (x = dx + 5; x <= dx + 10; x++, y++) { + arrow.addPoint(x, y); + } + for (x = dx + 9; x >= dx + 5; x--, y++) { + arrow.addPoint(x, y); + } + arrow.addPoint(dx + 5, dy + 7); + arrow.addPoint(dx, dy + 7); + + g.setColor(Color.red); + g.fillPolygon(arrow); + g.setColor(Color.black); + g.drawPolygon(arrow); + } +}; + diff --git a/scripting/java/com/sun/star/script/framework/provider/javascript/ScriptEditorForJavaScript.java b/scripting/java/com/sun/star/script/framework/provider/javascript/ScriptEditorForJavaScript.java new file mode 100644 index 000000000000..fb7c591bd543 --- /dev/null +++ b/scripting/java/com/sun/star/script/framework/provider/javascript/ScriptEditorForJavaScript.java @@ -0,0 +1,138 @@ +/************************************************************************* + * + * $RCSfile: ScriptEditorForJavaScript.java,v $ + * + * $Revision: 1.1 $ + * + * last change: $Author: toconnor $ $Date: 2003-10-15 17:18:31 $ + * + * The Contents of this file are made available subject to the terms of + * either of the following licenses + * + * - GNU Lesser General Public License Version 2.1 + * - Sun Industry Standards Source License Version 1.1 + * + * Sun Microsystems Inc., October, 2000 + * + * GNU Lesser General Public License Version 2.1 + * ============================================= + * Copyright 2000 by Sun Microsystems, Inc. + * 901 San Antonio Road, Palo Alto, CA 94303, USA + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software Foundation. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * + * Sun Industry Standards Source License Version 1.1 + * ================================================= + * The contents of this file are subject to the Sun Industry Standards + * Source License Version 1.1 (the "License"); You may not use this file + * except in compliance with the License. You may obtain a copy of the + * License at http://www.openoffice.org/license.html. + * + * Software provided under this License is provided on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, + * WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS, + * MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING. + * See the License for the specific provisions governing your rights and + * obligations concerning the Software. + * + * The Initial Developer of the Original Code is: Sun Microsystems, Inc. + * + * Copyright: 2000 by Sun Microsystems, Inc. + * + * All Rights Reserved. + * + * Contributor(s): _______________________________________ + * + * + ************************************************************************/ + +package com.sun.star.script.framework.provider.javascript; + +import javax.swing.SwingUtilities; +import java.io.InputStream; + +import org.mozilla.javascript.Context; +import org.mozilla.javascript.Scriptable; +import org.mozilla.javascript.ImporterTopLevel; +import org.mozilla.javascript.tools.debugger.Main; +import org.mozilla.javascript.tools.debugger.ScopeProvider; + +import drafts.com.sun.star.script.framework.runtime.XScriptContext; + +public class ScriptEditorForJavaScript { + + public void edit(final XScriptContext xsctxt, String filename) { + Main sdb = initUI(xsctxt); + + // This is the method we've added to open a file when starting + // the Rhino debugger + sdb.openFile(filename); + } + + public void go(final XScriptContext xsctxt, InputStream in) { + Main sdb = initUI(xsctxt); + + // Open a stream in the debugger + sdb.openStream(in); + } + + // This code is based on the main method of the Rhino Debugger Main class + // We pass in the XScriptContext in the global scope for script execution + private Main initUI(final XScriptContext xsctxt) { + try { + final Main sdb = new Main("Rhino JavaScript Debugger"); + swingInvoke(new Runnable() { + public void run() { + sdb.pack(); + sdb.setSize(640, 640); + sdb.setVisible(true); + } + }); + sdb.setExitAction(new Runnable() { + public void run() { + sdb.dispose(); + } + }); + Context.addContextListener(sdb); + sdb.setScopeProvider(new ScopeProvider() { + public Scriptable getScope() { + Context ctxt = Context.enter(); + ImporterTopLevel scope = new ImporterTopLevel(ctxt); + Scriptable jsArgs = Context.toObject(xsctxt, scope); + scope.put("XSCRIPTCONTEXT", scope, jsArgs); + Context.exit(); + return scope; + } + }); + return sdb; + } catch (Exception exc) { + exc.printStackTrace(); + } + return null; + } + + static void swingInvoke(Runnable f) { + if (SwingUtilities.isEventDispatchThread()) { + f.run(); + return; + } + try { + SwingUtilities.invokeAndWait(f); + } catch (Exception exc) { + exc.printStackTrace(); + } + } +} |