From 2111737cd2e8dab7e8fcb14bcefbd3a8cc897f75 Mon Sep 17 00:00:00 2001 From: ishmal Date: Mon, 31 Mar 2008 19:32:04 +0000 Subject: [PATCH] Move script dialog from gtkmm to jvm --- src/bind/java/org/inkscape/cmn/Gateway.java | 216 ++++++ src/bind/java/org/inkscape/cmn/Resource.java | 44 ++ .../java/org/inkscape/cmn/ScriptRunner.java | 338 --------- src/bind/java/org/inkscape/script/Editor.java | 49 ++ .../org/inkscape/script/ScriptConsole.java | 650 ++++++++++++++++++ .../java/org/inkscape/script/Terminal.java | 273 ++++++++ src/bind/javabind-private.h | 24 +- src/bind/javabind.cpp | 223 +++++- src/bind/javabind.h | 86 ++- src/extension/script/InkscapeScript.cpp | 16 +- src/verbs.cpp | 4 +- 11 files changed, 1509 insertions(+), 414 deletions(-) create mode 100644 src/bind/java/org/inkscape/cmn/Gateway.java create mode 100644 src/bind/java/org/inkscape/cmn/Resource.java delete mode 100644 src/bind/java/org/inkscape/cmn/ScriptRunner.java create mode 100644 src/bind/java/org/inkscape/script/Editor.java create mode 100644 src/bind/java/org/inkscape/script/ScriptConsole.java create mode 100644 src/bind/java/org/inkscape/script/Terminal.java diff --git a/src/bind/java/org/inkscape/cmn/Gateway.java b/src/bind/java/org/inkscape/cmn/Gateway.java new file mode 100644 index 000000000..00e720e32 --- /dev/null +++ b/src/bind/java/org/inkscape/cmn/Gateway.java @@ -0,0 +1,216 @@ +/** + * This is a simple mechanism to bind Inkscape to Java, and thence + * to all of the nice things that can be layered upon that. + * + * Authors: + * Bob Jamison + * + * Copyright (C) 2007-2008 Bob Jamison + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +package org.inkscape.cmn; + +import java.util.List; +import java.io.FileReader; +import java.io.PrintStream; +import java.io.OutputStream; +import java.io.IOException; +import javax.swing.JOptionPane; + +import org.inkscape.script.ScriptConsole; + + + +/** + * Provide a gateway from C to Java, to simplify adding + * interfaces. + */ +public class Gateway +{ +/** + * Pointer back to the BinderyImpl C++ object that launched me + */ +long backPtr; + + +//######################################################################## +//# MESSSAGES +//######################################################################## +static void err(String message) +{ + System.err.println("Gateway err:" + message); +} + +static void msg(String message) +{ + System.out.println("Gateway:" + message); +} + + + + +//######################################################################## +//# LOGGING STREAM +//######################################################################## + +public native void logWrite(long backptr, int ch); + +class LogStream extends OutputStream +{ + +public void write(int ch) +{ + logWrite(backPtr, ch); +} + +} + +PrintStream log = null; + +/** + * printf-style logging + */ +void log(String fmt, Object... args) +{ + log.printf("Gateway:" + fmt, args); +} + + +//######################################################################## +//# RUN +//######################################################################## + + +/** + * Run a script buffer + * + * @param backPtr pointer back to the C context that called this + * @param lang the scripting language to run + * @param str the script buffer to execute + * @return true if successful, else false + */ +public boolean scriptRun(String lang, String str) +{ + //wrap whole thing in try/catch, since this will + //likely be called from C + try + { + ScriptConsole console = ScriptConsole.getInstance(); + if (console == null) + { + err("ScriptConsole not initialized"); + return false; + } + return console.doRun(lang, str); + } + catch (Exception e) + { + err("run :" + e); + e.printStackTrace(); + return false; + } +} + + +/** + * Run a script file + * + * @param backPtr pointer back to the C context that called this + * @param lang the scripting language to run + * @param fname the script file to execute + * @return true if successful, else false + */ +public boolean scriptRunFile(String lang, String fname) +{ + //wrap whole thing in try/catch, since this will + //likely be called from C + try + { + { + ScriptConsole console = ScriptConsole.getInstance(); + if (console == null) + { + err("ScriptConsole not initialized"); + return false; + } + return console.doRun(lang, fname); + } + } + catch (Exception e) + { + err("scriptRunFile :" + e); + return false; + } +} + + + + + +//######################################################################## +//# C O N S O L E +//######################################################################## + + +public boolean showConsole() +{ + ScriptConsole.getInstance().setVisible(true); + return true; +} + + +//######################################################################## +//# CONSTRUCTOR +//######################################################################## + + + + +/** + * Constructor + * @param backPtr pointer back to the C context that called this + */ +public Gateway(long backPtr) +{ + /** + * Set up the logging stream + */ + log = new PrintStream(new LogStream()); + + //Point back to C++ object + this.backPtr = backPtr; + + _instance = this; +} + +private static Gateway _instance = null; + +public static Gateway getInstance(long backPtr) +{ + if (_instance == null) + { + _instance = new Gateway(backPtr); + } + return _instance; +} + +} +//######################################################################## +//# E N D O F F I L E +//######################################################################## + + diff --git a/src/bind/java/org/inkscape/cmn/Resource.java b/src/bind/java/org/inkscape/cmn/Resource.java new file mode 100644 index 000000000..a5a58a777 --- /dev/null +++ b/src/bind/java/org/inkscape/cmn/Resource.java @@ -0,0 +1,44 @@ + + +package org.inkscape.cmn; + +import java.awt.Image; +import javax.swing.ImageIcon; +import java.net.URL; + + + +/** + * This class will hold various functions for getting a + * resource from the classpath or jarfile + */ +public class Resource +{ + + +public static ImageIcon getIcon(String name) +{ + + String path = "/data/icons/" + name; + URL imgurl = Resource.class.getResource(path); + if (imgurl == null) + { + System.err.println("Icon '" + path + "' not found"); + return null; + } + ImageIcon icon = new ImageIcon(imgurl); + return icon; +} + +public static Image getImage(String name) +{ + + ImageIcon icon = getIcon(name); + if (icon == null) + return null; + return icon.getImage(); +} + + +} + diff --git a/src/bind/java/org/inkscape/cmn/ScriptRunner.java b/src/bind/java/org/inkscape/cmn/ScriptRunner.java deleted file mode 100644 index d05afd2e3..000000000 --- a/src/bind/java/org/inkscape/cmn/ScriptRunner.java +++ /dev/null @@ -1,338 +0,0 @@ -/** - * This is a simple mechanism to bind Inkscape to Java, and thence - * to all of the nice things that can be layered upon that. - * - * Authors: - * Bob Jamison - * - * Copyright (C) 2007-2008 Bob Jamison - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ - -package org.inkscape.cmn; - -import javax.script.*; -import java.util.List; -import java.io.FileReader; -import java.io.PrintStream; -import java.io.OutputStream; -import java.io.IOException; -import javax.swing.JOptionPane; - - -/** - * Runs scripts - */ -public class ScriptRunner -{ -/** - * Pointer back to the BinderyImpl C++ object that launched me - */ -long backPtr; - -/** - * The script engine manager that we want to use - */ -ScriptEngineManager scriptEngineManager; - - -//######################################################################## -//# MESSSAGES -//######################################################################## -static void err(String message) -{ - System.err.println("ScriptRunner err:" + message); -} - -static void msg(String message) -{ - System.out.println("ScriptRunner:" + message); -} - -static void trace(String message) -{ - log.println("ScriptRunner:" + message); -} - - - -//######################################################################## -//# REDIRECT STDERR / STDOUT -//######################################################################## -/** - * Redirect stdout - */ -public native void stdOutWrite(long ptr, int b); -class StdOutStream extends OutputStream -{ - -public void write(int b) -{ - stdOutWrite(backPtr, b); -} - -} - - -/** - * Redirect stderr - */ -public native void stdErrWrite(long ptr, int b); -class StdErrStream extends OutputStream -{ - -public void write(int b) -{ - stdErrWrite(backPtr, b); -} - - -} - -/** - * A logging stream - */ -static PrintStream log; -public native void logWrite(long ptr, int b); -class LogStream extends OutputStream -{ - -public void write(int b) -{ - logWrite(backPtr, b); -} - - -} - - -//######################################################################## -//# RUN -//######################################################################## - - -/** - * Run a script buffer - * - * @param lang the scripting language to run - * @param str the script buffer to execute - * @return true if successful, else false - */ -public boolean doRun(String lang, String str) -{ - // create JavaScript engine - ScriptEngine engine = scriptEngineManager.getEngineByName(lang); - if (engine == null) - { - err("doRun: cannot find script engine '" + lang + "'"); - return false; - } - //execute script from buffer - try - { - engine.eval(str); - } - catch (javax.script.ScriptException e) - { - err("Executing script: " + e); - e.printStackTrace(); - } - return true; -} - -/** - * Run a script buffer - * - * @param backPtr pointer back to the C context that called this - * @param lang the scripting language to run - * @param str the script buffer to execute - * @return true if successful, else false - */ -public static boolean run(String lang, String str) -{ - //wrap whole thing in try/catch, since this will - //likely be called from C - try - { - ScriptRunner runner = getInstance(); - if (runner == null) - { - err("ScriptRunner not initialized"); - return false; - } - return runner.doRun(lang, str); - } - catch (Exception e) - { - err("run :" + e); - e.printStackTrace(); - return false; - } -} - - -/** - * Run a script file - * - * @param lang the scripting language to run - * @param fname the script file to execute - * @return true if successful, else false - */ -public boolean doRunFile(String lang, String fname) -{ - // create JavaScript engine - ScriptEngine engine = scriptEngineManager.getEngineByName(lang); - if (engine == null) - { - err("doRunFile: cannot find script engine '" + lang + "'"); - return false; - } - //try opening file and feeding into engine - FileReader in = null; - boolean ret = true; - try - { - in = new FileReader(fname); - } - catch (java.io.IOException e) - { - err("Executing file: " + e); - return false; - } - try - { - engine.eval(in); - } - catch (javax.script.ScriptException e) - { - err("Executing file: " + e); - ret = false; - } - try - { - in.close(); - } - catch (java.io.IOException e) - { - err("Executing file: " + e); - return false; - } - return ret; -} - - -/** - * Run a script file - * - * @param backPtr pointer back to the C context that called this - * @param lang the scripting language to run - * @param fname the script file to execute - * @return true if successful, else false - */ -public static boolean runFile(String lang, String fname) -{ - //wrap whole thing in try/catch, since this will - //likely be called from C - try - { - ScriptRunner runner = getInstance(); - if (runner == null) - { - err("ScriptRunner not initialized"); - return false; - } - return runner.doRunFile(lang, fname); - } - catch (Exception e) - { - err("run :" + e); - return false; - } -} - - - -//######################################################################## -//# CONSTRUCTOR -//######################################################################## - - - -private static ScriptRunner _instance = null; -public static ScriptRunner getInstance() -{ - return _instance; -} - -private void listFactories() -{ - List factories = - scriptEngineManager.getEngineFactories(); - for (ScriptEngineFactory factory: factories) - { - log.println("ScriptEngineFactory Info"); - String engName = factory.getEngineName(); - String engVersion = factory.getEngineVersion(); - String langName = factory.getLanguageName(); - String langVersion = factory.getLanguageVersion(); - log.printf("\tScript Engine: %s (%s)\n", - engName, engVersion); - List engNames = factory.getNames(); - for(String name: engNames) - { - log.printf("\tEngine Alias: %s\n", name); - } - log.printf("\tLanguage: %s (%s)\n", - langName, langVersion); - } -} - - - -/** - * Constructor - * @param backPtr pointer back to the C context that called this - */ -public ScriptRunner(long backPtr) -{ - /** - * Set up the output, error, and logging stream - */ - System.setOut(new PrintStream(new StdOutStream())); - System.setErr(new PrintStream(new StdErrStream())); - log = new PrintStream(new LogStream()); - - //Point back to C++ object - this.backPtr = backPtr; - - //Start up the factory - scriptEngineManager = new ScriptEngineManager(); - listFactories(); - _instance = this; -} - - -static -{ - -} - -} -//######################################################################## -//# E N D O F F I L E -//######################################################################## - - diff --git a/src/bind/java/org/inkscape/script/Editor.java b/src/bind/java/org/inkscape/script/Editor.java new file mode 100644 index 000000000..ba57465ca --- /dev/null +++ b/src/bind/java/org/inkscape/script/Editor.java @@ -0,0 +1,49 @@ +package org.inkscape.script; + + + +import javax.swing.JPanel; +import javax.swing.JTextPane; +import java.awt.BorderLayout; + +/** + * A simple script editor for quick fixes. + */ +public class Editor extends JPanel +{ +JTextPane textPane; + + +/** + * + */ +public String getText() +{ + return textPane.getText(); +} + + +/** + * + */ +public void setText(String txt) +{ + textPane.setText(txt); +} + + +/** + * + */ +public Editor() +{ + super(); + setLayout(new BorderLayout()); + textPane = new JTextPane(); + add(textPane, BorderLayout.CENTER); +} + + + +} + diff --git a/src/bind/java/org/inkscape/script/ScriptConsole.java b/src/bind/java/org/inkscape/script/ScriptConsole.java new file mode 100644 index 000000000..dc4b8dc34 --- /dev/null +++ b/src/bind/java/org/inkscape/script/ScriptConsole.java @@ -0,0 +1,650 @@ + + +package org.inkscape.script; + +import org.inkscape.cmn.Resource; + +import javax.script.*; + +import javax.swing.WindowConstants; +import javax.swing.JFrame; +import javax.swing.JButton; +import javax.swing.JMenu; +import javax.swing.JMenuBar; +import javax.swing.JMenuItem; +import javax.swing.JRadioButtonMenuItem; +import javax.swing.ButtonGroup; +import javax.swing.JOptionPane; +import javax.swing.JFileChooser; +import javax.swing.JTabbedPane; +import javax.swing.JToolBar; +import javax.swing.filechooser.FileNameExtensionFilter; +import javax.swing.Action; +import javax.swing.AbstractAction; + + +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.BorderLayout; + +import java.io.File; +import java.io.FileReader; + +import java.util.List; +import java.util.HashMap; + + + +/** + * + */ +public class ScriptConsole extends JFrame +{ +Terminal terminal; +Editor editor; + +JTabbedPane tabPane; +JToolBar toolbar; +JMenuBar menubar; + + +//######################################################################## +//# MESSSAGES +//######################################################################## +void err(String fmt, Object... arguments) +{ + terminal.errorf("ScriptConsole err:" + fmt, arguments); +} + +void msg(String fmt, Object... arguments) +{ + terminal.outputf("ScriptConsole:" + fmt, arguments); +} + +void trace(String fmt, Object... arguments) +{ + terminal.outputf("ScriptConsole:" + fmt, arguments); +} + + + + + + +void alert(String msg) +{ + JOptionPane.showMessageDialog(this, msg); +} + + +//######################################################################## +//# U T I L I T Y +//######################################################################## + +private JFileChooser _chooser; + +JFileChooser getChooser() +{ + if (_chooser == null) + { + _chooser = new JFileChooser(); + _chooser.setAcceptAllFileFilterUsed(false); + FileNameExtensionFilter filter = new FileNameExtensionFilter( + "Script Files", "js", "py", "r"); + _chooser.setFileFilter(filter); + } + return _chooser; +} + + + +//######################################################################## +//# S C R I P T S +//######################################################################## +ScriptEngine engine; + +HashMap scriptEngineActions; + +public void setEngine(ScriptEngine engine) +{ + this.engine = engine; + this.engine.getContext().setWriter(terminal.getOutWriter()); + this.engine.getContext().setErrorWriter(terminal.getErrWriter()); +} + + +public ScriptEngine getEngine() +{ + return engine; +} + + +public boolean setEngine(String name) +{ + ScriptEngineAction action = scriptEngineActions.get(name); + if (action == null) + return false; + action.setEnabled(true); + setEngine(action.factory.getScriptEngine()); + return true; +} + + +/** + * Run a script buffer + * + * @param str the script buffer to execute + * @return true if successful, else false + */ +public boolean doRunCmd(String str) +{ + if (engine == null) + { + err("No engine set"); + return false; + } + + //execute script from buffer + try + { + getEngine().eval(str); + } + catch (javax.script.ScriptException e) + { + err("Executing script: " + e); + //e.printStackTrace(); + } + terminal.output("\nscript> "); + return true; +} + +/** + * Run a script buffer + * + * @param str the script buffer to execute + * @return true if successful, else false + */ +public boolean doRun(String str) +{ + if (engine == null) + { + err("No engine set"); + return false; + } + + //execute script from buffer + try + { + getEngine().eval(str); + } + catch (javax.script.ScriptException e) + { + err("Executing script: " + e); + //e.printStackTrace(); + } + return true; +} + + +/** + * Run a script buffer + * + * @param lang the scripting language to run + * @param str the script buffer to execute + * @return true if successful, else false + */ +public boolean doRun(String lang, String str) +{ + // find script engine + if (!setEngine(lang)) + { + err("doRun: cannot find script engine '" + lang + "'"); + return false; + } + return doRun(str); +} + + +/** + * Run a script file + * + * @param fname the script file to execute + * @return true if successful, else false + */ +public boolean doRunFile(String fname) +{ + if (engine == null) + { + err("No engine set"); + return false; + } + + //try opening file and feeding into engine + FileReader in = null; + boolean ret = true; + try + { + in = new FileReader(fname); + } + catch (java.io.IOException e) + { + err("Executing file: " + e); + return false; + } + try + { + engine.eval(in); + } + catch (javax.script.ScriptException e) + { + err("Executing file: " + e); + ret = false; + } + try + { + in.close(); + } + catch (java.io.IOException e) + { + err("Executing file: " + e); + return false; + } + return ret; +} + + +/** + * Run a script file + * + * @param lang the scripting language to run + * @param fname the script file to execute + * @return true if successful, else false + */ +public boolean doRunFile(String lang, String fname) +{ + // find script engine + if (!setEngine(lang)) + { + err("doRunFile: cannot find script engine '" + lang + "'"); + return false; + } + return doRunFile(fname); +} + + +class ScriptEngineAction extends AbstractAction +{ +ScriptEngineFactory factory; + + +public void actionPerformed(ActionEvent evt) +{ + setEngine(factory.getScriptEngine()); +} + +public ScriptEngineAction(ScriptEngineFactory factory) +{ + super(factory.getEngineName(), null); + putValue(SHORT_DESCRIPTION, factory.getLanguageName()); + this.factory = factory; +} + +} + + +private void initScripts() +{ + JMenu menu = new JMenu("Language"); + ButtonGroup group = new ButtonGroup(); + menubar.add(menu); + + ScriptEngineManager scriptEngineManager = + new ScriptEngineManager(); + List factories = + scriptEngineManager.getEngineFactories(); + for (ScriptEngineFactory factory: factories) + { + trace("ScriptEngineFactory Info"); + String engName = factory.getEngineName(); + String engVersion = factory.getEngineVersion(); + String langName = factory.getLanguageName(); + String langVersion = factory.getLanguageVersion(); + trace("\tScript Engine: %s (%s)\n", engName, engVersion); + List engNames = factory.getNames(); + for(String name: engNames) + { + trace("\tEngine Alias: %s\n", name); + } + trace("\tLanguage: %s (%s)\n", langName, langVersion); + ScriptEngineAction action = new ScriptEngineAction(factory); + JRadioButtonMenuItem item = new JRadioButtonMenuItem(action); + group.add(item); + menu.add(item); + } + if (menu.getItemCount()>0) + { + JMenuItem item = menu.getItem(0); + group.setSelected(item.getModel(), true); + ScriptEngineAction action = (ScriptEngineAction)item.getAction(); + setEngine(action.factory.getScriptEngine()); + } +} + + +static final String defaultCodeStr = + "/**\n" + + " * This is some example Javascript.\n" + + " * Try executing\n" + + " */\n" + + "importPackage(javax.swing);\n" + + "function sayHello() {\n" + + " JOptionPane.showMessageDialog(null, 'Hello, world!',\n" + + " 'Welcome to Inkscape', JOptionPane.WARNING_MESSAGE);\n" + + "}\n" + + "\n" + + "sayHello();\n" + + "\n"; + + +//######################################################################## +//# A C T I O N S +//######################################################################## +Action newAction; +Action openAction; +Action quitAction; +Action runAction; +Action saveAction; +Action saveAsAction; +Action stopAction; + + + +class NewAction extends AbstractAction +{ + +public void actionPerformed(ActionEvent evt) +{ + // +} + +public NewAction() +{ + super("New", Resource.getIcon("document-new.png")); + putValue(SHORT_DESCRIPTION, "Create a new script file"); +} + +} + + + +class OpenAction extends AbstractAction +{ + +public void actionPerformed(ActionEvent evt) +{ + JFileChooser chooser = getChooser(); + int ret = chooser.showOpenDialog(ScriptConsole.this); + if (ret != JFileChooser.APPROVE_OPTION) + return; + File f = chooser.getSelectedFile(); + String fname = f.getName(); + alert("You selected : " + fname); +} + +public OpenAction() +{ + super("Open", Resource.getIcon("document-open.png")); + putValue(SHORT_DESCRIPTION, "Open a script file"); +} + +} + + + +class QuitAction extends AbstractAction +{ + +public void actionPerformed(ActionEvent evt) +{ + setVisible(false); +} + +public QuitAction() +{ + super("Quit", Resource.getIcon("system-log-out.png")); + putValue(SHORT_DESCRIPTION, "Quit this script console"); +} + +} + + + +class RunAction extends AbstractAction +{ + +public void actionPerformed(ActionEvent evt) +{ + String txt = editor.getText(); + doRun(txt); +} + +public RunAction() +{ + super("Run", Resource.getIcon("go-next.png")); + putValue(SHORT_DESCRIPTION, "Run the script in the editor"); +} + +} + + + +class SaveAction extends AbstractAction +{ + +public void actionPerformed(ActionEvent evt) +{ + JFileChooser chooser = getChooser(); + int ret = chooser.showSaveDialog(ScriptConsole.this); + if (ret != JFileChooser.APPROVE_OPTION) + return; + File f = chooser.getSelectedFile(); + String fname = f.getName(); + alert("You selected : " + fname); +} + +public SaveAction() +{ + super("Save", Resource.getIcon("document-save.png")); + putValue(SHORT_DESCRIPTION, "Save file"); +} + +} + + + +class SaveAsAction extends AbstractAction +{ + +public void actionPerformed(ActionEvent evt) +{ + JFileChooser chooser = getChooser(); + int ret = chooser.showSaveDialog(ScriptConsole.this); + if (ret != JFileChooser.APPROVE_OPTION) + return; + File f = chooser.getSelectedFile(); + String fname = f.getName(); + alert("You selected : " + fname); +} + +public SaveAsAction() +{ + super("SaveAs", Resource.getIcon("document-save-as.png")); + putValue(SHORT_DESCRIPTION, "Save under a new file name"); +} + +} + + + +class StopAction extends AbstractAction +{ + +public void actionPerformed(ActionEvent evt) +{ + //# +} + +public StopAction() +{ + super("Stop", Resource.getIcon("process-stop.png")); + putValue(SHORT_DESCRIPTION, "Stop the running script"); +} + +} + + + +HashMap actions; +void setupActions() +{ + actions = new HashMap(); + actions.put("New", newAction = new NewAction()); + actions.put("Open", openAction = new OpenAction()); + actions.put("Quit", quitAction = new QuitAction()); + actions.put("Run", runAction = new RunAction()); + actions.put("Save", saveAction = new SaveAction()); + actions.put("SaveAs", saveAsAction = new SaveAsAction()); + actions.put("Stop", stopAction = new StopAction()); +} + + +public void enableAction(String name) +{ + Action action = actions.get(name); + if (action == null) + return; + action.setEnabled(true); +} + +public void disableAction(String name) +{ + Action action = actions.get(name); + if (action == null) + return; + action.setEnabled(false); +} + + + +//######################################################################## +//# S E T U P +//######################################################################## + +JButton toolbarButton(Action action) +{ + JButton btn = new JButton(action); + btn.setText(""); + btn.setToolTipText((String)action.getValue(Action.SHORT_DESCRIPTION)); + return btn; +} + + +private boolean setup() +{ + setTitle("Inkscape Script Console"); + setSize(600, 400); + setIconImage(Resource.getImage("inkscape.png")); + setDefaultCloseOperation(WindowConstants.HIDE_ON_CLOSE); + + //###################################################### + //# A C T I O N S + //###################################################### + setupActions(); + + //###################################################### + //# M E N U + //###################################################### + menubar = new JMenuBar(); + setJMenuBar(menubar); + + JMenu menu = new JMenu("File"); + menubar.add(menu); + menu.add(new JMenuItem(openAction)); + menu.add(new JMenuItem(saveAction)); + menu.add(new JMenuItem(saveAsAction)); + menu.add(new JMenuItem(quitAction)); + + menu = new JMenu("Run"); + menubar.add(menu); + menu.add(new JMenuItem(runAction)); + menu.add(new JMenuItem(stopAction)); + + //###################################################### + //# T O O L B A R + //###################################################### + toolbar = new JToolBar(); + getContentPane().add(toolbar, BorderLayout.NORTH); + toolbar.add(toolbarButton(openAction)); + toolbar.add(toolbarButton(saveAction)); + toolbar.add(toolbarButton(runAction)); + toolbar.add(toolbarButton(stopAction)); + + //###################################################### + //# C O N T E N T + //###################################################### + tabPane = new JTabbedPane(); + getContentPane().add(tabPane, BorderLayout.CENTER); + + terminal = new Terminal(); + tabPane.addTab("Console", + Resource.getIcon("utilities-terminal.png"), + terminal); + terminal.output("\nscript> "); + + editor = new Editor(); + tabPane.addTab("Script", + Resource.getIcon("accessories-text-editor.png"), + editor); + + editor.setText(defaultCodeStr); + + //###################################################### + //# E N G I N E + //###################################################### + initScripts(); + + return true; +} + + + + + + +public ScriptConsole() +{ + setup(); +} + + +private static ScriptConsole _instance = null; +public static ScriptConsole getInstance() +{ + if (_instance == null) + _instance = new ScriptConsole(); + return _instance; +} + + +public static void main(String argv[]) +{ + ScriptConsole sc = getInstance(); + sc.setVisible(true); +} + + +} +//######################################################################## +//# E N D O F F I L E +//######################################################################## + diff --git a/src/bind/java/org/inkscape/script/Terminal.java b/src/bind/java/org/inkscape/script/Terminal.java new file mode 100644 index 000000000..054382482 --- /dev/null +++ b/src/bind/java/org/inkscape/script/Terminal.java @@ -0,0 +1,273 @@ +package org.inkscape.script; + +import java.awt.BorderLayout; +import javax.swing.JFrame; +import javax.swing.JPanel; +import javax.swing.JTextPane; +import javax.swing.JScrollPane; +import javax.swing.text.DefaultCaret; +import javax.swing.text.Document; +import javax.swing.text.BadLocationException; +import javax.swing.text.StyleConstants; +import javax.swing.text.SimpleAttributeSet; +import java.awt.Color; +import java.awt.event.KeyEvent; +import java.awt.event.KeyListener; +import java.awt.Font; + +import java.io.ByteArrayOutputStream; +import java.io.PrintStream; +import java.io.IOException; +import java.io.Writer; +import java.io.PrintWriter; + +public class Terminal extends JPanel + implements KeyListener +{ + +SimpleAttributeSet inTextAttr; +SimpleAttributeSet outTextAttr; +SimpleAttributeSet errTextAttr; + +StringBuffer buf = new StringBuffer(); +JTextPane textPane; + +void err(String msg) +{ + System.out.println("Terminal err: " + msg); +} + +void trace(String msg) +{ + System.out.println("Terminal: " + msg); +} + + +void processInputLine(String txt) +{ + ScriptConsole cons = ScriptConsole.getInstance(); + if (cons != null) + cons.doRunCmd(txt); +} + + + +class OutWriter extends Writer +{ + +public void write(char[] cbuf, int off, int len) +{ + String s = new String(cbuf, off, len); + output(s); +} + +public void flush() +{ +} + +public void close() +{ +} + +} + + + +PrintWriter outWriter; + +public Writer getOutWriter() +{ + if (outWriter == null) + outWriter = new PrintWriter(new OutWriter()); + return outWriter; +} + + +public void output(String txt) +{ + Document doc = textPane.getDocument(); + try + { + doc.insertString(doc.getLength(), txt, outTextAttr); + textPane.setCaretPosition(doc.getLength()); + } + catch (BadLocationException e) + { + } + +} + + +public void outputf(String fmt, Object... args) +{ + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + PrintStream out = new PrintStream(baos); + out.printf(fmt, args); + out.close(); + String s = baos.toString(); + output(s); +} + + + +class ErrWriter extends Writer +{ + +public void write(char[] cbuf, int off, int len) +{ + String s = new String(cbuf, off, len); + error(s); +} + +public void flush() +{ +} + +public void close() +{ +} + +} + + + +PrintWriter errWriter; + +public Writer getErrWriter() +{ + if (errWriter == null) + errWriter = new PrintWriter(new ErrWriter()); + return errWriter; +} + + +public void error(String txt) +{ + Document doc = textPane.getDocument(); + try + { + doc.insertString(doc.getLength(), txt, errTextAttr); + textPane.setCaretPosition(doc.getLength()); + } + catch (BadLocationException e) + { + } + +} + +public void errorf(String fmt, Object... args) +{ + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + PrintStream out = new PrintStream(baos); + out.printf(fmt, args); + out.close(); + String s = baos.toString(); + error(s); +} + + +public void keyPressed(KeyEvent evt) +{ +} + +public void keyReleased(KeyEvent evt) +{ +} + +public void keyTyped(KeyEvent evt) +{ + Document doc = textPane.getDocument(); + char ch = evt.getKeyChar(); + if (ch == 127) + { + } + else if (ch == '\b') + { + if (buf.length() == 0) + return; + try + { + buf.delete(buf.length()-1, buf.length()); + doc.remove(doc.getLength()-1, 1); + textPane.setCaretPosition(doc.getLength()); + } + catch (BadLocationException e) + { + err("keyTyped:" + e); + } + } + else + { + try + { + buf.append(ch); + doc.insertString(doc.getLength(), "" + ch, inTextAttr); + textPane.setCaretPosition(doc.getLength()); + } + catch (BadLocationException e) + { + } + if (ch == '\n' || ch == '\r') + { + String txt = buf.toString(); + buf.delete(0, buf.length()); + txt = txt.trim(); + processInputLine(txt); + } + } + + + +} + + + +void setup() +{ + setLayout(new BorderLayout()); + textPane = new JTextPane(); + add(new JScrollPane(textPane), BorderLayout.CENTER); + textPane.setEditable(false); + textPane.setBackground(Color.BLACK); + textPane.setCaretColor(Color.WHITE); + textPane.setCaret(new DefaultCaret()); + textPane.getCaret().setVisible(true); + textPane.getCaret().setBlinkRate(500); + Font currentFont = textPane.getFont(); + textPane.setFont(new Font("Monospaced", currentFont.getStyle(), currentFont.getSize())); + textPane.addKeyListener(this); + + inTextAttr = new SimpleAttributeSet(); + StyleConstants.setForeground(inTextAttr, Color.YELLOW); + outTextAttr = new SimpleAttributeSet(); + StyleConstants.setForeground(outTextAttr, Color.GREEN); + errTextAttr = new SimpleAttributeSet(); + StyleConstants.setForeground(errTextAttr, Color.RED); + + +} + + + + + + +public Terminal() +{ + super(); + setup(); +} + + + +public static void main(String argv[]) +{ + Terminal t = new Terminal(); + JFrame par = new JFrame("Terminal Test"); + par.setSize(500, 350); + par.getContentPane().add(t); + par.setVisible(true); +} + +} + diff --git a/src/bind/javabind-private.h b/src/bind/javabind-private.h index c919c105d..2530bd735 100644 --- a/src/bind/javabind-private.h +++ b/src/bind/javabind-private.h @@ -54,11 +54,31 @@ public: const std::vector ¶ms, Value &retval); + virtual bool callInstance( + int type, + const jobject obj, + const String &methodName, + const String &signature, + const std::vector ¶ms, + Value &retval); + virtual bool callMain(const String &className, const std::vector &args); virtual bool isLoaded(); + /** + * + */ + virtual bool scriptRun(const String &lang, const String &script); + + /** + * + */ + virtual bool scriptRunFile(const String &lang, const String &fileName); + + virtual bool showConsole(); + virtual bool registerNatives(const String &className, const JNINativeMethod *methods); @@ -66,7 +86,7 @@ public: virtual String getException(); - virtual bool setupScriptRunner(); + virtual bool setupGateway(); static JavaBinderyImpl *getInstance(); @@ -75,7 +95,7 @@ private: JavaVM *jvm; JNIEnv *env; - + jobject gatewayObj; }; diff --git a/src/bind/javabind.cpp b/src/bind/javabind.cpp index 4314f8819..0262aee54 100644 --- a/src/bind/javabind.cpp +++ b/src/bind/javabind.cpp @@ -208,8 +208,9 @@ JavaBinderyImpl *JavaBinderyImpl::getInstance() JavaBinderyImpl::JavaBinderyImpl() { - jvm = NULL; - env = NULL; + jvm = NULL; + env = NULL; + gatewayObj = NULL; } JavaBinderyImpl::~JavaBinderyImpl() @@ -272,7 +273,7 @@ void msg(const char *fmt, ...) -static bool getRegistryString(HKEY root, const char *keyName, +static bool getRegistryString(HKEY /*root*/, const char *keyName, const char *valName, char *buf, int buflen) { HKEY key; @@ -632,28 +633,13 @@ static void populateClassPath(const String &javaroot, //======================================================================== -// SCRIPT RUNNER +// Gateway //======================================================================== /** - * These methods are used to allow the ScriptRunner class to - * redirect its stderr and stdout streams to here, to be caught - * by two string buffers. We can then use those buffers how we - * want. These native methods are only those needed for running - * a script. For the main C++/Java bindings, see dobinding.cpp + * This method is used to allow the gateway class to + * redirect its logging stream here. + * For the main C++/Java bindings, see dobinding.cpp */ -void JNICALL stdOutWrite(JNIEnv */*env*/, jobject /*obj*/, jlong ptr, jint ch) -{ - JavaBinderyImpl *bind = (JavaBinderyImpl *)ptr; - bind->stdOut(ch); -} - -void JNICALL stdErrWrite(JNIEnv */*env*/, jobject /*obj*/, jlong ptr, jint ch) -{ - JavaBinderyImpl *bind = (JavaBinderyImpl *)ptr; - bind->stdErr(ch); -} - - void JNICALL logWrite(JNIEnv */*env*/, jobject /*obj*/, jlong ptr, jint ch) { JavaBinderyImpl *bind = (JavaBinderyImpl *)ptr; @@ -661,58 +647,100 @@ void JNICALL logWrite(JNIEnv */*env*/, jobject /*obj*/, jlong ptr, jint ch) } -static JNINativeMethod scriptRunnerMethods[] = +static JNINativeMethod gatewayMethods[] = { -{ (char *)"stdOutWrite", (char *)"(JI)V", (void *)stdOutWrite }, -{ (char *)"stdErrWrite", (char *)"(JI)V", (void *)stdErrWrite }, { (char *)"logWrite", (char *)"(JI)V", (void *)logWrite }, { NULL, NULL, NULL } }; /** - * This sets up the 'ScriptRunner' java class for execution of + * This sets up the 'Gateway' java class for execution of * scripts. The class's constructor takes a jlong. This java long * is used to store the pointer to 'this'. When ScriptRunner makes * native calls, it passes that jlong back, so that it can call the * methods of this C++ class. */ -bool JavaBinderyImpl::setupScriptRunner() +bool JavaBinderyImpl::setupGateway() { - String className = "org/inkscape/cmn/ScriptRunner"; - if (!registerNatives(className, scriptRunnerMethods)) + String className = "org/inkscape/cmn/Gateway"; + if (!registerNatives(className, gatewayMethods)) { return false; } jclass cls = env->FindClass(className.c_str()); if (!cls) { - err("setupScriptRunner: cannot find class '%s' : %s", + err("setupGateway: cannot find class '%s' : %s", className.c_str(), getException().c_str()); return false; } jmethodID mid = env->GetMethodID(cls, "", "(J)V"); if (!mid) { - err("setupScriptRunner: cannot find constructor for '%s' : %s", + err("setupGateway: cannot find constructor for '%s' : %s", className.c_str(), getException().c_str()); return false; } - jobject obj = env->NewObject(cls, mid, ((jlong)this)); - if (!obj) + gatewayObj = env->NewObject(cls, mid, ((jlong)this)); + if (!gatewayObj) { - err("setupScriptRunner: cannot construct '%s' : %s", + err("setupGateway: cannot construct '%s' : %s", className.c_str(), getException().c_str()); return false; } - msg("ScriptRunner ready"); + msg("Gateway ready"); return true; } +bool JavaBinderyImpl::scriptRun(const String &lang, const String &script) +{ + if (!loadJVM()) + return false; + + std::vector params; + Value langParm(lang); + params.push_back(langParm); + Value scriptParm(script); + params.push_back(scriptParm); + Value retval; + callInstance(Value::BIND_VOID, gatewayObj, "scriptRun", + "(Ljava/lang/String;Ljava/lang/String;)Z", params, retval); + return retval.getBoolean(); +} + +bool JavaBinderyImpl::scriptRunFile(const String &lang, const String &fname) +{ + if (!loadJVM()) + return false; + + std::vector params; + Value langParm(lang); + params.push_back(langParm); + Value fnameParm(fname); + params.push_back(fnameParm); + Value retval; + callInstance(Value::BIND_VOID, gatewayObj, "scriptRunFile", + "(Ljava/lang/String;Ljava/lang/String;)Z", params, retval); + return retval.getBoolean(); +} + +bool JavaBinderyImpl::showConsole() +{ + if (!loadJVM()) + return false; + + std::vector params; + Value retval; + callInstance(Value::BIND_VOID, gatewayObj, "showConsole", + "()Z", params, retval); + return retval.getBoolean(); +} + //======================================================================== -// End SCRIPT RUNNER +// End Gateway //======================================================================== @@ -784,7 +812,7 @@ bool JavaBinderyImpl::loadJVM() int versionMinor = (vers ) & 0xffff; msg("Loaded JVM version %d.%d", versionMajor, versionMinor); - if (!setupScriptRunner()) + if (!setupGateway()) return false; return true; @@ -920,6 +948,127 @@ bool JavaBinderyImpl::callStatic(int type, +/** + * Another difficult method. However, this time we are operating + * on an existing instance jobject. + * + * @param type the return type of the method + * @param obj the instance upon which to make the call + * @param methodName the name of the method being invoked + * @param signature the method signature (ex: "(Ljava/lang/String;I)V" ) + * that describes the param and return types of the method. + * @param retval the return value of the java method + * @return true if the call was successful, else false. This is not + * the return value of the method. + */ +bool JavaBinderyImpl::callInstance( + int type, + const jobject obj, + const String &methodName, + const String &signature, + const std::vector ¶ms, + Value &retval) +{ + jmethodID mid = env->GetMethodID(env->GetObjectClass(obj), + methodName.c_str(), signature.c_str()); + if (!mid) + { + err("Could not find method '%s/%s' : %s", + methodName.c_str(), + signature.c_str(), getException().c_str()); + return false; + } + /** + * Assemble your parameters into a form usable by JNI + */ + jvalue *jvals = new jvalue[params.size()]; + for (unsigned int i=0 ; iNewStringUTF(v.getString().c_str()); + break; + } + default: + { + err("Unknown value type: %d", v.getType()); + return false; + } + } + } + switch (type) + { + case Value::BIND_VOID: + { + env->CallVoidMethodA(obj, mid, jvals); + break; + } + case Value::BIND_BOOLEAN: + { + jboolean ret = env->CallBooleanMethodA(obj, mid, jvals); + if (ret == JNI_TRUE) //remember, don't truncate + retval.setBoolean(true); + else + retval.setBoolean(false); + break; + } + case Value::BIND_INT: + { + jint ret = env->CallIntMethodA(obj, mid, jvals); + retval.setInt(ret); + break; + } + case Value::BIND_DOUBLE: + { + jdouble ret = env->CallDoubleMethodA(obj, mid, jvals); + retval.setDouble(ret); + break; + } + case Value::BIND_STRING: + { + jobject ret = env->CallObjectMethodA(obj, mid, jvals); + jstring jstr = (jstring) ret; + const char *str = env->GetStringUTFChars(jstr, JNI_FALSE); + retval.setString(str); + env->ReleaseStringUTFChars(jstr, str); + break; + } + default: + { + err("Unknown return type: %d", type); + return false; + } + } + delete jvals; + String errStr = getException(); + if (errStr.size()>0) + { + err("callStatic: %s", errStr.c_str()); + return false; + } + return true; +} + + + /** * Fetch the last exception from the JVM, if any. Clear it to diff --git a/src/bind/javabind.h b/src/bind/javabind.h index 144e633e7..6ea896a2c 100644 --- a/src/bind/javabind.h +++ b/src/bind/javabind.h @@ -92,6 +92,42 @@ public: init(); } + /** + * + */ + Value(int ival) + { + init(); + setInt(ival); + } + + /** + * + */ + Value(bool bval) + { + init(); + setBoolean(bval); + } + + /** + * + */ + Value(double dval) + { + init(); + setDouble(dval); + } + + /** + * + */ + Value(const String &sval) + { + init(); + setString(sval); + } + /** * */ @@ -280,49 +316,43 @@ public: /** * */ - virtual bool doBinding() + virtual bool scriptRun(const String &/*lang*/, const String &/*script*/) { return false; } - + /** * */ - virtual String getException() + virtual bool scriptRunFile(const String &/*lang*/, const String &/*fileName*/) { - return ""; - } - - virtual String stdOutGet() - { - return stdOutBuf; - } - - virtual void stdOutClear() - { - stdOutBuf.clear(); - } - - virtual void stdOut(int ch) - { - stdOutBuf.push_back((char)ch); + return false; } - virtual String stdErrGet() + /** + * + */ + virtual bool showConsole() { - return stdErrBuf; + return false; } - virtual void stdErrClear() + /** + * + */ + virtual bool doBinding() { - stdErrBuf.clear(); + return false; } - - virtual void stdErr(int ch) + + /** + * + */ + virtual String getException() { - stdErrBuf.push_back((char)ch); - } - + return ""; + } + virtual String logGet() { return logBuf; diff --git a/src/extension/script/InkscapeScript.cpp b/src/extension/script/InkscapeScript.cpp index 1507c6344..d492cb100 100644 --- a/src/extension/script/InkscapeScript.cpp +++ b/src/extension/script/InkscapeScript.cpp @@ -107,16 +107,16 @@ bool InkscapeScript::interpretScript(const Glib::ustring &script, parm.setString(script); parms.push_back(parm); - binder->stdOutClear(); - binder->stdErrClear(); + //binder->stdOutClear(); + //binder->stdErrClear(); bool ret = binder->callStatic(Value::BIND_BOOLEAN, "org/inkscape/cmn/ScriptRunner", "run", "(Ljava/lang/String;Ljava/lang/String;)Z", parms, retval); - output = binder->stdOutGet(); - error = binder->stdErrGet(); + //output = binder->stdOutGet(); + //error = binder->stdErrGet(); if (!ret) { @@ -175,16 +175,16 @@ bool InkscapeScript::interpretFile(const Glib::ustring &fname, parm.setString(fname); parms.push_back(parm); - binder->stdOutClear(); - binder->stdErrClear(); + //binder->stdOutClear(); + //binder->stdErrClear(); bool ret = binder->callStatic(Value::BIND_BOOLEAN, "org/inkscape/cmn/ScriptRunner", "runFile", "(Ljava/lang/String;Ljava/lang/String;)Z", parms, retval); - output = binder->stdOutGet(); - error = binder->stdErrGet(); + //output = binder->stdOutGet(); + //error = binder->stdErrGet(); if (!ret) { diff --git a/src/verbs.cpp b/src/verbs.cpp index 9258aa547..1068472bd 100644 --- a/src/verbs.cpp +++ b/src/verbs.cpp @@ -54,6 +54,7 @@ #endif #include "extension/effect.h" +#include "bind/javabind.h" #include "tools-switch.h" #include "inkscape-private.h" @@ -1727,7 +1728,8 @@ DialogVerb::perform(SPAction *action, void *data, void */*pdata*/) dt->_dlg_mgr->showDialog("Messages"); break; case SP_VERB_DIALOG_SCRIPT: - dt->_dlg_mgr->showDialog("Script"); + //dt->_dlg_mgr->showDialog("Script"); + Inkscape::Bind::JavaBindery::getInstance()->showConsole(); break; case SP_VERB_DIALOG_UNDO_HISTORY: dt->_dlg_mgr->showDialog("UndoHistory"); -- 2.30.2