index bec24f165dfd78310eb1c71d77e6d658519677a9..eabf147f64980afa2acbb18027dc682c961da6a3 100644 (file)
* Released under GNU GPL, read the file 'COPYING' for more information
*/
-/*
-TODO:
-FIXME:
- After Inkscape makes a formal requirement for a GTK version above 2.11.4, please
- replace all the instances of ink_ext_XXXXXX in this file that represent
- svg files with ink_ext_XXXXXX.svg . Doing so will prevent errors in extensions
- that call inkscape to manipulate the file.
-
- "** (inkscape:5848): WARNING **: Format autodetect failed. The file is being opened as SVG."
-
- references:
- http://www.gtk.org/api/2.6/glib/glib-File-Utilities.html#g-mkstemp
- http://ftp.gnome.org/pub/gnome/sources/glib/2.11/glib-2.11.4.changes
- http://developer.gnome.org/doc/API/2.0/glib/glib-File-Utilities.html#g-mkstemp
-
- --Aaron Spike
-*/
#define __INKSCAPE_EXTENSION_IMPLEMENTATION_SCRIPT_C__
#ifdef HAVE_CONFIG_H
#include "ui/view/view.h"
#include "desktop-handles.h"
+#include "desktop.h"
#include "selection.h"
#include "sp-namedview.h"
#include "io/sys.h"
-#include "prefs-utils.h"
+#include "preferences.h"
#include "../system.h"
#include "extension/effect.h"
#include "extension/output.h"
#include "extension/db.h"
#include "script.h"
#include "dialogs/dialog-events.h"
+#include "application/application.h"
+#include "xml/node.h"
+#include "xml/attribute-record.h"
#include "util/glib-list-iterators.h"
namespace Extension {
namespace Implementation {
-void pump_events (void) {
+/** \brief Make GTK+ events continue to come through a little bit
+
+ This just keeps coming the events through so that we'll make the GUI
+ update and look pretty.
+*/
+void
+Script::pump_events (void) {
while( Gtk::Main::events_pending() )
Gtk::Main::iteration();
return;
}
-//Interpreter lookup table
-struct interpreter_t {
- gchar const *identity;
- gchar const *prefstring;
- gchar const *defaultval;
-};
-
/** \brief A table of what interpreters to call for a given language
given script. It also tracks the preference to use to overwrite
the given interpreter to a custom one per user.
*/
-static interpreter_t const interpreterTab[] = {
+Script::interpreter_t const Script::interpreterTab[] = {
{"perl", "perl-interpreter", "perl" },
+#ifdef WIN32
+ {"python", "python-interpreter", "pythonw" },
+#else
{"python", "python-interpreter", "python" },
+#endif
{"ruby", "ruby-interpreter", "ruby" },
{"shell", "shell-interpreter", "sh" },
{ NULL, NULL, NULL }
-/**
- * Look up an interpreter name, and translate to something that
- * is executable
- */
-static Glib::ustring
-resolveInterpreterExecutable(const Glib::ustring &interpNameArg)
+/** \brief Look up an interpreter name, and translate to something that
+ is executable
+ \param interpNameArg The name of the interpreter that we're looking
+ for, should be an entry in interpreterTab
+*/
+Glib::ustring
+Script::resolveInterpreterExecutable(const Glib::ustring &interpNameArg)
{
Glib::ustring interpName = interpNameArg;
interpName = interp->defaultval;
// 1. Check preferences
- gchar const *prefInterp = prefs_get_string_attribute("extensions", interp->prefstring);
+ Inkscape::Preferences *prefs = Inkscape::Preferences::get();
+ Glib::ustring prefInterp = prefs->getString("/extensions/" + Glib::ustring(interp->prefstring));
- if (prefInterp) {
+ if (!prefInterp.empty()) {
interpName = prefInterp;
return interpName;
}
-#ifdef _WIN32
+#ifdef WIN32
// 2. Windows. Try looking relative to inkscape.exe
RegistryTool rt;
if (rt.getExeInfo(fullPath, path, exeName)) {
Glib::ustring interpPath = path;
interpPath.append("\\");
- interpPath.append(interpName);
+ interpPath.append(interpNameArg);
interpPath.append("\\");
interpPath.append(interpName);
interpPath.append(".exe");
interpPath .c_str(),
(int)finfo.st_size);
return interpPath;
- }
+ }
}
// 3. Try searching the path
return interpName;
}
-
-
/** \brief This function creates a script object and sets up the
variables.
\return A script object
{
}
-
/**
* brief Destructor
*/
}
- Glib::ustring path;
+ Glib::ustring path;
gchar *s = (gchar *) g_getenv("PATH");
if (s)
path = s;
localPath = path.substr(pos, pos2-pos);
pos = pos2+1;
}
-
+
//printf("### %s\n", localPath.c_str());
- Glib::ustring candidatePath =
+ Glib::ustring candidatePath =
Glib::build_filename(localPath, command);
if (Inkscape::IO::file_test(candidatePath .c_str(),
Script::load(Inkscape::Extension::Extension *module)
{
if (module->loaded())
- return TRUE;
+ return true;
helper_extension = "";
/* This should probably check to find the executable... */
Inkscape::XML::Node *child_repr = sp_repr_children(module->get_repr());
while (child_repr != NULL) {
- if (!strcmp(child_repr->name(), "script")) {
+ if (!strcmp(child_repr->name(), INKSCAPE_EXTENSION_NS "script")) {
child_repr = sp_repr_children(child_repr);
while (child_repr != NULL) {
- if (!strcmp(child_repr->name(), "command")) {
+ if (!strcmp(child_repr->name(), INKSCAPE_EXTENSION_NS "command")) {
const gchar *interpretstr = child_repr->attribute("interpreter");
if (interpretstr != NULL) {
Glib::ustring interpString =
resolveInterpreterExecutable(interpretstr);
+ //g_message("Found: %s and %s",interpString.c_str(),interpretstr);
command.insert(command.end(), interpretstr);
}
+ Glib::ustring tmp = "\"";
+ tmp += solve_reldir(child_repr);
+ tmp += "\"";
- command.insert(command.end(), solve_reldir(child_repr));
+ command.insert(command.end(), tmp);
}
- if (!strcmp(child_repr->name(), "helper_extension")) {
+ if (!strcmp(child_repr->name(), INKSCAPE_EXTENSION_NS "helper_extension")) {
helper_extension = sp_repr_children(child_repr)->content();
}
child_repr = sp_repr_next(child_repr);
child_repr = sp_repr_next(child_repr);
}
- //g_return_val_if_fail(command.length() > 0, FALSE);
+ //g_return_val_if_fail(command.length() > 0, false);
return true;
}
command if it has been allocated.
*/
void
-Script::unload(Inkscape::Extension::Extension *module)
+Script::unload(Inkscape::Extension::Extension */*module*/)
{
command.clear();
helper_extension = "";
bool
Script::check(Inkscape::Extension::Extension *module)
{
+ int script_count = 0;
Inkscape::XML::Node *child_repr = sp_repr_children(module->get_repr());
while (child_repr != NULL) {
- if (!strcmp(child_repr->name(), "script")) {
+ if (!strcmp(child_repr->name(), INKSCAPE_EXTENSION_NS "script")) {
+ script_count++;
child_repr = sp_repr_children(child_repr);
while (child_repr != NULL) {
- if (!strcmp(child_repr->name(), "check")) {
+ if (!strcmp(child_repr->name(), INKSCAPE_EXTENSION_NS "check")) {
Glib::ustring command_text = solve_reldir(child_repr);
if (command_text.size() > 0) {
/* I've got the command */
bool existance = check_existance(command_text);
if (!existance)
- return FALSE;
+ return false;
}
}
- if (!strcmp(child_repr->name(), "helper_extension")) {
+ if (!strcmp(child_repr->name(), INKSCAPE_EXTENSION_NS "helper_extension")) {
gchar const *helper = sp_repr_children(child_repr)->content();
if (Inkscape::Extension::db.get(helper) == NULL) {
- return FALSE;
+ return false;
}
}
child_repr = sp_repr_next(child_repr);
}
+ if (script_count == 0) {
+ return false;
+ }
+
return true;
}
+class ScriptDocCache : public ImplementationDocumentCache {
+ friend class Script;
+protected:
+ std::string _filename;
+ int _tempfd;
+public:
+ ScriptDocCache (Inkscape::UI::View::View * view);
+ ~ScriptDocCache ( );
+};
+
+ScriptDocCache::ScriptDocCache (Inkscape::UI::View::View * view) :
+ ImplementationDocumentCache(view),
+ _filename(""),
+ _tempfd(0)
+{
+ try {
+ _tempfd = Inkscape::IO::file_open_tmp(_filename, "ink_ext_XXXXXX.svg");
+ } catch (...) {
+ /// \todo Popup dialog here
+ return;
+ }
+
+ SPDesktop *desktop = (SPDesktop *) view;
+ sp_namedview_document_from_window(desktop);
+ Inkscape::Extension::save(
+ Inkscape::Extension::db.get(SP_MODULE_KEY_OUTPUT_SVG_INKSCAPE),
+ view->doc(), _filename.c_str(), false, false, false);
-/**
- \return A dialog for preferences
- \brief A stub funtion right now
- \param module Module who's preferences need getting
- \param filename Hey, the file you're getting might be important
+ return;
+}
- This function should really do something, right now it doesn't.
-*/
-Gtk::Widget *
-Script::prefs_input(Inkscape::Extension::Input *module,
- const gchar *filename)
+ScriptDocCache::~ScriptDocCache ( )
{
- return module->autogui(NULL, NULL);
+ close(_tempfd);
+ unlink(_filename.c_str());
}
+ImplementationDocumentCache *
+Script::newDocCache( Inkscape::Extension::Extension * /*ext*/, Inkscape::UI::View::View * view ) {
+ return new ScriptDocCache(view);
+}
/**
\return A dialog for preferences
\brief A stub funtion right now
- \param module Module whose preferences need getting
+ \param module Module who's preferences need getting
+ \param filename Hey, the file you're getting might be important
This function should really do something, right now it doesn't.
*/
Gtk::Widget *
-Script::prefs_output(Inkscape::Extension::Output *module)
+Script::prefs_input(Inkscape::Extension::Input *module,
+ const gchar */*filename*/)
{
- return module->autogui(NULL, NULL);
+ return module->autogui(NULL, NULL);
}
/**
\return A dialog for preferences
\brief A stub funtion right now
- \param module Module who's preferences need getting
+ \param module Module whose preferences need getting
This function should really do something, right now it doesn't.
*/
Gtk::Widget *
-Script::prefs_effect(Inkscape::Extension::Effect *module,
- Inkscape::UI::View::View *view,
- sigc::signal<void> * changeSignal,
- ImplementationDocumentCache * docCache)
+Script::prefs_output(Inkscape::Extension::Output *module)
{
- SPDocument * current_document = view->doc();
-
- using Inkscape::Util::GSListConstIterator;
- GSListConstIterator<SPItem *> selected =
- sp_desktop_selection((SPDesktop *)view)->itemList();
- Inkscape::XML::Node * first_select = NULL;
- if (selected != NULL) {
- const SPItem * item = *selected;
- first_select = SP_OBJECT_REPR(item);
- }
-
- return module->autogui(current_document, first_select, changeSignal);
+ return module->autogui(NULL, NULL);
}
-
-
-
/**
\return A new document that has been opened
\brief This function uses a filename that is put in, and calls
std::string tempfilename_out;
int tempfd_out = 0;
try {
- tempfd_out = Glib::file_open_tmp(tempfilename_out, "ink_ext_XXXXXX");
+ tempfd_out = Inkscape::IO::file_open_tmp(tempfilename_out, "ink_ext_XXXXXX.svg");
} catch (...) {
/// \todo Popup dialog here
return NULL;
} // data_read
if (mydoc != NULL) {
- sp_document_set_uri(mydoc, filenameArg);
+ g_free(mydoc->base);
+ mydoc->base = NULL;
+ sp_document_change_uri_and_hrefs(mydoc, filenameArg);
}
// make sure we don't leak file descriptors from g_file_open_tmp
std::string tempfilename_in;
int tempfd_in = 0;
try {
- tempfd_in = Glib::file_open_tmp(tempfilename_in, "ink_ext_XXXXXX");
+ tempfd_in = Inkscape::IO::file_open_tmp(tempfilename_in, "ink_ext_XXXXXX.svg");
} catch (...) {
/// \todo Popup dialog here
return;
if (helper_extension.size() == 0) {
Inkscape::Extension::save(
Inkscape::Extension::db.get(SP_MODULE_KEY_OUTPUT_SVG_INKSCAPE),
- doc, tempfilename_in.c_str(), FALSE, FALSE, FALSE);
+ doc, tempfilename_in.c_str(), false, false, false);
} else {
Inkscape::Extension::save(
Inkscape::Extension::db.get(helper_extension.c_str()),
- doc, tempfilename_in.c_str(), FALSE, FALSE, FALSE);
+ doc, tempfilename_in.c_str(), false, false, false);
}
void
Script::effect(Inkscape::Extension::Effect *module,
Inkscape::UI::View::View *doc,
- ImplementationDocumentCache * docCache)
+ ImplementationDocumentCache * docCache)
{
+ if (docCache == NULL) {
+ docCache = newDocCache(module, doc);
+ }
+ ScriptDocCache * dc = dynamic_cast<ScriptDocCache *>(docCache);
+ if (dc == NULL) {
+ printf("TOO BAD TO LIVE!!!");
+ exit(1);
+ }
+
+ SPDesktop *desktop = (SPDesktop *)doc;
+ sp_namedview_document_from_window(desktop);
+
+ gchar * orig_output_extension = g_strdup(sp_document_repr_root(desktop->doc())->attribute("inkscape:output_extension"));
+
std::list<std::string> params;
module->paramListString(params);
- if (module->no_doc) {
- // this is a no-doc extension, e.g. a Help menu command;
+ if (module->no_doc) {
+ // this is a no-doc extension, e.g. a Help menu command;
// just run the command without any files, ignoring errors
Glib::ustring empty;
return;
}
- std::string tempfilename_in;
- int tempfd_in = 0;
- try {
- tempfd_in = Glib::file_open_tmp(tempfilename_in, "ink_ext_XXXXXX.svg");
- } catch (...) {
- /// \todo Popup dialog here
- return;
- }
-
std::string tempfilename_out;
int tempfd_out = 0;
try {
- tempfd_out = Glib::file_open_tmp(tempfilename_out, "ink_ext_XXXXXX.svg");
+ tempfd_out = Inkscape::IO::file_open_tmp(tempfilename_out, "ink_ext_XXXXXX.svg");
} catch (...) {
/// \todo Popup dialog here
return;
}
- SPDesktop *desktop = (SPDesktop *) doc;
- sp_namedview_document_from_window(desktop);
-
- Inkscape::Extension::save(
- Inkscape::Extension::db.get(SP_MODULE_KEY_OUTPUT_SVG_INKSCAPE),
- doc->doc(), tempfilename_in.c_str(), FALSE, FALSE, FALSE);
-
- pump_events();
-
if (desktop != NULL) {
Inkscape::Util::GSListConstIterator<SPItem *> selected =
sp_desktop_selection(desktop)->itemList();
}
file_listener fileout;
- int data_read = execute(command, params, tempfilename_in, fileout);
+ int data_read = execute(command, params, dc->_filename, fileout);
fileout.toFile(tempfilename_out);
pump_events();
pump_events();
// make sure we don't leak file descriptors from g_file_open_tmp
- close(tempfd_in);
close(tempfd_out);
// FIXME: convert to utf8 (from "filename encoding") and unlink_utf8name
- unlink(tempfilename_in.c_str());
unlink(tempfilename_out.c_str());
/* Do something with mydoc.... */
doc->doc()->emitReconstructionFinish();
mydoc->release();
sp_namedview_update_layers_from_document(desktop);
+
+ sp_document_repr_root(desktop->doc())->setAttribute("inkscape:output_extension", orig_output_extension);
}
+ g_free(orig_output_extension);
return;
}
@@ -822,16 +830,34 @@ Script::copy_doc (Inkscape::XML::Node * oldroot, Inkscape::XML::Node * newroot)
for (Inkscape::XML::Node * newroot_namedview_child = child->firstChild();
newroot_namedview_child != NULL;
newroot_namedview_child = newroot_namedview_child->next()) {
- oldroot_namedview->appendChild(newroot_namedview_child->duplicate(child->document()));
+ oldroot_namedview->appendChild(newroot_namedview_child->duplicate(oldroot->document()));
}
}
} else {
- oldroot->appendChild(child->duplicate(newroot->document()));
+ oldroot->appendChild(child->duplicate(oldroot->document()));
}
}
- oldroot->setAttribute("width", newroot->attribute("width"));
- oldroot->setAttribute("height", newroot->attribute("height"));
+ {
+ using Inkscape::Util::List;
+ using Inkscape::XML::AttributeRecord;
+ std::vector<gchar const *> attribs;
+
+ // Make a list of all attributes of the old root node.
+ for (List<AttributeRecord const> iter = oldroot->attributeList(); iter; ++iter) {
+ attribs.push_back(g_quark_to_string(iter->key));
+ }
+
+ // Delete the attributes of the old root nodes.
+ for (std::vector<gchar const *>::const_iterator it = attribs.begin(); it != attribs.end(); it++)
+ oldroot->setAttribute(*it, NULL);
+
+ // Set the new attributes.
+ for (List<AttributeRecord const> iter = newroot->attributeList(); iter; ++iter) {
+ gchar const *name = g_quark_to_string(iter->key);
+ oldroot->setAttribute(name, newroot->attribute(name));
+ }
+ }
/** \todo Restore correct layer */
/** \todo Restore correct selection */
std::vector <std::string> argv;
+/*
for (std::list<std::string>::const_iterator i = in_command.begin();
i != in_command.end(); i++) {
argv.push_back(*i);
}
+*/
+ // according to http://www.gtk.org/api/2.6/glib/glib-Spawning-Processes.html spawn quotes parameter containing spaces
+ // we tokenize so that spwan does not need to quote over all params
+ for (std::list<std::string>::const_iterator i = in_command.begin();
+ i != in_command.end(); i++) {
+ std::string param_str = *i;
+ do {
+ //g_message("param: %s", param_str.c_str());
+ size_t first_space = param_str.find_first_of(' ');
+ size_t first_quote = param_str.find_first_of('"');
+ //std::cout << "first space " << first_space << std::endl;
+ //std::cout << "first quote " << first_quote << std::endl;
+
+ if((first_quote != std::string::npos) && (first_quote == 0)) {
+ size_t next_quote = param_str.find_first_of('"', first_quote + 1);
+ //std::cout << "next quote " << next_quote << std::endl;
+
+ if(next_quote != std::string::npos) {
+ //std::cout << "now split " << next_quote << std::endl;
+ //std::cout << "now split " << param_str.substr(1, next_quote - 1) << std::endl;
+ //std::cout << "now split " << param_str.substr(next_quote + 1) << std::endl;
+ std::string part_str = param_str.substr(1, next_quote - 1);
+ if(part_str.size() > 0)
+ argv.push_back(part_str);
+ param_str = param_str.substr(next_quote + 1);
- if (!(filein.empty())) {
- argv.push_back(filein);
+ }
+ else {
+ if(param_str.size() > 0)
+ argv.push_back(param_str);
+ param_str = "";
+ }
+
+ }
+ else if(first_space != std::string::npos) {
+ //std::cout << "now split " << first_space << std::endl;
+ //std::cout << "now split " << param_str.substr(0, first_space) << std::endl;
+ //std::cout << "now split " << param_str.substr(first_space + 1) << std::endl;
+ std::string part_str = param_str.substr(0, first_space);
+ if(part_str.size() > 0)
+ argv.push_back(part_str);
+ param_str = param_str.substr(first_space + 1);
+ }
+ else {
+ if(param_str.size() > 0)
+ argv.push_back(param_str);
+ param_str = "";
+ }
+ } while(param_str.size() > 0);
}
for (std::list<std::string>::const_iterator i = in_params.begin();
i != in_params.end(); i++) {
- argv.push_back(*i);
+ //g_message("Script parameter: %s",(*i)g.c_str());
+ argv.push_back(*i);
}
-/*
- for (std::vector<std::string>::const_iterator i = argv.begin();
- i != argv.end(); i++) {
- std::cout << *i << std::endl;
+ if (!(filein.empty())) {
+ argv.push_back(filein);
}
-*/
int stdout_pipe, stderr_pipe;
try {
- Glib::spawn_async_with_pipes(Glib::get_current_dir(), // working directory
+ Inkscape::IO::spawn_async_with_pipes(Glib::get_current_dir(), // working directory
argv, // arg v
Glib::SPAWN_SEARCH_PATH /*| Glib::SPAWN_DO_NOT_REAP_CHILD*/,
sigc::slot<void>(),
&stdout_pipe, // STDOUT
&stderr_pipe); // STDERR
} catch (Glib::SpawnError e) {
- printf("Can't Spawn!!! %d\n", e.code());
+ printf("Can't Spawn!!! spawn returns: %d\n", e.code());
return 0;
}
}
Glib::ustring stderr_data = fileerr.string();
- if (stderr_data.length() != 0) {
+ if (stderr_data.length() != 0 &&
+ Inkscape::NSApplication::Application::getUseGui()
+ ) {
checkStderr(stderr_data, Gtk::MESSAGE_INFO,
_("Inkscape has received additional data from the script executed. "
"The script did not return an error, but this may indicate the results will not be as expected."));