X-Git-Url: https://git.tokkee.org/?a=blobdiff_plain;f=src%2Fextension%2Fimplementation%2Fscript.cpp;h=9475b479623ed6e98865d48cd5baf03c8bf5a6e2;hb=86b3a7fc48d3fa59eb2e3289e0b8b2b56c7ed270;hp=96c436dfd0766f6bc5799c348369740cd443df4d;hpb=1c954df5d7f214580761f55fdd9470e893d1a032;p=inkscape.git diff --git a/src/extension/implementation/script.cpp b/src/extension/implementation/script.cpp index 96c436dfd..9475b4796 100644 --- a/src/extension/implementation/script.cpp +++ b/src/extension/implementation/script.cpp @@ -6,28 +6,11 @@ * Bryce Harrington * Ted Gould * - * Copyright (C) 2002-2005 Authors + * Copyright (C) 2002-2005,2007 Authors * * 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 @@ -41,16 +24,19 @@ FIXME: #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/input.h" #include "extension/db.h" #include "script.h" #include "dialogs/dialog-events.h" +#include "application/application.h" #include "util/glib-list-iterators.h" @@ -74,14 +60,17 @@ namespace Inkscape { namespace Extension { namespace Implementation { - - -//Interpreter lookup table -struct interpreter_t { - gchar * identity; - gchar * prefstring; - gchar * defaultval; -}; +/** \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; +} /** \brief A table of what interpreters to call for a given language @@ -90,9 +79,13 @@ struct interpreter_t { given script. It also tracks the preference to use to overwrite the given interpreter to a custom one per user. */ -static interpreter_t 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 } @@ -100,17 +93,18 @@ static interpreter_t interpreterTab[] = { -/** - * 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; - interpreter_t *interp; + interpreter_t const *interp; bool foundInterp = false; for (interp = interpreterTab ; interp->identity ; interp++ ){ if (interpName == interp->identity) { @@ -125,15 +119,15 @@ resolveInterpreterExecutable(const Glib::ustring &interpNameArg) interpName = interp->defaultval; // 1. Check preferences - gchar *prefInterp = (gchar *)prefs_get_string_attribute( - "extensions", interp->prefstring); + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + Glib::ustring prefInterp = prefs->getString("extensions", 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; @@ -143,7 +137,7 @@ resolveInterpreterExecutable(const Glib::ustring &interpNameArg) 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"); @@ -153,7 +147,7 @@ resolveInterpreterExecutable(const Glib::ustring &interpNameArg) interpPath .c_str(), (int)finfo.st_size); return interpPath; - } + } } // 3. Try searching the path @@ -173,66 +167,6 @@ resolveInterpreterExecutable(const Glib::ustring &interpNameArg) return interpName; } - -class file_listener { - Glib::ustring _string; - sigc::connection _conn; - Glib::RefPtr _channel; - Glib::RefPtr _main_loop; - -public: - file_listener () { }; - ~file_listener () { - _conn.disconnect(); - }; - - void init (int fd, Glib::RefPtr main) { - _channel = Glib::IOChannel::create_from_fd(fd); - _channel->set_encoding(); - _conn = Glib::signal_io().connect(sigc::mem_fun(*this, &file_listener::read), _channel, Glib::IO_IN | Glib::IO_HUP | Glib::IO_ERR); - _main_loop = main; - - return; - }; - - bool read (Glib::IOCondition condition) { - if (condition != Glib::IO_IN) { - _main_loop->quit(); - return false; - } - - Glib::IOStatus status; - Glib::ustring out; - status = _channel->read_to_end(out); - - if (status != Glib::IO_STATUS_NORMAL) { - _main_loop->quit(); - return false; - } - - _string += out; - return true; - }; - - // Note, doing a copy here, on purpose - Glib::ustring string (void) { return _string; }; - - void toFile (const Glib::ustring &name) { - Glib::RefPtr stdout_file = Glib::IOChannel::create_from_file(name, "w"); - stdout_file->write(_string); - return; - }; -}; - -int execute (const std::list &in_command, - const std::list &in_params, - const Glib::ustring &filein, - file_listener &fileout); -void checkStderr (const Glib::ustring &data, - Gtk::MessageType type, - const Glib::ustring &message); - - /** \brief This function creates a script object and sets up the variables. \return A script object @@ -246,7 +180,6 @@ Script::Script() : { } - /** * brief Destructor */ @@ -344,7 +277,7 @@ Script::check_existance(const Glib::ustring &command) } - Glib::ustring path; + Glib::ustring path; gchar *s = (gchar *) g_getenv("PATH"); if (s) path = s; @@ -367,9 +300,9 @@ Script::check_existance(const Glib::ustring &command) 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(), @@ -408,27 +341,31 @@ bool 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); @@ -439,7 +376,7 @@ Script::load(Inkscape::Extension::Extension *module) 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; } @@ -454,7 +391,7 @@ Script::load(Inkscape::Extension::Extension *module) command if it has been allocated. */ void -Script::unload(Inkscape::Extension::Extension *module) +Script::unload(Inkscape::Extension::Extension */*module*/) { command.clear(); helper_extension = ""; @@ -472,25 +409,27 @@ Script::unload(Inkscape::Extension::Extension *module) 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; } } @@ -502,40 +441,70 @@ Script::check(Inkscape::Extension::Extension *module) 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; + } -/** - \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 + SPDesktop *desktop = (SPDesktop *) view; + sp_namedview_document_from_window(desktop); - This function should really do something, right now it doesn't. -*/ -Gtk::Widget * -Script::prefs_input(Inkscape::Extension::Input *module, - const gchar *filename) + Inkscape::Extension::save( + Inkscape::Extension::db.get(SP_MODULE_KEY_OUTPUT_SVG_INKSCAPE), + view->doc(), _filename.c_str(), false, false, false); + + return; +} + +ScriptDocCache::~ScriptDocCache ( ) { - /*return module->autogui(); */ - return 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); } @@ -543,32 +512,16 @@ Script::prefs_output(Inkscape::Extension::Output *module) /** \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 * changeSignal) +Script::prefs_output(Inkscape::Extension::Output *module) { - SPDocument * current_document = view->doc(); - - using Inkscape::Util::GSListConstIterator; - GSListConstIterator 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); + 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 @@ -594,66 +547,48 @@ SPDocument * Script::open(Inkscape::Extension::Input *module, const gchar *filenameArg) { -#if 0 - Glib::ustring filename = filenameArg; - - gchar *tmpname; - - // FIXME: process the GError instead of passing NULL - gint tempfd = g_file_open_tmp("ink_ext_XXXXXX", &tmpname, NULL); - if (tempfd == -1) { - /* Error, couldn't create temporary filename */ - if (errno == EINVAL) { - /* The last six characters of template were not XXXXXX. Now template is unchanged. */ - perror("Extension::Script: template for filenames is misconfigured.\n"); - exit(-1); - } else if (errno == EEXIST) { - /* Now the contents of template are undefined. */ - perror("Extension::Script: Could not create a unique temporary filename\n"); - return NULL; - } else { - perror("Extension::Script: Unknown error creating temporary filename\n"); - exit(-1); - } - } + std::list params; + module->paramListString(params); - Glib::ustring tempfilename_out = tmpname; - g_free(tmpname); + std::string tempfilename_out; + int tempfd_out = 0; + try { + tempfd_out = Inkscape::IO::file_open_tmp(tempfilename_out, "ink_ext_XXXXXX.svg"); + } catch (...) { + /// \todo Popup dialog here + return NULL; + } - gsize bytesRead = 0; - gsize bytesWritten = 0; - GError *error = NULL; - Glib::ustring local_filename = - g_filename_from_utf8( filename.c_str(), -1, - &bytesRead, &bytesWritten, &error); + std::string lfilename = Glib::filename_from_utf8(filenameArg); - int data_read = execute(command, local_filename, tempfilename_out); + file_listener fileout; + int data_read = execute(command, params, lfilename, fileout); + fileout.toFile(tempfilename_out); - SPDocument *mydoc = NULL; + SPDocument * mydoc = NULL; if (data_read > 10) { if (helper_extension.size()==0) { mydoc = Inkscape::Extension::open( - Inkscape::Extension::db.get(SP_MODULE_KEY_INPUT_SVG), - tempfilename_out.c_str()); + Inkscape::Extension::db.get(SP_MODULE_KEY_INPUT_SVG), + tempfilename_out.c_str()); } else { mydoc = Inkscape::Extension::open( - Inkscape::Extension::db.get(helper_extension.c_str()), - tempfilename_out.c_str()); + Inkscape::Extension::db.get(helper_extension.c_str()), + tempfilename_out.c_str()); } - } + } // data_read - if (mydoc != NULL) - sp_document_set_uri(mydoc, (const gchar *)filename.c_str()); + if (mydoc != NULL) { + sp_document_set_uri(mydoc, filenameArg); + } // make sure we don't leak file descriptors from g_file_open_tmp - close(tempfd); - // FIXME: convert to utf8 (from "filename encoding") and unlink_utf8name - unlink(tempfilename_out.c_str()); + close(tempfd_out); + unlink(tempfilename_out.c_str()); return mydoc; -#endif -} +} // open @@ -686,60 +621,41 @@ Script::save(Inkscape::Extension::Output *module, SPDocument *doc, const gchar *filenameArg) { -#if 0 - Glib::ustring filename = filenameArg; - - gchar *tmpname; - // FIXME: process the GError instead of passing NULL - gint tempfd = g_file_open_tmp("ink_ext_XXXXXX", &tmpname, NULL); - if (tempfd == -1) { - /* Error, couldn't create temporary filename */ - if (errno == EINVAL) { - /* The last six characters of template were not XXXXXX. Now template is unchanged. */ - perror("Extension::Script: template for filenames is misconfigured.\n"); - exit(-1); - } else if (errno == EEXIST) { - /* Now the contents of template are undefined. */ - perror("Extension::Script: Could not create a unique temporary filename\n"); - return; - } else { - perror("Extension::Script: Unknown error creating temporary filename\n"); - exit(-1); - } - } + std::list params; + module->paramListString(params); - Glib::ustring tempfilename_in = tmpname; - g_free(tmpname); + std::string tempfilename_in; + int tempfd_in = 0; + try { + 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); } - gsize bytesRead = 0; - gsize bytesWritten = 0; - GError *error = NULL; - Glib::ustring local_filename = - g_filename_from_utf8( filename.c_str(), -1, - &bytesRead, &bytesWritten, &error); - - Glib::ustring local_command = command; - Glib::ustring paramString = *module->paramString(); - local_command.append(paramString); - execute(local_command, tempfilename_in, local_filename); + file_listener fileout; + execute(command, params, tempfilename_in, fileout); + std::string lfilename = Glib::filename_from_utf8(filenameArg); + fileout.toFile(lfilename); // make sure we don't leak file descriptors from g_file_open_tmp - close(tempfd); + close(tempfd_in); // FIXME: convert to utf8 (from "filename encoding") and unlink_utf8name unlink(tempfilename_in.c_str()); -#endif + + return; } @@ -773,14 +689,30 @@ Script::save(Inkscape::Extension::Output *module, point both should be full, and the second one is loaded. */ void -Script::effect(Inkscape::Extension::Effect *module, Inkscape::UI::View::View *doc) +Script::effect(Inkscape::Extension::Effect *module, + Inkscape::UI::View::View *doc, + ImplementationDocumentCache * docCache) { + if (docCache == NULL) { + docCache = newDocCache(module, doc); + } + ScriptDocCache * dc = dynamic_cast(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 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 - module->paramListString(params); Glib::ustring empty; file_listener outfile; @@ -789,57 +721,15 @@ Script::effect(Inkscape::Extension::Effect *module, Inkscape::UI::View::View *do return; } - gchar *tmpname; - // FIXME: process the GError instead of passing NULL - gint tempfd_in = g_file_open_tmp("ink_ext_XXXXXX", &tmpname, NULL); - if (tempfd_in == -1) { - /* Error, couldn't create temporary filename */ - if (errno == EINVAL) { - /* The last six characters of template were not XXXXXX. Now template is unchanged. */ - perror("Extension::Script: template for filenames is misconfigured.\n"); - exit(-1); - } else if (errno == EEXIST) { - /* Now the contents of template are undefined. */ - perror("Extension::Script: Could not create a unique temporary filename\n"); - return; - } else { - perror("Extension::Script: Unknown error creating temporary filename\n"); - exit(-1); - } - } - - Glib::ustring tempfilename_in = tmpname; - g_free(tmpname); - - - // FIXME: process the GError instead of passing NULL - gint tempfd_out = g_file_open_tmp("ink_ext_XXXXXX", &tmpname, NULL); - if (tempfd_out == -1) { - /* Error, couldn't create temporary filename */ - if (errno == EINVAL) { - /* The last six characters of template were not XXXXXX. Now template is unchanged. */ - perror("Extension::Script: template for filenames is misconfigured.\n"); - exit(-1); - } else if (errno == EEXIST) { - /* Now the contents of template are undefined. */ - perror("Extension::Script: Could not create a unique temporary filename\n"); - return; - } else { - perror("Extension::Script: Unknown error creating temporary filename\n"); - exit(-1); - } + std::string tempfilename_out; + int tempfd_out = 0; + try { + tempfd_out = Inkscape::IO::file_open_tmp(tempfilename_out, "ink_ext_XXXXXX.svg"); + } catch (...) { + /// \todo Popup dialog here + return; } - Glib::ustring tempfilename_out= tmpname; - g_free(tmpname); - - 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); - if (desktop != NULL) { Inkscape::Util::GSListConstIterator selected = sp_desktop_selection(desktop)->itemList(); @@ -853,21 +743,24 @@ Script::effect(Inkscape::Extension::Effect *module, Inkscape::UI::View::View *do } 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(); + SPDocument * mydoc = NULL; - if (data_read > 10) + if (data_read > 10) { mydoc = Inkscape::Extension::open( Inkscape::Extension::db.get(SP_MODULE_KEY_INPUT_SVG), tempfilename_out.c_str()); + } // data_read + + 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.... */ @@ -877,7 +770,10 @@ Script::effect(Inkscape::Extension::Effect *module, Inkscape::UI::View::View *do 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; } @@ -903,12 +799,21 @@ void Script::copy_doc (Inkscape::XML::Node * oldroot, Inkscape::XML::Node * newroot) { std::vector delete_list; + Inkscape::XML::Node * oldroot_namedview = NULL; + for (Inkscape::XML::Node * child = oldroot->firstChild(); child != NULL; child = child->next()) { - if (!strcmp("sodipodi:namedview", child->name())) - continue; - delete_list.push_back(child); + if (!strcmp("sodipodi:namedview", child->name())) { + oldroot_namedview = child; + for (Inkscape::XML::Node * oldroot_namedview_child = child->firstChild(); + oldroot_namedview_child != NULL; + oldroot_namedview_child = oldroot_namedview_child->next()) { + delete_list.push_back(oldroot_namedview_child); + } + } else { + delete_list.push_back(child); + } } for (unsigned int i = 0; i < delete_list.size(); i++) sp_repr_unparent(delete_list[i]); @@ -916,11 +821,22 @@ Script::copy_doc (Inkscape::XML::Node * oldroot, Inkscape::XML::Node * newroot) for (Inkscape::XML::Node * child = newroot->firstChild(); child != NULL; child = child->next()) { - if (!strcmp("sodipodi:namedview", child->name())) - continue; - oldroot->appendChild(child->duplicate(newroot->document())); + if (!strcmp("sodipodi:namedview", child->name())) { + if (oldroot_namedview != NULL) { + 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(oldroot->document())); + } + } + } else { + oldroot->appendChild(child->duplicate(oldroot->document())); + } } + oldroot->setAttribute("width", newroot->attribute("width")); + oldroot->setAttribute("height", newroot->attribute("height")); + /** \todo Restore correct layer */ /** \todo Restore correct selection */ } @@ -930,9 +846,9 @@ Script::copy_doc (Inkscape::XML::Node * oldroot, Inkscape::XML::Node * newroot) \param filename Filename of the stderr file */ void -checkStderr (const Glib::ustring &data, - Gtk::MessageType type, - const Glib::ustring &message) +Script::checkStderr (const Glib::ustring &data, + Gtk::MessageType type, + const Glib::ustring &message) { Gtk::MessageDialog warning(message, false, type, Gtk::BUTTONS_OK, true); warning.set_resizable(true); @@ -962,6 +878,16 @@ checkStderr (const Glib::ustring &data, return; } +bool +Script::cancelProcessing (void) { + _canceled = true; + _main_loop->quit(); + Glib::spawn_close_pid(_pid); + + return true; +} + + /** \brief This is the core of the extension file as it actually does the execution of the extension. \param in_command The command to be executed @@ -990,64 +916,122 @@ checkStderr (const Glib::ustring &data, are closed, and we return to what we were doing. */ int -execute (const std::list &in_command, - const std::list &in_params, - const Glib::ustring &filein, - file_listener &fileout) +Script::execute (const std::list &in_command, + const std::list &in_params, + const Glib::ustring &filein, + file_listener &fileout) { g_return_val_if_fail(in_command.size() > 0, 0); - // printf("Executing: %s\n", in_command); + // printf("Executing\n"); std::vector argv; +/* for (std::list::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::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::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::const_iterator i = argv.begin(); - i != argv.end(); i++) { - std::cout << *i << std::endl; + if (!(filein.empty())) { + argv.push_back(filein); } -*/ - Glib::Pid pid; int stdout_pipe, stderr_pipe; try { - Glib::spawn_async_with_pipes(Glib::get_tmp_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(), - &pid, // Pid + &_pid, // Pid NULL, // STDIN &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::RefPtr main_loop = Glib::MainLoop::create(false); + _main_loop = Glib::MainLoop::create(false); file_listener fileerr; - fileout.init(stdout_pipe, main_loop); - fileerr.init(stderr_pipe, main_loop); + fileout.init(stdout_pipe, _main_loop); + fileerr.init(stderr_pipe, _main_loop); + + _canceled = false; + _main_loop->run(); + + // Ensure all the data is out of the pipe + while (!fileout.isDead()) + fileout.read(Glib::IO_IN); + while (!fileerr.isDead()) + fileerr.read(Glib::IO_IN); - main_loop->run(); + if (_canceled) { + // std::cout << "Script Canceled" << std::endl; + 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."));