1 /**
2 * This is a simple mechanism to bind Inkscape to Java, and thence
3 * to all of the nice things that can be layered upon that.
4 *
5 * Authors:
6 * Bob Jamison
7 *
8 * Copyright (C) 2007-2008 Bob Jamison
9 *
10 * This library is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU Lesser General Public
12 * License as published by the Free Software Foundation; either
13 * version 3 of the License, or (at your option) any later version.
14 *
15 * This library is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 * Lesser General Public License for more details.
19 *
20 * You should have received a copy of the GNU Lesser General Public
21 * License along with this library; if not, write to the Free Software
22 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
23 */
25 package org.inkscape.script;
27 import org.inkscape.cmn.Resource;
29 import javax.script.*;
31 import javax.swing.WindowConstants;
32 import javax.swing.JFrame;
33 import javax.swing.JButton;
34 import javax.swing.JMenu;
35 import javax.swing.JLabel;
36 import javax.swing.JMenuBar;
37 import javax.swing.JMenuItem;
38 import javax.swing.JComboBox;
39 import javax.swing.ButtonGroup;
40 import javax.swing.JOptionPane;
41 import javax.swing.JTabbedPane;
42 import javax.swing.JToolBar;
43 import javax.swing.Action;
44 import javax.swing.AbstractAction;
47 import java.awt.event.ActionEvent;
48 import java.awt.event.ActionListener;
49 import java.awt.BorderLayout;
51 import java.io.File;
52 import java.io.FileReader;
53 import java.io.FileWriter;
54 import java.io.IOException;
57 import java.util.List;
58 import java.util.HashMap;
59 import java.util.ArrayList;
60 import java.util.List;
64 /**
65 * This is the main Script Console window. It contains
66 * a terminal-like console, and a simple script editor.
67 */
68 public class ScriptConsole extends JFrame
69 {
70 Terminal terminal;
71 Editor editor;
73 JTabbedPane tabPane;
74 JToolBar toolbar;
75 JMenuBar menubar;
76 JComboBox engineBox;
78 //########################################################################
79 //# MESSSAGES
80 //########################################################################
81 public void err(String fmt, Object... arguments)
82 {
83 terminal.errorf("ScriptConsole err:" + fmt + "\n", arguments);
84 }
86 public void msg(String fmt, Object... arguments)
87 {
88 terminal.outputf("ScriptConsole:" + fmt, arguments);
89 }
91 public void trace(String fmt, Object... arguments)
92 {
93 terminal.outputf("ScriptConsole:" + fmt + "\n", arguments);
94 }
101 void alert(String msg)
102 {
103 JOptionPane.showMessageDialog(this, msg);
104 }
109 //########################################################################
110 //# S C R I P T S
111 //########################################################################
112 ScriptEngine engine;
114 ArrayList<ScriptEngine> engines;
117 public void setEngine(ScriptEngine engine)
118 {
119 this.engine = engine;
120 this.engine.getContext().setWriter(terminal.getOutWriter());
121 this.engine.getContext().setErrorWriter(terminal.getErrWriter());
122 //do something to make the combobox show the current engine
123 }
126 public ScriptEngine getEngine()
127 {
128 return engine;
129 }
132 public boolean setEngine(String langName)
133 {
134 for (ScriptEngine engine : engines)
135 {
136 for(String name: engine.getFactory().getNames())
137 {
138 if (langName.equalsIgnoreCase(name))
139 {
140 setEngine(engine);
141 return true;
142 }
143 }
144 }
145 return false;
146 }
149 /**
150 * Run a script buffer
151 *
152 * @param str the script buffer to execute
153 * @return true if successful, else false
154 */
155 public boolean doRunCmd(String str)
156 {
157 if (engine == null)
158 {
159 err("No engine set");
160 return false;
161 }
163 //execute script from buffer
164 try
165 {
166 getEngine().eval(str);
167 }
168 catch (javax.script.ScriptException e)
169 {
170 err("Executing script: " + e);
171 //e.printStackTrace();
172 }
173 terminal.output("\nscript> ");
174 return true;
175 }
177 /**
178 * Run a script buffer
179 *
180 * @param str the script buffer to execute
181 * @return true if successful, else false
182 */
183 public boolean doRun(String str)
184 {
185 if (engine == null)
186 {
187 err("No engine set");
188 return false;
189 }
191 //execute script from buffer
192 try
193 {
194 getEngine().eval(str);
195 }
196 catch (javax.script.ScriptException e)
197 {
198 err("Executing script: " + e);
199 //e.printStackTrace();
200 }
201 return true;
202 }
205 /**
206 * Run a script buffer
207 *
208 * @param lang the scripting language to run
209 * @param str the script buffer to execute
210 * @return true if successful, else false
211 */
212 public boolean doRun(String lang, String str)
213 {
214 // find script engine
215 if (!setEngine(lang))
216 {
217 err("doRun: cannot find script engine '" + lang + "'");
218 return false;
219 }
220 return doRun(str);
221 }
224 /**
225 * Run a script file
226 *
227 * @param fname the script file to execute
228 * @return true if successful, else false
229 */
230 public boolean doRunFile(String fname)
231 {
232 if (engine == null)
233 {
234 err("No engine set");
235 return false;
236 }
238 //try opening file and feeding into engine
239 FileReader in = null;
240 boolean ret = true;
241 try
242 {
243 in = new FileReader(fname);
244 }
245 catch (java.io.IOException e)
246 {
247 err("Executing file: " + e);
248 return false;
249 }
250 try
251 {
252 engine.eval(in);
253 }
254 catch (javax.script.ScriptException e)
255 {
256 err("Executing file: " + e);
257 ret = false;
258 }
259 try
260 {
261 in.close();
262 }
263 catch (java.io.IOException e)
264 {
265 err("Executing file: " + e);
266 return false;
267 }
268 return ret;
269 }
272 /**
273 * Run a script file
274 *
275 * @param lang the scripting language to run
276 * @param fname the script file to execute
277 * @return true if successful, else false
278 */
279 public boolean doRunFile(String lang, String fname)
280 {
281 // find script engine
282 if (!setEngine(lang))
283 {
284 err("doRunFile: cannot find script engine '" + lang + "'");
285 return false;
286 }
287 return doRunFile(fname);
288 }
292 class ScriptEngineAction extends AbstractAction
293 {
296 public void actionPerformed(ActionEvent evt)
297 {
298 int index = engineBox.getSelectedIndex();
299 if (index<0)
300 return;
301 ScriptEngine engine = engines.get(index);
302 setEngine(engine);
303 }
305 public ScriptEngineAction()
306 {
307 super("SelectEngine", null);
308 putValue(SHORT_DESCRIPTION, "Select a scripting engine");
309 }
311 }
314 private void initScripts()
315 {
316 engines = new ArrayList<ScriptEngine>();
317 Action action = new ScriptEngineAction();
318 engineBox = new JComboBox();
319 engineBox.setAction(action);
320 engineBox.setEditable(false);
321 toolbar.add(engineBox);
323 ScriptEngineManager scriptEngineManager =
324 new ScriptEngineManager();
325 List<ScriptEngineFactory> factories =
326 scriptEngineManager.getEngineFactories();
327 for (ScriptEngineFactory factory: factories)
328 {
329 trace("ScriptEngineFactory Info");
330 String engName = factory.getEngineName();
331 String engVersion = factory.getEngineVersion();
332 String fullEngName = engName + " (" + engVersion + ")";
333 String langName = factory.getLanguageName();
334 String langVersion = factory.getLanguageVersion();
335 String fullLangName = langName + " (" + langVersion + ")";
336 trace("\t" + fullEngName);
337 List<String> engNames = factory.getNames();
338 for(String name: engNames)
339 {
340 trace("\tEngine Alias: " + name);
341 }
342 trace("\t" + fullLangName);
343 engines.add(factory.getScriptEngine());
344 engineBox.addItem(fullLangName + " / " + fullEngName);
345 }
346 if (engineBox.getItemCount()>0)
347 {
348 engineBox.setSelectedIndex(0);
349 setEngine(engines.get(0));
350 }
351 }
354 static final String defaultCodeStr =
355 "/**\n" +
356 " * This is some example Javascript.\n" +
357 " * Try executing\n" +
358 " */\n" +
359 "importPackage(javax.swing);\n" +
360 "function sayHello() {\n" +
361 " JOptionPane.showMessageDialog(null, 'Hello, world!',\n" +
362 " 'Welcome to Inkscape', JOptionPane.WARNING_MESSAGE);\n" +
363 "}\n" +
364 "\n" +
365 "sayHello();\n" +
366 "\n";
369 //########################################################################
370 //# A C T I O N S
371 //########################################################################
372 Action newAction;
373 Action openAction;
374 Action quitAction;
375 Action runAction;
376 Action saveAction;
377 Action saveAsAction;
378 Action stopAction;
382 class NewAction extends AbstractAction
383 {
385 public void actionPerformed(ActionEvent evt)
386 {
387 //
388 }
390 public NewAction()
391 {
392 super("New", Resource.getIcon("document-new.png"));
393 putValue(SHORT_DESCRIPTION, "Create a new script file");
394 }
396 }
400 class OpenAction extends AbstractAction
401 {
403 public void actionPerformed(ActionEvent evt)
404 {
405 editor.openFile();
406 }
408 public OpenAction()
409 {
410 super("Open", Resource.getIcon("document-open.png"));
411 putValue(SHORT_DESCRIPTION, "Open a script file");
412 }
414 }
418 class QuitAction extends AbstractAction
419 {
421 public void actionPerformed(ActionEvent evt)
422 {
423 setVisible(false);
424 }
426 public QuitAction()
427 {
428 super("Quit", Resource.getIcon("system-log-out.png"));
429 putValue(SHORT_DESCRIPTION, "Quit this script console");
430 }
432 }
436 class RunAction extends AbstractAction
437 {
439 public void actionPerformed(ActionEvent evt)
440 {
441 String txt = editor.getText();
442 doRun(txt);
443 }
445 public RunAction()
446 {
447 super("Run", Resource.getIcon("go-next.png"));
448 putValue(SHORT_DESCRIPTION, "Run the script in the editor");
449 }
451 }
455 class SaveAction extends AbstractAction
456 {
458 public void actionPerformed(ActionEvent evt)
459 {
460 editor.saveFile();
461 }
463 public SaveAction()
464 {
465 super("Save", Resource.getIcon("document-save.png"));
466 putValue(SHORT_DESCRIPTION, "Save file");
467 }
469 }
473 class SaveAsAction extends AbstractAction
474 {
476 public void actionPerformed(ActionEvent evt)
477 {
478 editor.saveAsFile();
479 }
481 public SaveAsAction()
482 {
483 super("SaveAs", Resource.getIcon("document-save-as.png"));
484 putValue(SHORT_DESCRIPTION, "Save under a new file name");
485 }
487 }
491 class StopAction extends AbstractAction
492 {
494 public void actionPerformed(ActionEvent evt)
495 {
496 //#
497 }
499 public StopAction()
500 {
501 super("Stop", Resource.getIcon("process-stop.png"));
502 putValue(SHORT_DESCRIPTION, "Stop the running script");
503 }
505 }
509 HashMap<String, Action> actions;
510 void setupActions()
511 {
512 actions = new HashMap<String, Action>();
513 actions.put("New", newAction = new NewAction());
514 actions.put("Open", openAction = new OpenAction());
515 actions.put("Quit", quitAction = new QuitAction());
516 actions.put("Run", runAction = new RunAction());
517 actions.put("Save", saveAction = new SaveAction());
518 actions.put("SaveAs", saveAsAction = new SaveAsAction());
519 actions.put("Stop", stopAction = new StopAction());
520 }
523 public void enableAction(String name)
524 {
525 Action action = actions.get(name);
526 if (action == null)
527 return;
528 action.setEnabled(true);
529 }
531 public void disableAction(String name)
532 {
533 Action action = actions.get(name);
534 if (action == null)
535 return;
536 action.setEnabled(false);
537 }
541 //########################################################################
542 //# S E T U P
543 //########################################################################
545 JButton toolbarButton(Action action)
546 {
547 JButton btn = new JButton(action);
548 btn.setText("");
549 btn.setToolTipText((String)action.getValue(Action.SHORT_DESCRIPTION));
550 return btn;
551 }
554 private boolean setup()
555 {
556 setTitle("Inkscape Script Console");
557 setSize(600, 400);
558 setIconImage(Resource.getImage("inkscape.png"));
559 setDefaultCloseOperation(WindowConstants.HIDE_ON_CLOSE);
561 //######################################################
562 //# A C T I O N S
563 //######################################################
564 setupActions();
566 //######################################################
567 //# M E N U
568 //######################################################
569 menubar = new JMenuBar();
570 setJMenuBar(menubar);
572 JMenu menu = new JMenu("File");
573 menubar.add(menu);
574 menu.add(new JMenuItem(openAction));
575 menu.add(new JMenuItem(saveAction));
576 menu.add(new JMenuItem(saveAsAction));
577 menu.add(new JMenuItem(quitAction));
579 menu = new JMenu("Run");
580 menubar.add(menu);
581 menu.add(new JMenuItem(runAction));
582 menu.add(new JMenuItem(stopAction));
584 //######################################################
585 //# T O O L B A R
586 //######################################################
587 toolbar = new JToolBar();
588 getContentPane().add(toolbar, BorderLayout.NORTH);
589 toolbar.add(toolbarButton(openAction));
590 toolbar.add(toolbarButton(saveAction));
591 toolbar.add(toolbarButton(runAction));
592 toolbar.add(toolbarButton(stopAction));
594 //######################################################
595 //# C O N T E N T
596 //######################################################
597 tabPane = new JTabbedPane();
598 getContentPane().add(tabPane, BorderLayout.CENTER);
600 terminal = new Terminal();
601 tabPane.addTab("Console",
602 Resource.getIcon("utilities-terminal.png"),
603 terminal);
604 terminal.output("\nscript> ");
606 editor = new Editor(this);
607 tabPane.addTab("Script",
608 Resource.getIcon("accessories-text-editor.png"),
609 editor);
611 editor.setText(defaultCodeStr);
613 //######################################################
614 //# E N G I N E
615 //######################################################
616 initScripts();
618 return true;
619 }
626 public ScriptConsole()
627 {
628 setup();
629 }
632 private static ScriptConsole _instance = null;
633 public static ScriptConsole getInstance()
634 {
635 if (_instance == null)
636 _instance = new ScriptConsole();
637 return _instance;
638 }
641 public static void main(String argv[])
642 {
643 ScriptConsole sc = getInstance();
644 sc.setVisible(true);
645 }
648 }
649 //########################################################################
650 //# E N D O F F I L E
651 //########################################################################