diff --git a/src/actions/actions-element-image.cpp b/src/actions/actions-element-image.cpp index bafc060f18eec2436f90092e6c0cd184318bf645..519be07c1bf9152348cd0096c67b1c6abbfc5a0f 100644 --- a/src/actions/actions-element-image.cpp +++ b/src/actions/actions-element-image.cpp @@ -10,21 +10,20 @@ #include "actions-element-image.h" -#include - -#include // Not ! To eventually allow a headless version! -#include // OK, we lied. We pop-up an message dialog if external editor not found and if we have a GUI. +#include // Not ! To eventually allow a headless version! #include +#include // OK, we lied. We pop-up an message dialog if external editor not found and if we have a GUI. +#include #include "inkscape-application.h" #include "inkscape-window.h" #include "message-stack.h" -#include "preferences.h" - -#include "selection.h" // Selection -#include "object/sp-image.h" #include "object/sp-clippath.h" +#include "object/sp-image.h" #include "object/sp-rect.h" +#include "object/uri.h" +#include "preferences.h" +#include "selection.h" #include "ui/tools/select-tool.h" #include "util/format_size.h" @@ -55,7 +54,6 @@ void image_edit(InkscapeApplication *app) for (auto item : selection->items()) { auto image = dynamic_cast(item); if (image) { - Inkscape::XML::Node *node = item->getRepr(); const gchar *href = node->attribute("xlink:href"); if (!href) { @@ -63,24 +61,25 @@ void image_edit(InkscapeApplication *app) continue; } - if (strncmp (href, "data", 4) == 0) { + const gchar *base_path = + document->getDocumentBase() ? document->getDocumentBase() : Glib::get_current_dir().c_str(); + + Inkscape::URI uri = Inkscape::URI(href, Inkscape::URI::from_dirname(base_path)); + + if (uri.hasScheme("data")) { + // data URL scheme, see https://www.ietf.org/rfc/rfc2397.txt std::cerr << "image_edit: cannot edit embedded image" << std::endl; continue; } - // Find filename. - std::string filename = href; - if (strncmp (href, "file", 4) == 0) { - filename = Glib::filename_from_uri(href); + if (uri.getScheme() != nullptr && !uri.hasScheme("file")) { + // any other scheme than 'file' + std::cerr << "image_edit: cannot edit image (scheme '" << uri.getScheme() << "' not supported)" + << std::endl; + continue; } - if (Glib::path_is_absolute(filename)) { - // Do nothing - } else if (document->getDocumentBase()) { - filename = Glib::build_filename(document->getDocumentBase(), filename); - } else { - filename = Glib::build_filename(Glib::get_current_dir(), filename); - } + std::string filename = uri.toNativeFilename(); // Bitmap or SVG? bool is_svg = false; @@ -89,40 +88,29 @@ void image_edit(InkscapeApplication *app) is_svg = true; } - // Get editor. - auto editor = image_get_editor_name(is_svg); - -#ifdef _WIN32 - // Parsing is done according to Unix shell rules, need to enclose editor path by single - // quotes (everything before file extension). - int index = editor.find(".exe"); - if (index < 0) index = editor.find(".bat"); - if (index < 0) index = editor.find(".com"); - if (index < 0) index = editor.length(); - - editor.insert(index, "'"); - editor.insert(0, "'"); -#endif - Glib::ustring command = editor + " '" + filename + "'"; - - GError* error = nullptr; - g_spawn_command_line_async(command.c_str(), &error); - if (error) { - Glib::ustring message = _("Failed to edit external image.\nNote: Path to editor can be set in Preferences dialog."); - Glib::ustring message2 = Glib::ustring::compose(_("System error message: %1"), error->message); + std::string command = + Glib::shell_quote(image_get_editor_name(is_svg)) + " " + Glib::shell_quote(filename.c_str()); + + Glib::ustring message = _("Failed to edit external image.\nNote: Path to editor can be set in " + "Preferences dialog."); + try { + Glib::spawn_command_line_async(command); + } catch (Glib::SpawnError &error) { auto window = app->get_active_window(); if (window) { Gtk::MessageDialog dialog(*window, message, true, Gtk::MESSAGE_WARNING, Gtk::BUTTONS_OK); dialog.property_destroy_with_parent() = true; dialog.set_name("SetEditorDialog"); dialog.set_title(_("External Edit Image:")); - dialog.set_secondary_text(message2); + dialog.set_secondary_text( + Glib::ustring::compose(_("System error message: %1"), error.what().raw())); dialog.run(); } else { std::cerr << "image_edit: " << message.raw() << std::endl; } - g_error_free(error); - error = nullptr; + } catch (Glib::ShellError &error) { + Glib::ustring message2 = Glib::ustring::compose(_("System error message: %1"), error.what().raw()); + std::cerr << "image_edit: " << message.raw() << "\n" << message2.raw() << std::endl; } } }