From d544ed6201b18f53ce9d5df1b3a44cf1cd85f71f Mon Sep 17 00:00:00 2001 From: Tavmjong Bah Date: Wed, 16 Oct 2024 12:08:32 +0200 Subject: [PATCH 01/11] Move choose-file.* and image-save.* to src/ui/dialogs/ from src/helper/ Return Gio::File from choose_file_save() and choose_file_open(). Adapt code for above changes. Restructure choose_file_open() functions to allow directly specifying Gtk::FileFilter list. Fix some implicit capture of 'this' warnings. --- src/extension/prefdialog/parameter-path.cpp | 2 +- src/helper/CMakeLists.txt | 4 - src/ui/CMakeLists.txt | 5 + src/{helper => ui/dialog}/choose-file.cpp | 104 +++++++++++--------- src/{helper => ui/dialog}/choose-file.h | 45 ++++++--- src/ui/dialog/document-resources.cpp | 21 ++-- src/ui/dialog/global-palettes.cpp | 4 +- src/ui/dialog/global-palettes.h | 7 +- src/{helper => ui/dialog}/save-image.cpp | 14 ++- src/{helper => ui/dialog}/save-image.h | 0 src/ui/dialog/swatches.cpp | 8 +- src/ui/widget/image-properties.cpp | 24 ++--- src/ui/widget/preferences-widget.cpp | 61 ++++++------ 13 files changed, 161 insertions(+), 138 deletions(-) rename src/{helper => ui/dialog}/choose-file.cpp (60%) rename src/{helper => ui/dialog}/choose-file.h (56%) rename src/{helper => ui/dialog}/save-image.cpp (77%) rename src/{helper => ui/dialog}/save-image.h (100%) diff --git a/src/extension/prefdialog/parameter-path.cpp b/src/extension/prefdialog/parameter-path.cpp index 58860e5742..bce31f092a 100644 --- a/src/extension/prefdialog/parameter-path.cpp +++ b/src/extension/prefdialog/parameter-path.cpp @@ -37,8 +37,8 @@ #include #include "extension/extension.h" -#include "helper/choose-file.h" #include "preferences.h" +#include "ui/dialog/choose-file.h" #include "ui/pack.h" #include "xml/node.h" diff --git a/src/helper/CMakeLists.txt b/src/helper/CMakeLists.txt index c47a1bf5f7..39207383c8 100644 --- a/src/helper/CMakeLists.txt +++ b/src/helper/CMakeLists.txt @@ -1,7 +1,6 @@ # SPDX-License-Identifier: GPL-2.0-or-later set(helper_SRC - choose-file.cpp geom.cpp geom-nodetype.cpp geom-pathstroke.cpp @@ -10,13 +9,11 @@ set(helper_SRC gettext.cpp pixbuf-ops.cpp png-write.cpp - save-image.cpp stock-items.cpp #units-test.cpp # ------- # Headers - choose-file.h geom-curves.h geom-nodetype.h geom-pathstroke.h @@ -27,7 +24,6 @@ set(helper_SRC mathfns.h pixbuf-ops.h png-write.h - save-image.h stock-items.h ) diff --git a/src/ui/CMakeLists.txt b/src/ui/CMakeLists.txt index 11b01a92a3..fbecd6be2b 100644 --- a/src/ui/CMakeLists.txt +++ b/src/ui/CMakeLists.txt @@ -113,11 +113,13 @@ set(ui_SRC dialog/about.cpp dialog/align-and-distribute.cpp + dialog/attrdialog.cpp dialog/calligraphic-profile-rename.cpp dialog/clonetiler.cpp dialog/color-item.cpp dialog/command-palette.cpp dialog/attrdialog.cpp + dialog/choose-file.cpp dialog/debug.cpp dialog/dialog-base.cpp dialog/dialog-container.cpp @@ -158,6 +160,7 @@ set(ui_SRC dialog/polar-arrange-tab.cpp dialog/print.cpp dialog/prototype.cpp + dialog/save-image.cpp dialog/selectorsdialog.cpp dialog/startup.cpp dialog/styledialog.cpp @@ -329,6 +332,7 @@ set(ui_SRC dialog/align-and-distribute.h dialog/arrange-tab.h dialog/calligraphic-profile-rename.h + dialog/choose-file.h dialog/clonetiler.h dialog/color-item.h dialog/command-palette.h @@ -373,6 +377,7 @@ set(ui_SRC dialog/polar-arrange-tab.h dialog/print.h dialog/prototype.h + dialog/save-image.h dialog/selectorsdialog.h dialog/startup.h dialog/styledialog.h diff --git a/src/helper/choose-file.cpp b/src/ui/dialog/choose-file.cpp similarity index 60% rename from src/helper/choose-file.cpp rename to src/ui/dialog/choose-file.cpp index c338bc0237..72bc0c2c38 100644 --- a/src/helper/choose-file.cpp +++ b/src/ui/dialog/choose-file.cpp @@ -2,6 +2,9 @@ #include "choose-file.h" +#include +#include + #include #include #include @@ -13,6 +16,8 @@ #include #include +#include "preferences.h" + namespace Inkscape { Glib::RefPtr create_file_dialog(Glib::ustring const &title, @@ -54,18 +59,17 @@ using FinishMethod = Glib::RefPtr (Gtk::FileDialog::*) file_dialog.set_initial_folder(Gio::File::create_for_path(current_folder)); bool responded = false; - std::string file_path; + Glib::RefPtr file; (file_dialog.*start)(parent, [&](Glib::RefPtr const &result) { try { responded = true; - auto const file = (file_dialog.*finish)(result); - if (!file) return; - - file_path = file->get_path(); - if (file_path.empty()) return; + file = (file_dialog.*finish)(result); + if (!file) { + return; + } current_folder = file->get_parent()->get_path(); } catch (Gtk::DialogError const &error) { @@ -82,13 +86,13 @@ using FinishMethod = Glib::RefPtr (Gtk::FileDialog::*) main_context->iteration(true); } - return file_path; + return file; } -std::string choose_file_save(Glib::ustring const &title, Gtk::Window *parent, - Glib::ustring const &mime_type, - Glib::ustring const &file_name, - std::string ¤t_folder) +Glib::RefPtr choose_file_save(Glib::ustring const &title, Gtk::Window *parent, + Glib::ustring const &mime_type, + Glib::ustring const &file_name, + std::string ¤t_folder) { if (!parent) return {}; @@ -108,58 +112,64 @@ std::string choose_file_save(Glib::ustring const &title, Gtk::Window *parent, &Gtk::FileDialog::save, &Gtk::FileDialog::save_finish); } -static std::string _choose_file_open(Glib::ustring const &title, Gtk::Window *parent, - std::vector> const &filters, - std::vector const &mime_types, - std::string ¤t_folder) -{ - if (!parent) return {}; +Glib::RefPtr choose_file_open(Glib::ustring const &title, Gtk::Window *parent, + Glib::RefPtr> const &filters_model, + std::string ¤t_folder, + Glib::ustring const &accept) +{ + if (!parent) return Glib::RefPtr(); if (current_folder.empty()) { current_folder = Glib::get_home_dir(); } - auto const file_dialog = create_file_dialog(title, _("Open")); + auto const file_dialog = create_file_dialog(title, accept.empty() ? _("Open") : accept); - auto filters_model = Gio::ListStore::create(); - if (!filters.empty()) { - auto all_supported = Gtk::FileFilter::create(); - all_supported->set_name(_("All Supported Formats")); - if (filters.size() > 1) filters_model->append(all_supported); - - for (auto const &f : filters) { - auto filter = Gtk::FileFilter::create(); - filter->set_name(f.first); - filter->add_pattern(f.second); - all_supported->add_pattern(f.second); - filters_model->append(filter); - } - } - else { - auto filter = Gtk::FileFilter::create(); - for (auto const &t : mime_types) { - filter->add_mime_type(t); - } - filters_model->append(filter); + if (filters_model) { + set_filters(*file_dialog, filters_model); } - set_filters(*file_dialog, filters_model); return run(*file_dialog, *parent, current_folder, &Gtk::FileDialog::open, &Gtk::FileDialog::open_finish); } -std::string choose_file_open(Glib::ustring const &title, Gtk::Window *parent, - std::vector const &mime_types, - std::string ¤t_folder) +Glib::RefPtr choose_file_open(Glib::ustring const &title, Gtk::Window *parent, + std::vector const &mime_types, + std::string ¤t_folder, + Glib::ustring const &accept) { - return _choose_file_open(title, parent, {}, mime_types, current_folder); + auto filters_model = Gio::ListStore::create(); + auto filter = Gtk::FileFilter::create(); + for (auto const &t : mime_types) { + filter->add_mime_type(t); + } + filters_model->append(filter); + + return choose_file_open(title, parent, filters_model, current_folder, accept); } -std::string choose_file_open(Glib::ustring const &title, Gtk::Window *parent, - std::vector> const &filters, - std::string ¤t_folder) +Glib::RefPtr choose_file_open(Glib::ustring const &title, Gtk::Window *parent, + std::vector> const &filters, + std::string ¤t_folder, + Glib::ustring const &accept) { - return _choose_file_open(title, parent, filters, {}, current_folder); + auto filters_model = Gio::ListStore::create(); + + auto all_supported = Gtk::FileFilter::create(); + if (filters.size() > 1) { + all_supported->set_name(_("All Supported Formats")); + filters_model->append(all_supported); + } + + for (auto const &f : filters) { + auto filter = Gtk::FileFilter::create(); + filter->set_name(f.first); + filter->add_pattern(f.second); + filters_model->append(filter); + all_supported->add_pattern(f.second); + } + + return choose_file_open(title, parent, filters_model, current_folder, accept); } } // namespace Inkscape diff --git a/src/helper/choose-file.h b/src/ui/dialog/choose-file.h similarity index 56% rename from src/helper/choose-file.h rename to src/ui/dialog/choose-file.h index 553654de18..f927a10bea 100644 --- a/src/helper/choose-file.h +++ b/src/ui/dialog/choose-file.h @@ -7,13 +7,11 @@ #include #include #include - -namespace Glib { -class ustring; -} // namespace Glib +#include namespace Gio { template class ListStore; +class File; } // namespace Gio namespace Gtk { @@ -27,9 +25,11 @@ namespace Inkscape { /// Create a Gtk::FileDialog with the given title and label for its default/accept button. [[nodiscard]] Glib::RefPtr create_file_dialog(Glib::ustring const &title, Glib::ustring const &accept_label); + /// Set available filters to a given list, & default to its 1st filter (if any). void set_filters(Gtk::FileDialog &file_dialog, Glib::RefPtr> const &filters); + /// Set the available filters & the default filter, to the single filter passed. void set_filter(Gtk::FileDialog &file_dialog, Glib::RefPtr const &filter); @@ -37,28 +37,41 @@ void set_filter(Gtk::FileDialog &file_dialog, Glib::RefPtr cons /// @param mime_type MIME type to use as a file filter in the dialog. /// @param file_name Name of the initial file to show in the dialogʼs text entry. /// @param current_folder Path of initial folder to show, updated to parent of selected file if any -/// @returns name of selected file as local path, or empty if no file selected or not representable +/// @returns Gio::File for selected file. [[nodiscard]] -std::string choose_file_save(Glib::ustring const &title, Gtk::Window *parent, - Glib::ustring const &mime_type, Glib::ustring const &file_name, - std::string& current_folder); +Glib::RefPtr choose_file_save(Glib::ustring const &title, Gtk::Window *parent, + Glib::ustring const &mime_type, Glib::ustring const &file_name, + std::string& current_folder); + +/// Synchronously run a Gtk::FileDialog to open a single file for reading data. +/// @param filters_model For selection of file types to be shown in dialog. +/// @param current_folder Path of initial folder to show, updated to parent of selected file if any. +/// @returns Gio::File for selected file. +[[nodiscard]] +Glib::RefPtr choose_file_open(Glib::ustring const &title, Gtk::Window *parent, + Glib::RefPtr> const &filters_model, + std::string ¤t_folder, + Glib::ustring const &accept={}); /// Synchronously run a Gtk::FileDialog to open a single file for reading data. /// @param mime_type MIME types to offer as file filters in the dialog. /// @param current_folder Path of initial folder to show, updated to parent of selected file if any -/// @returns name of selected file as local path, or empty if no file selected or not representable +/// @returns Gio::File for selected file. [[nodiscard]] -std::string choose_file_open(Glib::ustring const &title, Gtk::Window *parent, - std::vector const &mime_types, - std::string& current_folder); +Glib::RefPtr choose_file_open(Glib::ustring const &title, Gtk::Window *parent, + std::vector const &mime_types, + std::string& current_folder, + Glib::ustring const &accept={}); + /// Synchronously run a Gtk::FileDialog to open a single file for reading data. /// @param filters Vector of pairs of to create file filters to offer in the dialog /// @param current_folder Path of initial folder to show, updated to parent of selected file if any -/// @returns name of selected file as local path, or empty if no file selected or not representable +/// @returns Gio::File for selected file. [[nodiscard]] -std::string choose_file_open(Glib::ustring const &title, Gtk::Window *parent, - std::vector> const &filters, - std::string& current_folder); +Glib::RefPtr choose_file_open(Glib::ustring const &title, Gtk::Window *parent, + std::vector> const &filters, + std::string& current_folder, + Glib::ustring const &accept={}); } // namespace Inkscape diff --git a/src/ui/dialog/document-resources.cpp b/src/ui/dialog/document-resources.cpp index 8d329f8825..c22ac665e2 100644 --- a/src/ui/dialog/document-resources.cpp +++ b/src/ui/dialog/document-resources.cpp @@ -63,8 +63,6 @@ #include "colors/color-set.h" #include "desktop.h" #include "document-undo.h" -#include "helper/choose-file.h" -#include "helper/save-image.h" #include "inkscape.h" #include "object/color-profile.h" #include "object/filters/sp-filter-primitive.h" @@ -86,6 +84,8 @@ #include "selection.h" #include "style.h" #include "ui/builder-utils.h" +#include "ui/dialog/choose-file.h" +#include "ui/dialog/save-image.h" #include "ui/icon-names.h" #include "ui/themes.h" #include "ui/util.h" @@ -180,7 +180,8 @@ bool is_resource_present(std::string const &id, details::Statistics const &stats return get_resource_count(id, stats) > 0; } -std::string choose_file(Glib::ustring title, Gtk::Window* parent, Glib::ustring mime_type, Glib::ustring file_name) { +Glib::RefPtr choose_file(Glib::ustring title, Gtk::Window* parent, + Glib::ustring mime_type, Glib::ustring file_name) { static std::string current_folder; return Inkscape::choose_file_save(title, parent, mime_type, file_name, current_folder); } @@ -212,11 +213,11 @@ void save_gimp_palette(std::string fname, const std::vector& colors, const void extract_colors(Gtk::Window* parent, const std::vector& colors, const char* name) { if (colors.empty() || !parent) return; - auto fname = choose_file(_("Export Color Palette"), parent, "application/color-palette", "color-palette.gpl"); - if (fname.empty()) return; + auto file = choose_file(_("Export Color Palette"), parent, "application/color-palette", "color-palette.gpl"); + if (!file) return; // export palette - save_gimp_palette(fname, colors, name); + save_gimp_palette(file->get_path(), colors, name); } static void delete_object(SPObject* object, Inkscape::Selection* selection) { @@ -368,7 +369,7 @@ DocumentResources::DocumentResources() auto model = Gtk::SortListModel::create(filtered_items, sorter); // model->set_sort_column(g_item_columns.label.index(), Gtk::SortType::ASCENDING); - _item_factory = IconViewItemFactory::create([=](auto& ptr) -> IconViewItemFactory::ItemData { + _item_factory = IconViewItemFactory::create([this](auto& ptr) -> IconViewItemFactory::ItemData { auto rsrc = std::dynamic_pointer_cast(ptr); if (!rsrc) return {}; @@ -412,7 +413,7 @@ DocumentResources::DocumentResources() for (int i = 0; i < cols->get_n_items(); ++i) { auto info_factory = Gtk::SignalListItemFactory::create(); info_factory->signal_setup().connect(set_up_label); - info_factory->signal_bind().connect([=](auto& list_item) { + info_factory->signal_bind().connect([this, i, bind_label](auto& list_item) { auto item = std::dynamic_pointer_cast(list_item->get_item()); if (!item) return; Glib::ustring text; @@ -524,7 +525,7 @@ DocumentResources::DocumentResources() auto pos = paned->get_position(); get_widget(_builder, "spacer").set_size_request(pos); }; - paned->property_position().signal_changed().connect([=](){ move(); }); + paned->property_position().signal_changed().connect([move](){ move(); }); move(); _edit.signal_clicked().connect([this]{ @@ -558,7 +559,7 @@ DocumentResources::DocumentResources() } }); - _search.signal_search_changed().connect([=, this](){ + _search.signal_search_changed().connect([this, refilter_info](){ refilter_info(); _item_filter->refilter(_search.get_text()); }); diff --git a/src/ui/dialog/global-palettes.cpp b/src/ui/dialog/global-palettes.cpp index dd4b5fd5d0..f525c40947 100644 --- a/src/ui/dialog/global-palettes.cpp +++ b/src/ui/dialog/global-palettes.cpp @@ -36,10 +36,10 @@ #include "colors/manager.h" #include "colors/spaces/enum.h" -#include "helper/choose-file.h" #include "colors/spaces/lab.h" #include "io/resource.h" #include "io/sys.h" +#include "ui/dialog/choose-file.h" #include "util/delete-with.h" #include "util-string/ustring-format.h" using Inkscape::Util::delete_with; @@ -416,7 +416,7 @@ const PaletteFileData* GlobalPalettes::find_palette(const Glib::ustring& id) con return p != _access.end() ? p->second : nullptr; } -std::string choose_palette_file(Gtk::Window* window) { +Glib::RefPtr choose_palette_file(Gtk::Window* window) { static std::string current_folder; static std::vector> const filters{ {_("Gimp Color Palette"), "*.gpl"}, diff --git a/src/ui/dialog/global-palettes.h b/src/ui/dialog/global-palettes.h index 017961ff6c..2937153ae1 100644 --- a/src/ui/dialog/global-palettes.h +++ b/src/ui/dialog/global-palettes.h @@ -17,10 +17,15 @@ #include #include #include +#include #include #include "colors/color.h" +namespace Gio { +class File; +} // namespace Gio + namespace Gtk { class Window; } // namespace Gtk @@ -89,7 +94,7 @@ struct PaletteResult { // todo: replace with std::expected when it becomes avail PaletteResult load_palette(std::string const &path); // Show file chooser and select color palette file -std::string choose_palette_file(Gtk::Window* window); +Glib::RefPtr choose_palette_file(Gtk::Window* window); } // namespace Inkscape::UI::Dialog diff --git a/src/helper/save-image.cpp b/src/ui/dialog/save-image.cpp similarity index 77% rename from src/helper/save-image.cpp rename to src/ui/dialog/save-image.cpp index eca667bd19..6e08174bf6 100644 --- a/src/helper/save-image.cpp +++ b/src/ui/dialog/save-image.cpp @@ -1,11 +1,15 @@ // SPDX-License-Identifier: GPL-2.0-or-later #include "save-image.h" -#include + #include + +#include +#include + #include "display/cairo-utils.h" -#include "helper/choose-file.h" #include "object/sp-image.h" +#include "ui/dialog/choose-file.h" namespace Inkscape { @@ -30,11 +34,11 @@ bool extract_image(Gtk::Window* parent, SPImage* image) { if (!image || !image->pixbuf || !parent) return false; std::string current_dir; - auto fname = choose_file_save(_("Extract Image"), parent, "image/png", "image.png", current_dir); - if (fname.empty()) return false; + auto file = choose_file_save(_("Extract Image"), parent, "image/png", "image.png", current_dir); + if (!file) return false; // save image - return save_image(fname, image->pixbuf.get()); + return save_image(file->get_path(), image->pixbuf.get()); } } // namespace Inkscape diff --git a/src/helper/save-image.h b/src/ui/dialog/save-image.h similarity index 100% rename from src/helper/save-image.h rename to src/ui/dialog/save-image.h diff --git a/src/ui/dialog/swatches.cpp b/src/ui/dialog/swatches.cpp index 41d99ec8e1..c9256f4b2f 100644 --- a/src/ui/dialog/swatches.cpp +++ b/src/ui/dialog/swatches.cpp @@ -575,10 +575,10 @@ bool SwatchesPanel::load_swatches() { auto window = dynamic_cast(get_root()); auto file = choose_palette_file(window); auto loaded = false; - if (load_swatches(file)) { + if (load_swatches(file->get_path())) { auto prefs = Preferences::get(); prefs->setString(_prefs_path + "/palette", _loaded_palette.id); - prefs->setString(_prefs_path + "/palette-path", file); + prefs->setString(_prefs_path + "/palette-path", file->get_path()); loaded = true; } return loaded; @@ -586,7 +586,9 @@ bool SwatchesPanel::load_swatches() { bool SwatchesPanel::load_swatches(std::string const &path) { - if (path.empty()) return false; + if (path.empty()) { + return false; + } // load colors auto res = load_palette(path); diff --git a/src/ui/widget/image-properties.cpp b/src/ui/widget/image-properties.cpp index 8bc7818389..71df9f31be 100644 --- a/src/ui/widget/image-properties.cpp +++ b/src/ui/widget/image-properties.cpp @@ -13,6 +13,7 @@ #include #include #include +#include #include #include #include @@ -30,10 +31,10 @@ #include "display/cairo-utils.h" #include "document-undo.h" #include "enums.h" -#include "helper/choose-file.h" -#include "helper/save-image.h" #include "object/sp-image.h" #include "ui/builder-utils.h" +#include "ui/dialog/choose-file.h" +#include "ui/dialog/save-image.h" #include "ui/icon-names.h" #include "ui/pack.h" #include "ui/util.h" @@ -67,20 +68,11 @@ void link_image(Gtk::Window* window, SPImage* image) { "image/png", "image/jpeg", "image/gif", "image/bmp", "image/tiff" }; auto file = choose_file_open(_("Change Image"), window, mime_types, current_folder); - if (file.empty()) return; - - // link image now - // todo: set/calc dpi? - // todo: set color profile? - try { - // convert filename to uri - auto uri = Glib::filename_to_uri(file); - setHrefAttribute(*image->getRepr(), uri); - } - catch (Glib::ConvertError const &e) { - g_warning("Error converting path to URI: %s", e.what()); - setHrefAttribute(*image->getRepr(), file); - } + if (!file) return; + + auto uri = file->get_uri(); + setHrefAttribute(*image->getRepr(), uri); + // SPImage modifies size when href changes; trigger it now before undo concludes // TODO: this needs to be fixed in SPImage image->document->_updateDocument(0); diff --git a/src/ui/widget/preferences-widget.cpp b/src/ui/widget/preferences-widget.cpp index 01f68a4ded..03d2bd78d2 100644 --- a/src/ui/widget/preferences-widget.cpp +++ b/src/ui/widget/preferences-widget.cpp @@ -35,6 +35,7 @@ #include "selection-chemistry.h" #include "include/gtkmm_version.h" #include "io/sys.h" +#include "ui/dialog/choose-file.h" #include "ui/dialog/filedialog.h" #include "ui/icon-loader.h" #include "ui/pack.h" @@ -776,50 +777,44 @@ void PrefEntryFileButtonHBox::onRelatedEntryChangedCallback() } } -static Inkscape::UI::Dialog::FileOpenDialog * selectPrefsFileInstance = nullptr; - void PrefEntryFileButtonHBox::onRelatedButtonClickedCallback() { if (this->get_visible()) { // Only take action if user changed value. // Get the current directory for finding files. - static std::string open_path; - Inkscape::UI::Dialog::get_start_directory(open_path, _prefs_path, true); + static std::string current_folder; + Inkscape::UI::Dialog::get_start_directory(current_folder, _prefs_path, true); + + auto filters = Gio::ListStore::create(); + + // Create a filter to limit options to executables. + // (Only used to select Bitmap and SVG editors.) + auto filter_app = Gtk::FileFilter::create(); + filter_app->set_name(_("Applications")); + filter_app->add_mime_type("application/x-executable"); // Linux (xdg-mime query filetype) + filter_app->add_mime_type("application/x-pie-executable"); // Linux (filetype --mime-type) + filter_app->add_mime_type("application/x-mach-binary"); // MacOS + filter_app->add_mime_type("application/vnd.microsoft.portable-executable"); // Windows + filter_app->add_suffix("exe"); // Windows + filters->append(filter_app); + + // Just in case... + auto filter_all = Gtk::FileFilter::create(); + filter_all->set_name(_("All Files")); + filter_all->add_pattern("*"); + filters->append(filter_all); // Create a dialog. SPDesktop *desktop = SP_ACTIVE_DESKTOP; - if (!selectPrefsFileInstance) { - selectPrefsFileInstance = - Inkscape::UI::Dialog::FileOpenDialog::create( - *desktop->getInkscapeWindow(), - open_path, - Inkscape::UI::Dialog::EXE_TYPES, - _("Select a bitmap editor")).release(); - } - - // Show the dialog. - bool const success = selectPrefsFileInstance->show(); - - if (!success) { - return; - } - - // User selected something, get file. - auto file = selectPrefsFileInstance->getFile(); - if (!file) { - return; - } + auto window = desktop->getInkscapeWindow(); + auto file = choose_file_open(_("Select an editor"), window, filters, current_folder, _("Select")); - auto path = file->get_path(); - if (!path.empty()) { - open_path = path;; + if (!file) { + return; // Cancel } - if (!open_path.empty()) { - Inkscape::Preferences *prefs = Inkscape::Preferences::get(); - prefs->setString(_prefs_path, open_path); - } - + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + prefs->setString(_prefs_path, file->get_path()); relatedEntry->set_text(file->get_parse_name()); } } -- GitLab From a1ddb65bc19ea57baed4df27227dc729e726969d Mon Sep 17 00:00:00 2001 From: Tavmjong Bah Date: Wed, 16 Oct 2024 12:36:05 +0200 Subject: [PATCH 02/11] Move get_start_directory() into a new utility file. Rewrite get_start_directory() to use Glib function to find user's document directory (rather than custom Windows code). Fallback to user's document directory on all platforms, rather than just on Windows. (Fallback only enabled for file opening and specifying bitmap/svg editors.) --- src/file.cpp | 1 + src/ui/CMakeLists.txt | 2 + src/ui/dialog/choose-file-utils.cpp | 55 +++++++++++++++++++++++++ src/ui/dialog/choose-file-utils.h | 37 +++++++++++++++++ src/ui/dialog/document-properties.cpp | 12 +++--- src/ui/dialog/filedialog.cpp | 52 ----------------------- src/ui/dialog/filedialog.h | 5 --- src/ui/dialog/filter-effects-dialog.cpp | 1 + src/ui/dialog/startup.cpp | 1 + src/ui/widget/preferences-widget.cpp | 1 + 10 files changed, 105 insertions(+), 62 deletions(-) create mode 100644 src/ui/dialog/choose-file-utils.cpp create mode 100644 src/ui/dialog/choose-file-utils.h diff --git a/src/file.cpp b/src/file.cpp index d399bc39da..f1e4a21456 100644 --- a/src/file.cpp +++ b/src/file.cpp @@ -65,6 +65,7 @@ #include "selection.h" #include "style.h" #include "svg/svg.h" // for sp_svg_transform_write, used in sp_import_document +#include "ui/dialog/choose-file-utils.h" #include "ui/dialog/filedialog.h" #include "ui/icon-names.h" #include "ui/interface.h" diff --git a/src/ui/CMakeLists.txt b/src/ui/CMakeLists.txt index fbecd6be2b..7ab02e635a 100644 --- a/src/ui/CMakeLists.txt +++ b/src/ui/CMakeLists.txt @@ -121,6 +121,7 @@ set(ui_SRC dialog/attrdialog.cpp dialog/choose-file.cpp dialog/debug.cpp + dialog/choose-file-utils.cpp dialog/dialog-base.cpp dialog/dialog-container.cpp dialog/dialog-data.cpp @@ -333,6 +334,7 @@ set(ui_SRC dialog/arrange-tab.h dialog/calligraphic-profile-rename.h dialog/choose-file.h + dialog/choose-file-utils.h dialog/clonetiler.h dialog/color-item.h dialog/command-palette.h diff --git a/src/ui/dialog/choose-file-utils.cpp b/src/ui/dialog/choose-file-utils.cpp new file mode 100644 index 0000000000..6833185d6c --- /dev/null +++ b/src/ui/dialog/choose-file-utils.cpp @@ -0,0 +1,55 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "choose-file-utils.h" + +#include + +#include // Glib::FileTest +#include // Glib::get_home_dir(), etc. + +#include "preferences.h" + +#include "extension/db.h" +#include "extension/input.h" + +namespace Inkscape::UI::Dialog { + +// TODO: Should we always try to use document directory if no path in preferences? +void get_start_directory(std::string &start_path, Glib::ustring const &prefs_path, bool try_document_dir) +{ + // Get the current directory for finding files. + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + std::string attr = prefs->getString(prefs_path); // Glib::ustring -> std::string + if (!attr.empty()) { + start_path = attr; + } + + // Test if the path directory exists. + if (!Glib::file_test(start_path, Glib::FileTest::EXISTS)) { + std::cerr << "get_start_directory: directory does not exist: " << start_path << std::endl; + start_path = ""; + } + + // If no start path, try document directory. + if (start_path.empty() && try_document_dir) { + start_path = Glib::get_user_special_dir(Glib::UserDirectory::DOCUMENTS); + } + + // If no start path, default to home directory. + if (start_path.empty()) { + start_path = Glib::get_home_dir(); + } +} + +} // namespace Inkscape::UI::Dialog + +/* + Local Variables: + mode:c++ + c-file-style:"stroustrup" + c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) + indent-tabs-mode:nil + fill-column:99 + End: +*/ +// vim:filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99: diff --git a/src/ui/dialog/choose-file-utils.h b/src/ui/dialog/choose-file-utils.h new file mode 100644 index 0000000000..532f5b3749 --- /dev/null +++ b/src/ui/dialog/choose-file-utils.h @@ -0,0 +1,37 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + +#ifndef SEEN_CHOOSE_FILE_FILTER_H +#define SEEN_CHOOSE_FILE_FILTER_H + +#include +#include +#include +#include + +namespace Glib { +class ustring; +} + +namespace Gtk { +class FileFilter; +} // namespace Gtk + +namespace Inkscape::UI::Dialog { + +/// Find the start directory for a file dialog. +void get_start_directory(std::string &start_path, Glib::ustring const &prefs_path, bool try_document_dir = false); + +} // namespace Inkscape::UI::Dialog + +#endif // SEEN_CHOOSE_FILE_FILTER_H + +/* + Local Variables: + mode:c++ + c-file-style:"stroustrup" + c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) + indent-tabs-mode:nil + fill-column:99 + End: +*/ +// vim:filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99: diff --git a/src/ui/dialog/document-properties.cpp b/src/ui/dialog/document-properties.cpp index 5bf3cdaf72..4f46a0ef28 100644 --- a/src/ui/dialog/document-properties.cpp +++ b/src/ui/dialog/document-properties.cpp @@ -24,6 +24,12 @@ #include #include #include +#include +#include +#include +#include +#include + #include #include #include @@ -41,11 +47,6 @@ #include #include #include -#include -#include -#include -#include -#include #include #include #include @@ -75,6 +76,7 @@ #include "ui/pack.h" #include "ui/popup-menu.h" #include "ui/util.h" +#include "ui/dialog/choose-file-utils.h" #include "ui/widget/alignment-selector.h" #include "ui/widget/entity-entry.h" #include "ui/widget/labelled.h" diff --git a/src/ui/dialog/filedialog.cpp b/src/ui/dialog/filedialog.cpp index 22faa715ab..6daa414a1c 100644 --- a/src/ui/dialog/filedialog.cpp +++ b/src/ui/dialog/filedialog.cpp @@ -58,58 +58,6 @@ bool hasSuffix(const Glib::ustring &str, const Glib::ustring &ext) return true; } -// start_path is usually a static string. -// try_document_dir only used by WIN32. -void get_start_directory(std::string &start_path, Glib::ustring const &prefs_path, bool try_document_dir) -{ - // Get the current directory for finding files. - Inkscape::Preferences *prefs = Inkscape::Preferences::get(); - std::string attr = prefs->getString(prefs_path); // Glib::ustring -> std::string - if (!attr.empty()) { - start_path = attr; - } - - // Test if the path directory exists. - if (!Glib::file_test(start_path, Glib::FileTest::EXISTS)) { - start_path = ""; - } - -#ifdef _WIN32 - // If no start path, default to our win32 documents folder. - if (start_path.empty() && try_document_dir) { - - // The path to the My Documents folder is read from the - // value "HKEY_CURRENT_USER\Software\Windows\CurrentVersion\Explorer\Shell Folders\Personal" - HKEY key = NULL; - if (RegOpenKeyExA(HKEY_CURRENT_USER, - "Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Shell Folders", - 0, KEY_QUERY_VALUE, &key) == ERROR_SUCCESS) - { - WCHAR utf16path[_MAX_PATH]; - DWORD value_type; - DWORD data_size = sizeof(utf16path); - if(RegQueryValueExW(key, L"Personal", NULL, &value_type, - (BYTE*)utf16path, &data_size) == ERROR_SUCCESS) - { - g_assert(value_type == REG_SZ); - gchar *utf8path = g_utf16_to_utf8( - (const gunichar2*)utf16path, -1, NULL, NULL, NULL); - if (utf8path) { - start_path = Glib::ustring(utf8path); // Glib::ustring -> std::string - g_free(utf8path); - } - } - } - } -#endif - - // If no start path, default to our home directory. - if (start_path.empty()) { - start_path = Glib::get_home_dir(); - start_path.append(G_DIR_SEPARATOR_S); - } -} - bool isValidImageFile(const Glib::ustring &fileName) { std::vectorformats = Gdk::Pixbuf::get_formats(); // Returns Glib::ustrings! diff --git a/src/ui/dialog/filedialog.h b/src/ui/dialog/filedialog.h index 67c37864a4..536d169d1f 100644 --- a/src/ui/dialog/filedialog.h +++ b/src/ui/dialog/filedialog.h @@ -74,11 +74,6 @@ enum FileDialogSelectionType */ bool hasSuffix(const Glib::ustring &str, const Glib::ustring &ext); -/** - * Set initial directory for dialog given a preference path. - */ -void get_start_directory(std::string &start_path, Glib::ustring const &prefs_path, bool try_document_dir = false); - /** * Return true if the image is loadable by Gdk, else false. * Only user is svg-preview.cpp which is disappearing, don't worry about string type. diff --git a/src/ui/dialog/filter-effects-dialog.cpp b/src/ui/dialog/filter-effects-dialog.cpp index e1c8cd014e..4a54f039d8 100644 --- a/src/ui/dialog/filter-effects-dialog.cpp +++ b/src/ui/dialog/filter-effects-dialog.cpp @@ -83,6 +83,7 @@ #include "ui/builder-utils.h" #include "ui/column-menu-builder.h" #include "ui/controller.h" +#include "ui/dialog/choose-file-utils.h" #include "ui/dialog/filedialog.h" #include "ui/icon-names.h" #include "ui/pack.h" diff --git a/src/ui/dialog/startup.cpp b/src/ui/dialog/startup.cpp index 10708bea84..4ed4f9e7d6 100644 --- a/src/ui/dialog/startup.cpp +++ b/src/ui/dialog/startup.cpp @@ -43,6 +43,7 @@ #include "preferences.h" #include "ui/builder-utils.h" #include "ui/controller.h" +#include "ui/dialog/choose-file-utils.h" #include "ui/dialog/filedialog.h" #include "ui/shortcuts.h" #include "ui/themes.h" diff --git a/src/ui/widget/preferences-widget.cpp b/src/ui/widget/preferences-widget.cpp index 03d2bd78d2..00e06323b0 100644 --- a/src/ui/widget/preferences-widget.cpp +++ b/src/ui/widget/preferences-widget.cpp @@ -36,6 +36,7 @@ #include "include/gtkmm_version.h" #include "io/sys.h" #include "ui/dialog/choose-file.h" +#include "ui/dialog/choose-file-utils.h" #include "ui/dialog/filedialog.h" #include "ui/icon-loader.h" #include "ui/pack.h" -- GitLab From f1d1d3f9cc67805ac48d3b5c57efed2934ccf782 Mon Sep 17 00:00:00 2001 From: Tavmjong Bah Date: Wed, 16 Oct 2024 16:50:03 +0200 Subject: [PATCH 03/11] Change some dialogs (Shortcuts, Startup, FilterEffects, DocumentProperties) to use routines from src/ui/dialog/choose-file.*. Add function to create list of file filters for image files to src/ui/dialog/choose-file-utils.*. --- po/POTFILES.src.in | 5 +- src/ui/dialog/choose-file-utils.cpp | 80 +++++++++++++++++++++++++ src/ui/dialog/choose-file-utils.h | 8 +++ src/ui/dialog/document-properties.cpp | 43 ++++--------- src/ui/dialog/filter-effects-dialog.cpp | 37 +++--------- src/ui/dialog/startup.cpp | 20 ++++--- src/ui/shortcuts.cpp | 56 ++++++++--------- 7 files changed, 149 insertions(+), 100 deletions(-) diff --git a/po/POTFILES.src.in b/po/POTFILES.src.in index 539da21564..23f0cf645a 100644 --- a/po/POTFILES.src.in +++ b/po/POTFILES.src.in @@ -143,10 +143,8 @@ ${_build_dir}/share/templates/templates.h ../src/filter-enums.cpp ../src/gradient-chemistry.cpp ../src/gradient-drag.cpp -../src/helper/choose-file.cpp ../src/helper/gettext.cpp ../src/helper/gettext.h -../src/helper/save-image.cpp ../src/inkscape-application.cpp ../src/inkscape.cpp ../src/inkview-application.cpp @@ -278,6 +276,8 @@ ${_build_dir}/share/templates/templates.h ../src/ui/desktop/menubar.cpp ../src/ui/dialog/attrdialog.cpp ../src/ui/dialog/calligraphic-profile-rename.cpp +../src/ui/dialog/choose-file.cpp +../src/ui/dialog/choose-file-utils.cpp ../src/ui/dialog/clonetiler.cpp ../src/ui/dialog/color-item.cpp ../src/ui/dialog/command-palette.cpp @@ -317,6 +317,7 @@ ${_build_dir}/share/templates/templates.h ../src/ui/dialog/paint-servers.cpp ../src/ui/dialog/polar-arrange-tab.cpp ../src/ui/dialog/print.cpp +../src/ui/dialog/save-image.cpp ../src/ui/dialog/save-template-dialog.cpp ../src/ui/dialog/save-template-dialog.h ../src/ui/dialog/selectorsdialog.cpp diff --git a/src/ui/dialog/choose-file-utils.cpp b/src/ui/dialog/choose-file-utils.cpp index 6833185d6c..ceaccb943b 100644 --- a/src/ui/dialog/choose-file-utils.cpp +++ b/src/ui/dialog/choose-file-utils.cpp @@ -4,8 +4,11 @@ #include +#include #include // Glib::FileTest +#include #include // Glib::get_home_dir(), etc. +#include #include "preferences.h" @@ -41,6 +44,83 @@ void get_start_directory(std::string &start_path, Glib::ustring const &prefs_pat } } +Glib::RefPtr> +create_open_filters() { + + auto filters = Gio::ListStore::create(); + + auto allfiles = Gtk::FileFilter::create(); + allfiles->set_name(_("All Files")); + allfiles->add_pattern("*"); + filters->append(allfiles); + + auto inkscape = Gtk::FileFilter::create(); + inkscape->set_name(_("All Inkscape Files")); + filters->append(inkscape); + + auto images = Gtk::FileFilter::create(); + images->set_name(_("Images")); + filters->append(images); + + auto bitmaps = Gtk::FileFilter::create(); + bitmaps->set_name(_("Bitmaps")); + filters->append(bitmaps); + + auto vectors = Gtk::FileFilter::create(); + vectors->set_name(_("Vectors")); + filters->append(vectors); + + // Patterns added dynamically below based on which files are supported by input extensions. + Inkscape::Extension::DB::InputList extension_list; + Inkscape::Extension::db.get_input_list(extension_list); + + for (auto imod : extension_list) { + + gchar const * extension = imod->get_extension(); + if (extension[0]) { + extension = extension + 1; // extension begins with '.', we need it without! + } + + // TODO: Evaluate add_mime_type() instead of add_suffix(). This might allow opening + // files with wrong extension. + + // Add filter for this extension. + auto filter = Gtk::FileFilter::create(); + filter->set_name(imod->get_filetypename(true)); + filter->add_suffix(extension); // Both upper and lower cases. + filters->append(filter); + + inkscape->add_suffix(extension); + + if (strncmp("image", imod->get_mimetype(), 5) == 0) { + images->add_suffix(extension); + } + + // I don't know of any other way to define "bitmap" formats other than by listing them + // clang-format off + if (strncmp("image/png", imod->get_mimetype(), 9) == 0 || + strncmp("image/jpeg", imod->get_mimetype(), 10) == 0 || + strncmp("image/gif", imod->get_mimetype(), 9) == 0 || + strncmp("image/x-icon", imod->get_mimetype(), 12) == 0 || + strncmp("image/x-navi-animation", imod->get_mimetype(), 22) == 0 || + strncmp("image/x-cmu-raster", imod->get_mimetype(), 18) == 0 || + strncmp("image/x-xpixmap", imod->get_mimetype(), 15) == 0 || + strncmp("image/bmp", imod->get_mimetype(), 9) == 0 || + strncmp("image/vnd.wap.wbmp", imod->get_mimetype(), 18) == 0 || + strncmp("image/tiff", imod->get_mimetype(), 10) == 0 || + strncmp("image/x-xbitmap", imod->get_mimetype(), 15) == 0 || + strncmp("image/x-tga", imod->get_mimetype(), 11) == 0 || + strncmp("image/x-pcx", imod->get_mimetype(), 11) == 0) { + bitmaps->add_suffix(extension); + } else { + vectors->add_suffix(extension); + } + // clang-format on + } // Loop over extension_list + + return filters; +} + } // namespace Inkscape::UI::Dialog /* diff --git a/src/ui/dialog/choose-file-utils.h b/src/ui/dialog/choose-file-utils.h index 532f5b3749..2c44492fde 100644 --- a/src/ui/dialog/choose-file-utils.h +++ b/src/ui/dialog/choose-file-utils.h @@ -8,6 +8,10 @@ #include #include +namespace Gio { +template class ListStore; +} // namespace Gio + namespace Glib { class ustring; } @@ -21,6 +25,10 @@ namespace Inkscape::UI::Dialog { /// Find the start directory for a file dialog. void get_start_directory(std::string &start_path, Glib::ustring const &prefs_path, bool try_document_dir = false); +/// Create a Gtk::FileFilter for all image file types. +[[nodiscard]] Glib::RefPtr> create_open_filters(); + + } // namespace Inkscape::UI::Dialog #endif // SEEN_CHOOSE_FILE_FILTER_H diff --git a/src/ui/dialog/document-properties.cpp b/src/ui/dialog/document-properties.cpp index 4f46a0ef28..7d75af9a0a 100644 --- a/src/ui/dialog/document-properties.cpp +++ b/src/ui/dialog/document-properties.cpp @@ -70,7 +70,7 @@ #include "object/sp-root.h" #include "object/sp-script.h" #include "streq.h" -#include "ui/dialog/filedialog.h" +#include "ui/dialog/choose-file.h" #include "ui/icon-loader.h" #include "ui/icon-names.h" #include "ui/pack.h" @@ -1124,8 +1124,6 @@ void DocumentProperties::addExternalScript(){ } } -static Inkscape::UI::Dialog::FileOpenDialog * selectPrefsFileInstance = nullptr; - void DocumentProperties::browseExternalScript() { // Get the current directory for finding files. @@ -1133,39 +1131,22 @@ void DocumentProperties::browseExternalScript() { Inkscape::UI::Dialog::get_start_directory(open_path, _prefs_path); // Create a dialog. - SPDesktop *desktop = getDesktop(); - if (desktop && !selectPrefsFileInstance) { - selectPrefsFileInstance = - Inkscape::UI::Dialog::FileOpenDialog::create( - *desktop->getInkscapeWindow(), - open_path, - Inkscape::UI::Dialog::CUSTOM_TYPE, - _("Select a script to load")).release(); - selectPrefsFileInstance->addFilterMenu(_("JavaScript Files"), "*.js"); - } - - // Show the dialog. - bool const success = selectPrefsFileInstance->show(); + static std::vector> const filters { + {_("JavaScript Files"), "*.js"} + }; - if (!success) { - return; - } + auto window = getDesktop()->getInkscapeWindow(); + auto file = choose_file_open(_("Select a script to load"), + window, + filters, + open_path); - // User selected something, get file. - auto file = selectPrefsFileInstance->getFile(); if (!file) { - return; + return; // Cancel } - auto path = file->get_path(); - if (!path.empty()) { - open_path = path;; - } - - if (!open_path.empty()) { - Inkscape::Preferences *prefs = Inkscape::Preferences::get(); - prefs->setString(_prefs_path, open_path); - } + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + prefs->setString(_prefs_path, open_path); _script_entry.set_text(file->get_parse_name()); } diff --git a/src/ui/dialog/filter-effects-dialog.cpp b/src/ui/dialog/filter-effects-dialog.cpp index 4a54f039d8..60e72f6276 100644 --- a/src/ui/dialog/filter-effects-dialog.cpp +++ b/src/ui/dialog/filter-effects-dialog.cpp @@ -83,8 +83,8 @@ #include "ui/builder-utils.h" #include "ui/column-menu-builder.h" #include "ui/controller.h" +#include "ui/dialog/choose-file.h" #include "ui/dialog/choose-file-utils.h" -#include "ui/dialog/filedialog.h" #include "ui/icon-names.h" #include "ui/pack.h" #include "ui/util.h" @@ -574,8 +574,6 @@ private: Gtk::Label _label; }; -static Inkscape::UI::Dialog::FileOpenDialog * selectFeImageFileInstance = nullptr; - //Displays a chooser for feImage input //It may be a filename or the id for an SVG Element //described in xlink:href syntax @@ -641,38 +639,17 @@ private: std::string open_path; get_start_directory(open_path, "/dialogs/open/path"); - // Create a dialog if we don't already have one. - if (!selectFeImageFileInstance) { - selectFeImageFileInstance = - Inkscape::UI::Dialog::FileOpenDialog::create( - *_dialog.getDesktop()->getInkscapeWindow(), - open_path, - Inkscape::UI::Dialog::SVG_TYPES, /* TODO: any image, not just svg */ - (char const *)_("Select an image to be used as input.")).release(); - } - - // Show the dialog. - bool const success = selectFeImageFileInstance->show(); - if (!success) { - return; - } + // Create a dialog. + auto window = _dialog.getDesktop()->getInkscapeWindow(); + auto filters = create_open_filters(); + auto file = choose_file_open(_("Select an image to be used as input."), window, filters, open_path); - // User selected something. Get name and type. - auto file = selectFeImageFileInstance->getFile(); if (!file) { - return; + return; // Cancel } - auto path = selectFeImageFileInstance->getCurrentDirectory(); - if (!path) { - return; - } - - open_path = path->get_path(); - open_path.append(G_DIR_SEPARATOR_S); - Inkscape::Preferences *prefs = Inkscape::Preferences::get(); - prefs->setString("/dialogs/open/path", open_path); + prefs->setString("/dialogs/open/path", file->get_path()); _entry.set_text(file->get_parse_name()); } diff --git a/src/ui/dialog/startup.cpp b/src/ui/dialog/startup.cpp index 4ed4f9e7d6..1c12761f73 100644 --- a/src/ui/dialog/startup.cpp +++ b/src/ui/dialog/startup.cpp @@ -22,6 +22,7 @@ #include #include #include +#include #include #include #include @@ -43,8 +44,8 @@ #include "preferences.h" #include "ui/builder-utils.h" #include "ui/controller.h" +#include "ui/dialog/choose-file.h" #include "ui/dialog/choose-file-utils.h" -#include "ui/dialog/filedialog.h" #include "ui/shortcuts.h" #include "ui/themes.h" #include "ui/util.h" @@ -403,17 +404,18 @@ StartScreen::load_document() std::string open_path; get_start_directory(open_path, "/dialogs/open/path"); - auto browser = Inkscape::UI::Dialog::FileOpenDialog::create( - *this, open_path, Inkscape::UI::Dialog::SVG_TYPES, _("Open a different file")); - browser->setSelectMultiple(false); // We can only handle one document via start up screen! + std::string current_folder; + get_start_directory(current_folder, "/dialogs/open/path"); - if (browser->show()) { - auto prefs = Inkscape::Preferences::get(); - prefs->setString("/dialogs/open/path", Glib::filename_to_utf8(browser->getCurrentDirectory()->get_path())); - file = browser->getFile(); - } else { + auto filters = create_open_filters(); + file = choose_file_open(_("Open a different file"), this, filters, current_folder); + + if (!file) { return; // Cancel } + + auto prefs = Inkscape::Preferences::get(); + prefs->setString("/dialogs/open/path", current_folder); } // Now we have file, open document. diff --git a/src/ui/shortcuts.cpp b/src/ui/shortcuts.cpp index 2dfe345b96..ad832f4288 100644 --- a/src/ui/shortcuts.cpp +++ b/src/ui/shortcuts.cpp @@ -38,7 +38,7 @@ #include "io/sys.h" #include "ui/modifiers.h" #include "ui/tools/tool-base.h" // For latin keyval -#include "ui/dialog/filedialog.h" // Importing/exporting files. +#include "ui/dialog/choose-file.h" // Importing/exporting shortcut files. #include "ui/util.h" #include "ui/widget/events/canvas-event.h" #include "xml/simple-document.h" @@ -599,7 +599,7 @@ Shortcuts::get_file_names() bool Shortcuts::import_shortcuts() { // Users key directory. - auto const &directory = get_path_string(USER, KEYS, {}); + auto directory = get_path_string(USER, KEYS, {}); // Create and show the dialog Gtk::Window* window = app->get_active_window(); @@ -607,19 +607,20 @@ Shortcuts::import_shortcuts() { return false; } - auto const importFileDialog = std::unique_ptr{ - UI::Dialog::FileOpenDialog::create(*window, directory, Inkscape::UI::Dialog::CUSTOM_TYPE, - _("Select a file to import"))}; - importFileDialog->addFilterMenu(_("Inkscape shortcuts (*.xml)"), "*.xml"); - bool const success = importFileDialog->show(); + static std::vector> const filters { + {_("Inkscape shortcuts (*.xml)"), "*.xml"} + }; - if (!success) { - return false; + auto file = choose_file_open(_("Select a file to import"), + window, + filters, + directory); + if (!file) { + return false; // Cancel } - // Get file and read. - auto file_read = importFileDialog->getFile(); - if (!_read(file_read, true)) { + // Read + if (!_read(file, true)) { std::cerr << "Shortcuts::import_shortcuts: Failed to read file!" << std::endl; return false; } @@ -631,7 +632,7 @@ Shortcuts::import_shortcuts() { bool Shortcuts::export_shortcuts() { // Users key directory. - auto const &directory = get_path_string(USER, KEYS, {}); + auto directory = get_path_string(USER, KEYS, {}); // Create and show the dialog Gtk::Window* window = app->get_active_window(); @@ -639,22 +640,21 @@ Shortcuts::export_shortcuts() { return false; } - auto const saveFileDialog = std::unique_ptr{ - UI::Dialog::FileSaveDialog::create(*window, directory, Inkscape::UI::Dialog::CUSTOM_TYPE, - _("Select a filename for export"), - {}, {}, Inkscape::Extension::FILE_SAVE_METHOD_SAVE_AS)}; - saveFileDialog->addFilterMenu(_("Inkscape shortcuts (*.xml)"), "*.xml"); - saveFileDialog->setCurrentName("shortcuts.xml"); - bool success = saveFileDialog->show(); - - // Get file name and write. - if (success) { - auto file = saveFileDialog->getFile(); - success = _write(file, User); - if (!success) { - std::cerr << "Shortcuts::export_shortcuts: Failed to save file!" << std::endl; - } + auto file = choose_file_save(_("Select a filename for export"), + window, + "text/xml", // Mime type + "shortcuts.xml", // Initial filename + directory); // Initial directory + + if (!file) { + return false; // Cancel } + + auto success = _write(file, User); + if (!success) { + std::cerr << "Shortcuts::export_shortcuts: Failed to save file!" << std::endl; + } + return success; }; -- GitLab From 9fa00b8f88b1674064c627c32fb81eec63d701dc Mon Sep 17 00:00:00 2001 From: Tavmjong Bah Date: Wed, 16 Oct 2024 21:19:53 +0200 Subject: [PATCH 04/11] Add choose_file_open_images() to handle opening multiple files at once (using Gtk::FileDialog). Convert document_open() and document_import() to use new function. --- src/actions/actions-file-window.cpp | 14 ++++- src/file.cpp | 96 +---------------------------- src/file.h | 12 +--- src/ui/dialog/choose-file.cpp | 53 +++++++++++++++- src/ui/dialog/choose-file.h | 9 +++ 5 files changed, 77 insertions(+), 107 deletions(-) diff --git a/src/actions/actions-file-window.cpp b/src/actions/actions-file-window.cpp index ea22579cf5..11ee0727e9 100644 --- a/src/actions/actions-file-window.cpp +++ b/src/actions/actions-file-window.cpp @@ -23,6 +23,7 @@ #include "desktop.h" #include "file.h" #include "preferences.h" +#include "ui/dialog/choose-file.h" #include "ui/dialog/save-template-dialog.h" #include "ui/dialog/new-from-template.h" @@ -44,7 +45,11 @@ void document_open(InkscapeWindow* win) { // Open File Dialog - sp_file_open_dialog(*win, nullptr, nullptr); + auto files = Inkscape::choose_file_open_images(_("Select file(s) to open"), win, "/dialog/open/path", _("Open")); + auto *app = InkscapeApplication::instance(); + for (auto file : files) { + app->create_window(file); + } } void @@ -84,7 +89,12 @@ document_save_template(InkscapeWindow* win) void document_import(InkscapeWindow* win) { - sp_file_import(*win); + // Import File Dialog + auto files = Inkscape::choose_file_open_images(_("Select file(s) to import"), win, "/dialog/import/path", _("Import")); + auto document = win->get_document(); // Target document. + for (auto file : files) { + file_import(document, file->get_path(), nullptr); + } } void diff --git a/src/file.cpp b/src/file.cpp index f1e4a21456..6534cc04f6 100644 --- a/src/file.cpp +++ b/src/file.cpp @@ -154,53 +154,6 @@ void sp_file_revert_dialog() } } -/** - * Display an file Open selector. Open a document if OK is pressed. - * Can select single or multiple files for opening. - */ -void -sp_file_open_dialog(Gtk::Window &parentWindow, gpointer /*object*/, gpointer /*data*/) -{ - // Get the current directory for finding files. - static std::string open_path; - Inkscape::UI::Dialog::get_start_directory(open_path, "/dialogs/open/path", true); - - // Create a dialog. - auto openDialogInstance = Inkscape::UI::Dialog::FileOpenDialog::create( - parentWindow, - open_path, - Inkscape::UI::Dialog::SVG_TYPES, - _("Select file to open")); - - // Show the dialog. - bool const success = openDialogInstance->show(); - - // Save the folder the user selected for later. - open_path = openDialogInstance->getCurrentDirectory()->get_path(); - - if (!success) { - return; - } - - // Open selected files. - auto *app = InkscapeApplication::instance(); - auto files = openDialogInstance->getFiles(); - for (int i = 0; i < files->get_n_items(); i++) { - auto file = files->get_typed_object(i); - app->create_window(file); - } - - // Save directory to preferences (if only one file selected as we could have files from - // multiple directories). - if (files->get_n_items() == 1) { - open_path = Glib::path_get_dirname(files->get_typed_object(0)->get_path()); - open_path.append(G_DIR_SEPARATOR_S); - Inkscape::Preferences *prefs = Inkscape::Preferences::get(); - prefs->setString("/dialogs/open/path", open_path); - } - - return; -} /*###################### ## V A C U U M @@ -800,7 +753,8 @@ void sp_import_document(SPDesktop *desktop, SPDocument *clipdoc, bool in_place, } /** - * Import a resource. Called by sp_file_import() (Drag and Drop) + * Import a resource. Called by document_import() and Drag and Drop. + * The only place 'key' is used non-null is in drag-and-drop of a GDK_TYPE_TEXTURE. */ SPObject * file_import(SPDocument *in_doc, const std::string &path, Inkscape::Extension::Extension *key) @@ -997,52 +951,6 @@ void file_import_pages(SPDocument *this_doc, SPDocument *that_doc) set.applyAffine(tr, true, false, true); } -/** - * Display an Open dialog, import a resource if OK pressed. - */ -void -sp_file_import(Gtk::Window &parentWindow) -{ - SPDocument *doc = SP_ACTIVE_DOCUMENT; - if (!doc) { - return; - } - - static std::string import_path; - Inkscape::UI::Dialog::get_start_directory(import_path, "/dialogs/import/path"); - - // Create new dialog (don't use an old one, because parentWindow has probably changed) - auto importDialogInstance = - Inkscape::UI::Dialog::FileOpenDialog::create( - parentWindow, - import_path, - Inkscape::UI::Dialog::IMPORT_TYPES, - (char const *)_("Select file to import")); - - bool success = importDialogInstance->show(); - if (!success) { - return; - } - - auto files = importDialogInstance->getFiles(); - auto extension = importDialogInstance->getExtension(); - for (int i = 0; i < files->get_n_items(); i++) { - auto file = files->get_typed_object(i); - file_import(doc, file->get_path(), extension); - } - - // Save directory to preferences (if only one file selected as we could have files from - // multiple directories). - if (files->get_n_items() == 1) { - import_path = Glib::path_get_dirname(files->get_typed_object(0)->get_path()); - import_path.append(G_DIR_SEPARATOR_S); - Inkscape::Preferences *prefs = Inkscape::Preferences::get(); - prefs->setString("/dialogs/import/path", import_path); - } - - return; -} - /*###################### ## P R I N T ######################*/ diff --git a/src/file.h b/src/file.h index 79a4ba7b5f..980d240d7d 100644 --- a/src/file.h +++ b/src/file.h @@ -61,11 +61,7 @@ void sp_file_exit (); ## O P E N ######################*/ -/** - * Displays a file open dialog. Calls sp_file_open on - * an OK. - */ -void sp_file_open_dialog (Gtk::Window &parentWindow, void* object, void* data); +// See src/actions/actions-file-window.h /** * Reverts file to disk-copy on "YES" @@ -117,11 +113,7 @@ bool sp_file_save_dialog (Gtk::Window &parentWindow, SPDocument *doc, Inkscape:: void sp_import_document(SPDesktop *desktop, SPDocument *clipdoc, bool in_place, bool on_page = false); -/** - * Displays a file selector dialog, to allow the - * user to import data into the current document. - */ -void sp_file_import (Gtk::Window &parentWindow); +// See src/actions/actions-file-window.h /** * Imports pages into the document. diff --git a/src/ui/dialog/choose-file.cpp b/src/ui/dialog/choose-file.cpp index 72bc0c2c38..77416a63c0 100644 --- a/src/ui/dialog/choose-file.cpp +++ b/src/ui/dialog/choose-file.cpp @@ -17,6 +17,7 @@ #include #include "preferences.h" +#include "choose-file-utils.h" namespace Inkscape { @@ -172,7 +173,57 @@ Glib::RefPtr choose_file_open(Glib::ustring const &title, Gtk::Window return choose_file_open(title, parent, filters_model, current_folder, accept); } -} // namespace Inkscape +// Open one or more image files. +std::vector> choose_file_open_images(Glib::ustring const &title, + Gtk::Window* parent, + std::string const &pref_path, + Glib::ustring const &accept) +{ + auto const file_dialog = create_file_dialog(title, accept); + auto filter_model = Inkscape::UI::Dialog::create_open_filters(); + set_filters(*file_dialog, filter_model); + + std::string current_folder; + Inkscape::UI::Dialog::get_start_directory(current_folder, pref_path, true); + if (current_folder.empty()) { + current_folder = Glib::get_home_dir(); + } + file_dialog->set_initial_folder(Gio::File::create_for_path(current_folder)); + + bool responded = false; + std::vector> files; + + file_dialog->open_multiple(*parent, [&](Glib::RefPtr const &result) + { + try { + responded = true; + + files = file_dialog->open_multiple_finish(result); + if (files.size() == 0) { + return; + } + if (files.size() == 1) { + // Save current_folder. + current_folder = files[0]->get_parent()->get_path(); + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + prefs->setString(pref_path, current_folder); + } + } catch (Gtk::DialogError const &error) { + if (error.code() == Gtk::DialogError::Code::DISMISSED) { + responded = true; + } else { + throw; + } + } + }, Glib::RefPtr{}); + + auto const main_context = Glib::MainContext::get_default(); + while (!responded) { + main_context->iteration(true); + } + + return files; +}} // namespace Inkscape /* Local Variables: diff --git a/src/ui/dialog/choose-file.h b/src/ui/dialog/choose-file.h index f927a10bea..11bc7284b6 100644 --- a/src/ui/dialog/choose-file.h +++ b/src/ui/dialog/choose-file.h @@ -73,6 +73,15 @@ Glib::RefPtr choose_file_open(Glib::ustring const &title, Gtk::Window std::string& current_folder, Glib::ustring const &accept={}); +/// Synchronously run a Gtk::FileDialog to open a one or more image files. +/// @param pref_path Preference path (i.e. "/dialog/open/path"). +/// @returns vector of selected Gio::Files. +[[nodiscard]] +std::vector> choose_file_open_images(Glib::ustring const &title, + Gtk::Window *parent, + std::string const &pref_path, + Glib::ustring const &accept={}); + } // namespace Inkscape #endif // SEEN_CHOOSE_FILE_H -- GitLab From 4f1a89b86eaed73d98f2d118099389f29c24b4c8 Mon Sep 17 00:00:00 2001 From: Tavmjong Bah Date: Wed, 16 Oct 2024 21:24:59 +0200 Subject: [PATCH 05/11] Remove FileOpenDialog and FileOpenDialogImplGtk classes. --- src/ui/dialog/filedialog.cpp | 14 --- src/ui/dialog/filedialog.h | 29 ------ src/ui/dialog/filedialogimpl-gtkmm.cpp | 126 ------------------------- src/ui/dialog/filedialogimpl-gtkmm.h | 44 --------- 4 files changed, 213 deletions(-) diff --git a/src/ui/dialog/filedialog.cpp b/src/ui/dialog/filedialog.cpp index 6daa414a1c..3f8ec63c48 100644 --- a/src/ui/dialog/filedialog.cpp +++ b/src/ui/dialog/filedialog.cpp @@ -73,20 +73,6 @@ bool isValidImageFile(const Glib::ustring &fileName) return false; } -/*######################################################################### - ### F I L E O P E N - #########################################################################*/ - -/** - * Public factory. Called by file.cpp, among others. - */ -std::unique_ptr FileOpenDialog::create(Gtk::Window &parentWindow, - std::string const &path, - FileDialogType fileTypes, - char const *title) -{ - return std::make_unique(parentWindow, path, fileTypes, title); -} //######################################################################## //# F I L E S A V E diff --git a/src/ui/dialog/filedialog.h b/src/ui/dialog/filedialog.h index 536d169d1f..64554dc536 100644 --- a/src/ui/dialog/filedialog.h +++ b/src/ui/dialog/filedialog.h @@ -113,35 +113,6 @@ protected: Inkscape::Extension::Extension *_extension; }; -/** - * This class provides an implementation-independent API for - * file "Open" dialogs. Using a standard interface obviates the need - * for ugly #ifdefs in file open code - */ -class FileOpenDialog : public FileDialog -{ -public: - virtual ~FileOpenDialog() = default; - - /** - * Factory. - * @param path the directory where to start searching - * @param fileTypes one of FileDialogTypes - * @param title the title of the dialog - */ - static std::unique_ptr create(Gtk::Window &parentWindow, - std::string const &path, - FileDialogType fileTypes, - char const *title); - - virtual void setSelectMultiple(bool value) = 0; - virtual Glib::RefPtr getFiles() = 0; - virtual Glib::RefPtr getFile() = 0; - -protected: - FileOpenDialog() = default; -}; - /** * This class provides an implementation-independent API for file "Save" dialogs. */ diff --git a/src/ui/dialog/filedialogimpl-gtkmm.cpp b/src/ui/dialog/filedialogimpl-gtkmm.cpp index 2e69eb2f6a..14cf037aa7 100644 --- a/src/ui/dialog/filedialogimpl-gtkmm.cpp +++ b/src/ui/dialog/filedialogimpl-gtkmm.cpp @@ -91,132 +91,6 @@ Glib::ustring FileDialogBaseGtk::extToPattern(const Glib::ustring &extension) co return pattern; } -/*######################################################################### -### F I L E O P E N -#########################################################################*/ - -/** - * Constructor. Not called directly. Use the factory. - */ -FileOpenDialogImplGtk::FileOpenDialogImplGtk(Gtk::Window &parentWindow, const std::string &dir, - FileDialogType fileTypes, const Glib::ustring &title) - : FileDialogBaseGtk(parentWindow, title, Gtk::FileChooser::Action::OPEN, fileTypes, "/dialogs/open") -{ - if (_dialogType == EXE_TYPES) { - /* One file at a time */ - set_select_multiple(false); - } else { - /* And also Multiple Files */ - set_select_multiple(true); - } - - // set_local_only(false); // Gone? - - /* Set our dialog type (open, import, etc...)*/ - _dialogType = fileTypes; - - /* Set the pwd and/or the filename */ - if (dir.size() > 0) { - std::string udir(dir); - std::string::size_type len = udir.length(); - // leaving a trailing backslash on the directory name leads to the infamous - // double-directory bug on win32 - - if (len != 0 && udir[len - 1] == '\\') { - udir.erase(len - 1); - } - - auto file = Gio::File::create_for_path(udir); - if (_dialogType == EXE_TYPES) { - set_file(file); - } else { - set_current_folder(file); - } - } - - // Add the file types menu. - createFilterMenu(); - - add_button(_("_Cancel"), Gtk::ResponseType::CANCEL); - add_button(_("_Open"), Gtk::ResponseType::OK); - set_default_response(Gtk::ResponseType::OK); - - // Allow easy access to our examples folder. - using namespace Inkscape::IO::Resource; - auto examplesdir = get_path_string(SYSTEM, EXAMPLES); - if (Glib::file_test(examplesdir, Glib::FileTest::IS_DIR) && Glib::path_is_absolute(examplesdir)) { - add_shortcut_folder(Gio::File::create_for_path(examplesdir)); - } -} - -void FileOpenDialogImplGtk::createFilterMenu() -{ - if (_dialogType == CUSTOM_TYPE) { - return; - } - - addFilter(_("All Files"), "*"); - - if (_dialogType != EXE_TYPES) { - auto allInkscapeFilter = addFilter(_("All Inkscape Files")); - auto allImageFilter = addFilter(_("All Images")); - auto allVectorFilter = addFilter(_("All Vectors")); - auto allBitmapFilter = addFilter(_("All Bitmaps")); - - // patterns added dynamically below - Inkscape::Extension::DB::InputList extension_list; - Inkscape::Extension::db.get_input_list(extension_list); - - for (auto imod : extension_list) - { - addFilter(imod->get_filetypename(true), imod->get_extension(), imod); - - auto upattern = extToPattern(imod->get_extension()); - allInkscapeFilter->add_pattern(upattern); - if (strncmp("image", imod->get_mimetype(), 5) == 0) - allImageFilter->add_pattern(upattern); - - // I don't know of any other way to define "bitmap" formats other than by listing them - if (strncmp("image/png", imod->get_mimetype(), 9) == 0 || - strncmp("image/jpeg", imod->get_mimetype(), 10) == 0 || - strncmp("image/gif", imod->get_mimetype(), 9) == 0 || - strncmp("image/x-icon", imod->get_mimetype(), 12) == 0 || - strncmp("image/x-navi-animation", imod->get_mimetype(), 22) == 0 || - strncmp("image/x-cmu-raster", imod->get_mimetype(), 18) == 0 || - strncmp("image/x-xpixmap", imod->get_mimetype(), 15) == 0 || - strncmp("image/bmp", imod->get_mimetype(), 9) == 0 || - strncmp("image/vnd.wap.wbmp", imod->get_mimetype(), 18) == 0 || - strncmp("image/tiff", imod->get_mimetype(), 10) == 0 || - strncmp("image/x-xbitmap", imod->get_mimetype(), 15) == 0 || - strncmp("image/x-tga", imod->get_mimetype(), 11) == 0 || - strncmp("image/x-pcx", imod->get_mimetype(), 11) == 0) - { - allBitmapFilter->add_pattern(upattern); - } else { - allVectorFilter->add_pattern(upattern); - } - } - } - return; -} - -/** - * Show this dialog modally. Return true if user hits [OK] - */ -bool FileOpenDialogImplGtk::show() -{ - set_modal(true); // Window - sp_transientize(*this); // Make transient - int response = dialog_run(*this); // Dialog - - if (response == Gtk::ResponseType::OK) { - setExtension(filterExtensionMap[get_filter()]); - return true; - } - - return false; -} - //######################################################################## //# F I L E S A V E diff --git a/src/ui/dialog/filedialogimpl-gtkmm.h b/src/ui/dialog/filedialogimpl-gtkmm.h index 2dd8de4324..b60b776cb7 100644 --- a/src/ui/dialog/filedialogimpl-gtkmm.h +++ b/src/ui/dialog/filedialogimpl-gtkmm.h @@ -84,50 +84,6 @@ protected: std::map> extensionFilterMap; }; -/*######################################################################### -### F I L E O P E N -#########################################################################*/ - -/** - * Our implementation class for the FileOpenDialog interface.. - */ -class FileOpenDialogImplGtk final - : public FileOpenDialog - , public FileDialogBaseGtk -{ -public: - FileOpenDialogImplGtk(Gtk::Window& parentWindow, - std::string const &dir, - FileDialogType fileTypes, - Glib::ustring const &title); - - bool show() override; - - void setSelectMultiple(bool value) override { set_select_multiple(value); } - Glib::RefPtr getFiles() override { return get_files(); } - Glib::RefPtr getFile() override { return get_file(); } - - Glib::RefPtr getCurrentDirectory() override - { - auto file = get_current_folder(); - if (file != nullptr) { - return file; - } - return getFile()->get_parent(); - } - - void addFilterMenu(Glib::ustring const &name, Glib::ustring pattern = "", - Inkscape::Extension::Extension *mod = nullptr) override - { - addFilter(name, pattern, mod); - } - -private: - /** - * Create a filter menu for this type of dialog - */ - void createFilterMenu(); -}; //######################################################################## //# F I L E S A V E -- GitLab From 1cedb46c596f063263511596ddafc249224dcd61 Mon Sep 17 00:00:00 2001 From: Tavmjong Bah Date: Fri, 18 Oct 2024 10:33:01 +0200 Subject: [PATCH 06/11] Add new choose_file_save() function that takes a list of file filters. Add function to generate Export file filter list, with only one entry per file type (i.e., one entry for SVG instead of one for Inkscape SVG, Plain SVG, and Optimized SVG). Convert ExportSingle dialog to use new choose_file_save(). Enable all supported filetypes in ExportSingle dialog. --- src/ui/dialog/choose-file-utils.cpp | 212 ++++++++++++++++++---------- src/ui/dialog/choose-file-utils.h | 3 + src/ui/dialog/choose-file.cpp | 30 +++- src/ui/dialog/choose-file.h | 16 ++- src/ui/dialog/export-single.cpp | 57 ++++---- src/ui/widget/export-lists.cpp | 5 +- 6 files changed, 216 insertions(+), 107 deletions(-) diff --git a/src/ui/dialog/choose-file-utils.cpp b/src/ui/dialog/choose-file-utils.cpp index ceaccb943b..c0b442181f 100644 --- a/src/ui/dialog/choose-file-utils.cpp +++ b/src/ui/dialog/choose-file-utils.cpp @@ -14,6 +14,7 @@ #include "extension/db.h" #include "extension/input.h" +#include "extension/output.h" namespace Inkscape::UI::Dialog { @@ -47,78 +48,147 @@ void get_start_directory(std::string &start_path, Glib::ustring const &prefs_pat Glib::RefPtr> create_open_filters() { - auto filters = Gio::ListStore::create(); - - auto allfiles = Gtk::FileFilter::create(); - allfiles->set_name(_("All Files")); - allfiles->add_pattern("*"); - filters->append(allfiles); - - auto inkscape = Gtk::FileFilter::create(); - inkscape->set_name(_("All Inkscape Files")); - filters->append(inkscape); - - auto images = Gtk::FileFilter::create(); - images->set_name(_("Images")); - filters->append(images); - - auto bitmaps = Gtk::FileFilter::create(); - bitmaps->set_name(_("Bitmaps")); - filters->append(bitmaps); - - auto vectors = Gtk::FileFilter::create(); - vectors->set_name(_("Vectors")); - filters->append(vectors); - - // Patterns added dynamically below based on which files are supported by input extensions. - Inkscape::Extension::DB::InputList extension_list; - Inkscape::Extension::db.get_input_list(extension_list); - - for (auto imod : extension_list) { - - gchar const * extension = imod->get_extension(); - if (extension[0]) { - extension = extension + 1; // extension begins with '.', we need it without! - } - - // TODO: Evaluate add_mime_type() instead of add_suffix(). This might allow opening - // files with wrong extension. - - // Add filter for this extension. - auto filter = Gtk::FileFilter::create(); - filter->set_name(imod->get_filetypename(true)); - filter->add_suffix(extension); // Both upper and lower cases. - filters->append(filter); - - inkscape->add_suffix(extension); - - if (strncmp("image", imod->get_mimetype(), 5) == 0) { - images->add_suffix(extension); - } - - // I don't know of any other way to define "bitmap" formats other than by listing them - // clang-format off - if (strncmp("image/png", imod->get_mimetype(), 9) == 0 || - strncmp("image/jpeg", imod->get_mimetype(), 10) == 0 || - strncmp("image/gif", imod->get_mimetype(), 9) == 0 || - strncmp("image/x-icon", imod->get_mimetype(), 12) == 0 || - strncmp("image/x-navi-animation", imod->get_mimetype(), 22) == 0 || - strncmp("image/x-cmu-raster", imod->get_mimetype(), 18) == 0 || - strncmp("image/x-xpixmap", imod->get_mimetype(), 15) == 0 || - strncmp("image/bmp", imod->get_mimetype(), 9) == 0 || - strncmp("image/vnd.wap.wbmp", imod->get_mimetype(), 18) == 0 || - strncmp("image/tiff", imod->get_mimetype(), 10) == 0 || - strncmp("image/x-xbitmap", imod->get_mimetype(), 15) == 0 || - strncmp("image/x-tga", imod->get_mimetype(), 11) == 0 || - strncmp("image/x-pcx", imod->get_mimetype(), 11) == 0) { - bitmaps->add_suffix(extension); - } else { - vectors->add_suffix(extension); - } - // clang-format on - } // Loop over extension_list + auto filters = Gio::ListStore::create(); + + auto allfiles = Gtk::FileFilter::create(); + allfiles->set_name(_("All Files")); + allfiles->add_pattern("*"); + filters->append(allfiles); + + auto inkscape = Gtk::FileFilter::create(); + inkscape->set_name(_("All Inkscape Files")); + filters->append(inkscape); + + auto images = Gtk::FileFilter::create(); + images->set_name(_("Images")); + filters->append(images); + + auto bitmaps = Gtk::FileFilter::create(); + bitmaps->set_name(_("Bitmaps")); + filters->append(bitmaps); + + auto vectors = Gtk::FileFilter::create(); + vectors->set_name(_("Vectors")); + filters->append(vectors); + + // Patterns added dynamically below based on which files are supported by input extensions. + Inkscape::Extension::DB::InputList extension_list; + Inkscape::Extension::db.get_input_list(extension_list); + + for (auto imod : extension_list) { + + gchar const * extension = imod->get_extension(); + if (extension[0]) { + extension = extension + 1; // extension begins with '.', we need it without! + } + + // TODO: Evaluate add_mime_type() instead of add_suffix(). This might allow opening + // files with wrong extension. + + // Add filter for this extension. + auto filter = Gtk::FileFilter::create(); + filter->set_name(imod->get_filetypename(true)); + filter->add_suffix(extension); // Both upper and lower cases. + filters->append(filter); + + inkscape->add_suffix(extension); + + if (strncmp("image", imod->get_mimetype(), 5) == 0) { + images->add_suffix(extension); + } + + // I don't know of any other way to define "bitmap" formats other than by listing them + // clang-format off + if (strncmp("image/png", imod->get_mimetype(), 9) == 0 || + strncmp("image/jpeg", imod->get_mimetype(), 10) == 0 || + strncmp("image/gif", imod->get_mimetype(), 9) == 0 || + strncmp("image/x-icon", imod->get_mimetype(), 12) == 0 || + strncmp("image/x-navi-animation", imod->get_mimetype(), 22) == 0 || + strncmp("image/x-cmu-raster", imod->get_mimetype(), 18) == 0 || + strncmp("image/x-xpixmap", imod->get_mimetype(), 15) == 0 || + strncmp("image/bmp", imod->get_mimetype(), 9) == 0 || + strncmp("image/vnd.wap.wbmp", imod->get_mimetype(), 18) == 0 || + strncmp("image/tiff", imod->get_mimetype(), 10) == 0 || + strncmp("image/x-xbitmap", imod->get_mimetype(), 15) == 0 || + strncmp("image/x-tga", imod->get_mimetype(), 11) == 0 || + strncmp("image/x-pcx", imod->get_mimetype(), 11) == 0) { + bitmaps->add_suffix(extension); + } else { + vectors->add_suffix(extension); + } + // clang-format on + } // Loop over extension_list + + return filters; +} - return filters; +Glib::RefPtr> +create_export_filters() { + + auto filters = Gio::ListStore::create(); + + auto allfiles = Gtk::FileFilter::create(); + allfiles->set_name(_("All Files")); + allfiles->add_pattern("*"); + filters->append(allfiles); + + // Patterns added dynamically below based on which files are supported by output extensions. + Inkscape::Extension::DB::OutputList extension_list; + Inkscape::Extension::db.get_output_list(extension_list); + + std::vector file_extensions; + + for (auto omod : extension_list) { + + gchar const * extension = omod->get_extension(); + if (extension[0]) { + extension = extension + 1; // extension begins with '.', we need it without! + } + Glib::ustring file_extension(extension); + + // Don't add entry for duplicate filename extensions. + if (std::find(file_extensions.begin(), file_extensions.end(), file_extension) != file_extensions.end()) { + // std::cout << "Duplicate extension: " << file_extension << std::endl; + continue; + } + file_extensions.push_back(extension); + + // std::cout << " " << extension + // << " exported: " << std::boolalpha << omod->is_exported() + // << " raster: " << std::boolalpha << omod->is_raster() + // << " save copy only: " << std::boolalpha << omod->savecopy_only() // Always false! + // << " " << omod->get_filetypename() + // << std::endl; + + // For duplicate filename extensions, use simplified name. + auto name = omod->get_filetypename(true); + if (file_extension == "svg") { + name = "SVG (.svg)"; + } + else if (file_extension == "svgz") { + name = _("Compressed SVG (.svgz)"); + } + else if (file_extension == "dxf") { + name = "DXF (.dxf)"; + } + else if (file_extension == "zip") { + name = "ZIP (.zip)"; + } + else if (file_extension == "pdf") { + name = "PDF (.pdf)"; + } + else if (file_extension == "png") { + name = "PNG (.png)"; + } + + // Add filter for this extension. Also see ExtensionList::setup(). + auto filter = Gtk::FileFilter::create(); + filter->set_name(name); + filter->add_suffix(extension); // Both upper and lower cases. + filters->append(filter); + } // Loop over extension_list + + return filters; } } // namespace Inkscape::UI::Dialog diff --git a/src/ui/dialog/choose-file-utils.h b/src/ui/dialog/choose-file-utils.h index 2c44492fde..bb365c4290 100644 --- a/src/ui/dialog/choose-file-utils.h +++ b/src/ui/dialog/choose-file-utils.h @@ -28,6 +28,9 @@ void get_start_directory(std::string &start_path, Glib::ustring const &prefs_pat /// Create a Gtk::FileFilter for all image file types. [[nodiscard]] Glib::RefPtr> create_open_filters(); +/// Create a Gtk::FileFilter for all export file types. +[[nodiscard]] Glib::RefPtr> create_export_filters(); + } // namespace Inkscape::UI::Dialog diff --git a/src/ui/dialog/choose-file.cpp b/src/ui/dialog/choose-file.cpp index 77416a63c0..f0500e93a8 100644 --- a/src/ui/dialog/choose-file.cpp +++ b/src/ui/dialog/choose-file.cpp @@ -91,8 +91,8 @@ using FinishMethod = Glib::RefPtr (Gtk::FileDialog::*) } Glib::RefPtr choose_file_save(Glib::ustring const &title, Gtk::Window *parent, - Glib::ustring const &mime_type, - Glib::ustring const &file_name, + Glib::RefPtr> const &filters_model, + std::string const &file_name, std::string ¤t_folder) { if (!parent) return {}; @@ -103,9 +103,12 @@ Glib::RefPtr choose_file_save(Glib::ustring const &title, Gtk::Window auto const file_dialog = create_file_dialog(title, _("Save")); - auto filter = Gtk::FileFilter::create(); - filter->add_mime_type(mime_type); - set_filter(*file_dialog, filter); + if (filters_model) { + set_filters(*file_dialog, filters_model); + // for (int i = 0; i < filters_model->get_n_items(); ++i) { + // std::cout << filters_model->get_item(i)->get_name() << std::endl; + // } + } file_dialog->set_initial_name(file_name); @@ -113,6 +116,23 @@ Glib::RefPtr choose_file_save(Glib::ustring const &title, Gtk::Window &Gtk::FileDialog::save, &Gtk::FileDialog::save_finish); } +Glib::RefPtr choose_file_save(Glib::ustring const &title, Gtk::Window *parent, + Glib::ustring const &mime_type, + std::string const &file_name, + std::string ¤t_folder) +{ + if (!parent) return {}; + + auto filters_model = Gio::ListStore::create(); + auto filter = Gtk::FileFilter::create(); + if (!mime_type.empty()) { + auto filter = Gtk::FileFilter::create(); + filter->add_mime_type(mime_type); + } + + return choose_file_save(title, parent, filters_model, file_name, current_folder); +} + Glib::RefPtr choose_file_open(Glib::ustring const &title, Gtk::Window *parent, Glib::RefPtr> const &filters_model, std::string ¤t_folder, diff --git a/src/ui/dialog/choose-file.h b/src/ui/dialog/choose-file.h index 11bc7284b6..1c58dd337b 100644 --- a/src/ui/dialog/choose-file.h +++ b/src/ui/dialog/choose-file.h @@ -33,6 +33,17 @@ void set_filters(Gtk::FileDialog &file_dialog, /// Set the available filters & the default filter, to the single filter passed. void set_filter(Gtk::FileDialog &file_dialog, Glib::RefPtr const &filter); +/// Synchronously run a Gtk::FileDialog to select a file for saving data. +/// @param filters_model For selection of file types to be shown in dialog. +/// @param file_name Name of the initial file to show in the dialogʼs text entry. +/// @param current_folder Path of initial folder to show, updated to parent of selected file if any +/// @returns Gio::File for selected file. +[[nodiscard]] +Glib::RefPtr choose_file_save(Glib::ustring const &title, Gtk::Window *parent, + Glib::RefPtr> const &filters_model, + std::string const &file_name, + std::string ¤t_folder); + /// Synchronously run a Gtk::FileDialog to select a file for saving data. /// @param mime_type MIME type to use as a file filter in the dialog. /// @param file_name Name of the initial file to show in the dialogʼs text entry. @@ -40,8 +51,9 @@ void set_filter(Gtk::FileDialog &file_dialog, Glib::RefPtr cons /// @returns Gio::File for selected file. [[nodiscard]] Glib::RefPtr choose_file_save(Glib::ustring const &title, Gtk::Window *parent, - Glib::ustring const &mime_type, Glib::ustring const &file_name, - std::string& current_folder); + Glib::ustring const &mime_type, + std::string const &file_name, + std::string ¤t_folder); /// Synchronously run a Gtk::FileDialog to open a single file for reading data. /// @param filters_model For selection of file types to be shown in dialog. diff --git a/src/ui/dialog/export-single.cpp b/src/ui/dialog/export-single.cpp index 7b9c3cf022..9f7326dbf7 100644 --- a/src/ui/dialog/export-single.cpp +++ b/src/ui/dialog/export-single.cpp @@ -13,12 +13,16 @@ #include "export-single.h" +#include +#include + #include #include #include #include #include #include +#include #include #include #include @@ -46,7 +50,8 @@ #include "selection.h" #include "ui/builder-utils.h" #include "ui/dialog/export.h" -#include "ui/dialog/filedialog.h" +#include "ui/dialog/choose-file.h" +#include "ui/dialog/choose-file-utils.h" #include "ui/icon-names.h" #include "ui/util.h" #include "ui/widget/color-picker.h" @@ -654,6 +659,11 @@ void SingleExport::onFilenameModified() si_extension_cb.setExtensionFromFilename(filename); } + // This will not change the output extension if filename extension is same as previously + // selected extension's filename extension. In otherwords, selecting "SVG" in file dialog + // won't override "Plain SVG" in export dialog. + si_extension_cb.setExtensionFromFilename(filename); + extensionConn.unblock(); } @@ -687,6 +697,7 @@ void SingleExport::onExport() bool exportSuccessful = false; auto omod = si_extension_cb.getExtension(); if (!omod) { + std::cerr << "SingleExport::onExport(): Cannot find export extension!" << std::endl; return; } @@ -802,36 +813,28 @@ void SingleExport::onBrowse() Gtk::Window *window = _app->get_active_window(); browseConn.block(); + auto omod = si_extension_cb.getExtension(); + assert(omod); - auto previous_filename = filepath_native; - if (previous_filename.empty()) { - previous_filename = Export::defaultFilename(_document, filepath_native, ".png"); - } - - auto dialog = Inkscape::UI::Dialog::FileSaveDialog::create( - *window, previous_filename, Inkscape::UI::Dialog::EXPORT_TYPES, _("Select a filename for exporting"), "", "", - Inkscape::Extension::FILE_SAVE_METHOD_EXPORT); + std::string filename = Glib::filename_from_utf8(si_filename_entry.get_text()); - // Tell the browse dialog what extension to start with - if (auto omod = si_extension_cb.getExtension()) { - dialog->setExtension(omod); + if (filename.empty()) { + filename = Export::defaultFilename(_document, filename, omod->get_extension()); } - if (dialog->show()) { - auto file = dialog->getFile(); - if (file) { - auto filename = file->get_path(); - // Once complete, we use the extension selected to save the file - if (auto ext = dialog->getExtension()) { - si_extension_cb.set_active_id(ext->get_id()); - } else { - si_extension_cb.setExtensionFromFilename(filename); - } - setFilename(filename, true); - } - - // deleting dialog before exporting is important - dialog.reset(); + // Note, there are currently multiple modules per filename extension (.svg, .dxf, .zip). + // We cannot distinguish between them. + std::string basename = Glib::path_get_basename(filename); + std::string dirname = Glib::path_get_dirname(filename); + auto file = choose_file_save( _("Select a filename for exporting"), window, + create_export_filters(), // {}, // mimetype + basename, + dirname); + + if (file) { + Glib::ustring filename_utf8 = file->get_parse_name(); + si_filename_entry.set_text(filename_utf8); + si_filename_entry.set_position(filename_utf8.length()); onExport(); } diff --git a/src/ui/widget/export-lists.cpp b/src/ui/widget/export-lists.cpp index 65a95e4859..63c945c3bd 100644 --- a/src/ui/widget/export-lists.cpp +++ b/src/ui/widget/export-lists.cpp @@ -81,6 +81,7 @@ void ExtensionList::on_changed() void ExtensionList::setup() { + // See also create_export_filters(). this->remove_all(); Inkscape::Preferences *prefs = Inkscape::Preferences::get(); @@ -90,8 +91,8 @@ void ExtensionList::setup() Inkscape::Extension::db.get_output_list(extensions); for (auto omod : extensions) { auto oid = Glib::ustring(omod->get_id()); - if (!export_all && !omod->is_raster() && !omod->is_exported()) - continue; + // if (!export_all && !omod->is_raster() && !omod->is_exported()) + // continue; // Comboboxes don't have a disabled row property if (omod->deactivated()) continue; -- GitLab From 098f5ad0c544bf37a29e5f594166b9ecedcf7e4c Mon Sep 17 00:00:00 2001 From: Tavmjong Bah Date: Tue, 5 Nov 2024 13:43:26 +0100 Subject: [PATCH 07/11] Use new choose_file_save() function for "Save as" and "Save a copy". Add option to create file filters for saving with create_export_filters() function (exclude raster types as saving from Save dialogs fails, use generic ".svg", ".dxf", etc. entries where Limit file-filters to non-raster types (saving raster types fails). --- src/file.cpp | 76 +++++++++++++++++------------ src/ui/dialog/choose-file-utils.cpp | 23 ++++++--- src/ui/dialog/choose-file-utils.h | 2 +- 3 files changed, 61 insertions(+), 40 deletions(-) diff --git a/src/file.cpp b/src/file.cpp index 6534cc04f6..2294900efc 100644 --- a/src/file.cpp +++ b/src/file.cpp @@ -65,8 +65,9 @@ #include "selection.h" #include "style.h" #include "svg/svg.h" // for sp_svg_transform_write, used in sp_import_document +#include "ui/dialog/choose-file.h" #include "ui/dialog/choose-file-utils.h" -#include "ui/dialog/filedialog.h" +#include "ui/dialog/filedialog.h" // TODO REMOVE! #include "ui/icon-names.h" #include "ui/interface.h" #include "ui/tools/tool-base.h" @@ -339,43 +340,54 @@ sp_file_save_dialog(Gtk::Window &parentWindow, SPDocument *doc, Inkscape::Extens } // Show the SaveAs dialog. - char const *dialog_title = is_copy ? - (char const *) _("Select file to save a copy to") : - (char const *) _("Select file to save to"); - + const Glib::ustring dialog_title = is_copy ? + _("Select file to save a copy to") : + _("Select file to save to"); + + // Note, there are currently multiple modules per filename extension (.svg, .dxf, .zip). + // We cannot distinguish between them. + std::string basename = Glib::path_get_basename(save_loc); + std::string dirname = Glib::path_get_dirname(save_loc); + auto file = choose_file_save( dialog_title, &parentWindow, + Inkscape::UI::Dialog::create_export_filters(true), + basename, + dirname); + + if (!file) { + return false; // Cancelled + } + + // Set title here (call RDF to ensure metadata and title element are updated). + // Is this necessary? In 1.4.x, the Windows native dialog shows the title in + // an entry which can be changed but 1.5.x doesn't allow that. gchar* doc_title = doc->getRoot()->title(); - auto saveDialog = - Inkscape::UI::Dialog::FileSaveDialog::create( - parentWindow, - save_loc, - Inkscape::UI::Dialog::SVG_TYPES, - dialog_title, - default_extension, - doc_title ? doc_title : "", - save_method); - - saveDialog->setExtension(extension); // Use default extension from preferences! - - bool success = saveDialog->show(); - if (!success) { - if (doc_title) { - g_free(doc_title); - } - return success; + if (doc_title) { + rdf_set_work_entity(doc, rdf_find_entity("title"), doc_title); + g_free(doc_title); } - // set new title here (call RDF to ensure metadata and title element are updated) - rdf_set_work_entity(doc, rdf_find_entity("title"), saveDialog->getDocTitle().c_str()); + // Find output module from file extension. + auto file_extension = Inkscape::IO::get_file_extension(file->get_path()); - auto file = saveDialog->getFile(); - Inkscape::Extension::Extension *selectionType = saveDialog->getExtension(); + Inkscape::Extension::DB::OutputList extension_list; + Inkscape::Extension::db.get_output_list(extension_list); + bool found = false; - saveDialog.reset(); - if (doc_title) { - g_free(doc_title); + for (auto omod : extension_list) { + if (file_extension == omod->get_extension()) { + extension = omod; + found = true; + break; + } } - if (file_save(parentWindow, doc, file, selectionType, true, !is_copy, save_method)) { + if (!found) { + std::cerr << "sp_file_save_dialog(): Cannot find output module for file type: " + << file_extension << "!" << std::endl; + return false; + } + + if (file_save(parentWindow, doc, file, extension, true, !is_copy, save_method)) { if (doc->getDocumentFilename()) { Glib::RefPtr recent = Gtk::RecentManager::get_default(); @@ -385,7 +397,7 @@ sp_file_save_dialog(Gtk::Window &parentWindow, SPDocument *doc, Inkscape::Extens save_path = Glib::path_get_dirname(file->get_path()); Inkscape::Extension::store_save_path_in_prefs(save_path, save_method); - return success; + return true; } return false; diff --git a/src/ui/dialog/choose-file-utils.cpp b/src/ui/dialog/choose-file-utils.cpp index c0b442181f..838635cd37 100644 --- a/src/ui/dialog/choose-file-utils.cpp +++ b/src/ui/dialog/choose-file-utils.cpp @@ -122,8 +122,11 @@ create_open_filters() { return filters; } +// Return a list of file filters for the Export dialog. +// Optionally, return a custom list for the Save dialog (hopefully to disappear). +// With native dialogs, we can only examine the file path on return. Glib::RefPtr> -create_export_filters() { +create_export_filters(bool for_save) { auto filters = Gio::ListStore::create(); @@ -140,6 +143,18 @@ create_export_filters() { for (auto omod : extension_list) { + // std::cout << " " << extension + // << " exported: " << std::boolalpha << omod->is_exported() + // << " raster: " << std::boolalpha << omod->is_raster() + // << " save copy only: " << std::boolalpha << omod->savecopy_only() // Always false! + // << " " << omod->get_filetypename() + // << std::endl; + + // Save dialogs cannot handle raster images. + if (for_save && omod->is_raster()) { + continue; + } + gchar const * extension = omod->get_extension(); if (extension[0]) { extension = extension + 1; // extension begins with '.', we need it without! @@ -153,12 +168,6 @@ create_export_filters() { } file_extensions.push_back(extension); - // std::cout << " " << extension - // << " exported: " << std::boolalpha << omod->is_exported() - // << " raster: " << std::boolalpha << omod->is_raster() - // << " save copy only: " << std::boolalpha << omod->savecopy_only() // Always false! - // << " " << omod->get_filetypename() - // << std::endl; // For duplicate filename extensions, use simplified name. auto name = omod->get_filetypename(true); diff --git a/src/ui/dialog/choose-file-utils.h b/src/ui/dialog/choose-file-utils.h index bb365c4290..3572d3c2f1 100644 --- a/src/ui/dialog/choose-file-utils.h +++ b/src/ui/dialog/choose-file-utils.h @@ -29,7 +29,7 @@ void get_start_directory(std::string &start_path, Glib::ustring const &prefs_pat [[nodiscard]] Glib::RefPtr> create_open_filters(); /// Create a Gtk::FileFilter for all export file types. -[[nodiscard]] Glib::RefPtr> create_export_filters(); +[[nodiscard]] Glib::RefPtr> create_export_filters(bool for_save = false); } // namespace Inkscape::UI::Dialog -- GitLab From d0a6abea855e1ffb45d5fc4824aa732fcda0190b Mon Sep 17 00:00:00 2001 From: Tavmjong Bah Date: Tue, 5 Nov 2024 13:48:29 +0100 Subject: [PATCH 08/11] Remove remnants of old file dialog code. --- src/file.cpp | 1 - src/ui/CMakeLists.txt | 4 - src/ui/dialog/filedialog.cpp | 132 --------- src/ui/dialog/filedialog.h | 174 ------------ src/ui/dialog/filedialogimpl-gtkmm.cpp | 371 ------------------------- src/ui/dialog/filedialogimpl-gtkmm.h | 166 ----------- src/ui/widget/preferences-widget.cpp | 1 - 7 files changed, 849 deletions(-) delete mode 100644 src/ui/dialog/filedialog.cpp delete mode 100644 src/ui/dialog/filedialog.h delete mode 100644 src/ui/dialog/filedialogimpl-gtkmm.cpp delete mode 100644 src/ui/dialog/filedialogimpl-gtkmm.h diff --git a/src/file.cpp b/src/file.cpp index 2294900efc..549e914f6c 100644 --- a/src/file.cpp +++ b/src/file.cpp @@ -67,7 +67,6 @@ #include "svg/svg.h" // for sp_svg_transform_write, used in sp_import_document #include "ui/dialog/choose-file.h" #include "ui/dialog/choose-file-utils.h" -#include "ui/dialog/filedialog.h" // TODO REMOVE! #include "ui/icon-names.h" #include "ui/interface.h" #include "ui/tools/tool-base.h" diff --git a/src/ui/CMakeLists.txt b/src/ui/CMakeLists.txt index 7ab02e635a..df176e0343 100644 --- a/src/ui/CMakeLists.txt +++ b/src/ui/CMakeLists.txt @@ -135,8 +135,6 @@ set(ui_SRC dialog/export-batch.cpp dialog/export-single.cpp dialog/extensions-gallery.cpp - dialog/filedialog.cpp - dialog/filedialogimpl-gtkmm.cpp dialog/fill-and-stroke.cpp dialog/filter-effects-dialog.cpp dialog/find.cpp @@ -353,8 +351,6 @@ set(ui_SRC dialog/export-batch.h dialog/export-single.h dialog/extensions-gallery.h - dialog/filedialog.h - dialog/filedialogimpl-gtkmm.h dialog/fill-and-stroke.h dialog/filter-effects-dialog.h dialog/find.h diff --git a/src/ui/dialog/filedialog.cpp b/src/ui/dialog/filedialog.cpp deleted file mode 100644 index 3f8ec63c48..0000000000 --- a/src/ui/dialog/filedialog.cpp +++ /dev/null @@ -1,132 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/** - * @file - * Implementation of the file dialog interfaces defined in filedialog.h. - */ -/* Authors: - * Bob Jamison - * Joel Holdsworth - * Others from The Inkscape Organization - * - * Copyright (C) 2004-2007 Bob Jamison - * Copyright (C) 2006 Johan Engelen - * Copyright (C) 2007-2008 Joel Holdsworth - * Copyright (C) 2004-2008 The Inkscape Organization - * - * Released under GNU GPL v2+, read the file 'COPYING' for more information. - */ - -#include "filedialog.h" - -#include // Glib::get_home_dir() -#include - -#ifdef _WIN32 -#include -#endif - -#include "filedialogimpl-gtkmm.h" - -#include "preferences.h" -#include "ui/dialog-events.h" -#include "extension/output.h" - - -namespace Inkscape::UI::Dialog { - -/*######################################################################### - ### U T I L I T Y - #########################################################################*/ - -bool hasSuffix(const Glib::ustring &str, const Glib::ustring &ext) -{ - int strLen = str.length(); - int extLen = ext.length(); - if (extLen > strLen) - return false; - int strpos = strLen-1; - for (int extpos = extLen-1 ; extpos>=0 ; extpos--, strpos--) { - Glib::ustring::value_type ch = str[strpos]; - if (ch != ext[extpos]) { - if ( ((ch & 0xff80) != 0) || - static_cast( g_ascii_tolower( static_cast(0x07f & ch) ) ) != ext[extpos] ) - { - return false; - } - } - } - return true; -} - -bool isValidImageFile(const Glib::ustring &fileName) -{ - std::vectorformats = Gdk::Pixbuf::get_formats(); // Returns Glib::ustrings! - for (auto format : formats) - { - std::vectorextensions = format.get_extensions(); - for (auto ext : extensions) - { - if (hasSuffix(fileName, ext)) - return true; - } - } - return false; -} - - -//######################################################################## -//# F I L E S A V E -//######################################################################## - -/** - * Public factory method. Used in file.cpp - */ -std::unique_ptr FileSaveDialog::create(Gtk::Window& parentWindow, - std::string const &path, - FileDialogType fileTypes, - char const *title, - Glib::ustring const &default_key, - char const *docTitle, - Inkscape::Extension::FileSaveMethod save_method) -{ - return std::make_unique(parentWindow, path, fileTypes, title, default_key, docTitle, save_method); -} - -// Used in FileSaveDialogImplGtk to update displayed filename (thus utf8). -void FileSaveDialog::appendExtension(Glib::ustring& filename_utf8, Inkscape::Extension::Output* outputExtension) -{ - if (!outputExtension) { - return; - } - - bool appendExtension = true; - Glib::ustring::size_type pos = filename_utf8.rfind('.'); - if ( pos != Glib::ustring::npos ) { - Glib::ustring trail = filename_utf8.substr( pos ); - Glib::ustring foldedTrail = trail.casefold(); - if ( (trail == ".") - | (foldedTrail != Glib::ustring( outputExtension->get_extension() ).casefold() - && ( knownExtensions.find(foldedTrail) != knownExtensions.end() ) ) ) { - filename_utf8 = filename_utf8.erase( pos ); - } else { - appendExtension = false; - } - } - - if (appendExtension) { - filename_utf8 = filename_utf8 + outputExtension->get_extension(); - } -} - -} //namespace Inkscape::UI::Dialog - -/* - Local Variables: - mode:c++ - c-file-style:"stroustrup" - c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) - indent-tabs-mode:nil - fill-column:99 - End: -*/ -// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 : diff --git a/src/ui/dialog/filedialog.h b/src/ui/dialog/filedialog.h deleted file mode 100644 index 64554dc536..0000000000 --- a/src/ui/dialog/filedialog.h +++ /dev/null @@ -1,174 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/** @file - * @brief Virtual base definitions for native file dialogs - */ -/* Authors: - * Bob Jamison - * Joel Holdsworth - * Inkscape developers. - * - * Copyright (C) 2006 Johan Engelen - * Copyright (C) 2007-2008 Joel Holdsworth - * Copyright (C) 2004-2008, Inkscape Authors - * - * Released under GNU GPL v2+, read the file 'COPYING' for more information. - */ - -#ifndef SEEN_FILE_DIALOG_H -#define SEEN_FILE_DIALOG_H - -#include -#include -#include - -#include "extension/system.h" - -#include -#include -#include - -namespace Gtk { class Window; } - -class SPDocument; - -namespace Gio { -class File; -} // namespace Gio - -namespace Gtk { -class Window; -} // namespace Gtk - -namespace Inkscape::Extension { -class Extension; -class Output; -} // namespace Inkscape::Extension - -namespace Inkscape::UI::Dialog { - -/** - * Used for setting filters and options, and - * reading them back from user selections. - */ -enum FileDialogType -{ - SVG_TYPES, - IMPORT_TYPES, - EXPORT_TYPES, - EXE_TYPES, - SWATCH_TYPES, - CUSTOM_TYPE -}; - -/** - * Used for returning the type selected in a SaveAs - */ -enum FileDialogSelectionType -{ - SVG_NAMESPACE, - SVG_NAMESPACE_WITH_EXTENSIONS -}; - -/** - * Return true if the string ends with the given suffix - */ -bool hasSuffix(const Glib::ustring &str, const Glib::ustring &ext); - -/** - * Return true if the image is loadable by Gdk, else false. - * Only user is svg-preview.cpp which is disappearing, don't worry about string type. - */ -bool isValidImageFile(const Glib::ustring &fileName); - -class FileDialog -{ -public: - /** - * Return the 'key' (filetype) of the selection, if any - * @return a pointer to a string if successful (which must - * be later freed with g_free(), else NULL. - */ - virtual Inkscape::Extension::Extension *getExtension() { return _extension; } - virtual void setExtension(Inkscape::Extension::Extension *key) { _extension = key; } - - /** - * Show file selector. - * @return the selected path if user selected one, else NULL - */ - virtual bool show() = 0; - - /** - * Add a filter menu to the file dialog. - */ - virtual void addFilterMenu(const Glib::ustring &name, Glib::ustring pattern = "", - Inkscape::Extension::Extension *mod = nullptr) = 0; - - /** - * Get the current directory of the file dialog. - */ - virtual Glib::RefPtr getCurrentDirectory() = 0; - -protected: - // The selected extension - Inkscape::Extension::Extension *_extension; -}; - -/** - * This class provides an implementation-independent API for file "Save" dialogs. - */ -class FileSaveDialog : public FileDialog -{ -public: - // Constructor. Do not call directly. Use the factory. - FileSaveDialog() = default; - virtual ~FileSaveDialog() = default; - - /** - * Factory. - * @param path the directory where to start searching - * @param fileTypes one of FileDialogTypes - * @param title the title of the dialog - * @param key a list of file types from which the user can select - */ - static std::unique_ptr create(Gtk::Window &parentWindow, - std::string const &path, - FileDialogType fileTypes, - char const *title, - Glib::ustring const &default_key, - char const *docTitle, - Inkscape::Extension::FileSaveMethod save_method); - - virtual const Glib::RefPtr getFile() = 0; - virtual void setCurrentName(Glib::ustring) = 0; - - /** - * Get the document title chosen by the user. - * Valid after an [OK] - */ - Glib::ustring getDocTitle () { return myDocTitle; } // Only used by rdf_set_work_entity() - -protected: - // Doc Title that was given - Glib::ustring myDocTitle; - - // List of known file extensions. - std::map knownExtensions; - - void appendExtension(Glib::ustring& filename_utf8, Inkscape::Extension::Output* outputExtension); - -}; //FileSaveDialog - -} // namespace Inkscape::UI::Dialog - -#endif // SEEN_FILE_DIALOG_H - -/* - Local Variables: - mode:c++ - c-file-style:"stroustrup" - c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) - indent-tabs-mode:nil - fill-column:99 - End: -*/ -// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 : diff --git a/src/ui/dialog/filedialogimpl-gtkmm.cpp b/src/ui/dialog/filedialogimpl-gtkmm.cpp deleted file mode 100644 index 14cf037aa7..0000000000 --- a/src/ui/dialog/filedialogimpl-gtkmm.cpp +++ /dev/null @@ -1,371 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/** - * @file - * Implementation of the file dialog interfaces defined in filedialogimpl.h. - */ -/* Authors: - * Bob Jamison - * Joel Holdsworth - * Bruno Dilly - * Others from The Inkscape Organization - * Abhishek Sharma - * - * Copyright (C) 2004-2007 Bob Jamison - * Copyright (C) 2006 Johan Engelen - * Copyright (C) 2007-2008 Joel Holdsworth - * Copyright (C) 2004-2007 The Inkscape Organization - * - * Released under GNU GPL v2+, read the file 'COPYING' for more information. - */ - -#include "filedialogimpl-gtkmm.h" - -#include -#include -#include -#include -#include - -#include "extension/db.h" -#include "extension/input.h" -#include "extension/output.h" -#include "io/resource.h" -#include "io/sys.h" -#include "preferences.h" -#include "ui/dialog-events.h" -#include "ui/dialog-run.h" - -namespace Inkscape::UI::Dialog { - -/*######################################################################### -### F I L E D I A L O G B A S E C L A S S -#########################################################################*/ - -FileDialogBaseGtk::FileDialogBaseGtk(Gtk::Window &parentWindow, Glib::ustring const &title, - Gtk::FileChooser::Action const dialogType, - FileDialogType const type, - char const * const preferenceBase) - : Gtk::FileChooserDialog{parentWindow, title, dialogType} - , _preferenceBase{preferenceBase ? preferenceBase : "unknown"} - , _dialogType(type) -{ - reference(); -} - -FileDialogBaseGtk::~FileDialogBaseGtk() -{ - unreference(); -} - -Glib::RefPtr FileDialogBaseGtk::addFilter(const Glib::ustring &name, Glib::ustring ext, - Inkscape::Extension::Extension *extension) -{ - auto filter = Gtk::FileFilter::create(); - filter->set_name(name); - add_filter(filter); - - if (!ext.empty()) { - filter->add_pattern(extToPattern(ext)); - } - - filterExtensionMap[filter] = extension; - extensionFilterMap[extension] = filter; - - return filter; -} - -// Replace this with add_suffix in Gtk4 -Glib::ustring FileDialogBaseGtk::extToPattern(const Glib::ustring &extension) const -{ - Glib::ustring pattern = "*"; - for (unsigned int ch : extension) { - if (Glib::Unicode::isalpha(ch)) { - pattern += '['; - pattern += Glib::Unicode::toupper(ch); - pattern += Glib::Unicode::tolower(ch); - pattern += ']'; - } else { - pattern += ch; - } - } - return pattern; -} - - -//######################################################################## -//# F I L E S A V E -//######################################################################## - -/** - * Constructor - */ -FileSaveDialogImplGtk::FileSaveDialogImplGtk(Gtk::Window &parentWindow, const std::string &dir, - FileDialogType fileTypes, const Glib::ustring &title, - const Glib::ustring & /*default_key*/, const gchar *docTitle, - const Inkscape::Extension::FileSaveMethod save_method) - : FileDialogBaseGtk(parentWindow, title, Gtk::FileChooser::Action::SAVE, fileTypes, - (save_method == Inkscape::Extension::FILE_SAVE_METHOD_SAVE_COPY) ? "/dialogs/save_copy" - : "/dialogs/save_as") - , save_method(save_method) -{ - if (docTitle) { - FileSaveDialog::myDocTitle = docTitle; - } - - // One file at a time. - set_select_multiple(false); - - // set_local_only(false); // Gone? - - // ===== Choices ===== - - add_choice("Extension", _("Append filename extension automatically")); - add_choice("SVG1.1", _("Export as SVG 1.1 per settings in Preferences dialog")); - - // Initial choice values. - Inkscape::Preferences *prefs = Inkscape::Preferences::get(); - - // Append extention automatically? - bool append_extension = false; - if (save_method == Inkscape::Extension::FILE_SAVE_METHOD_SAVE_COPY) { - append_extension = prefs->getBool("/dialogs/save_copy/append_extension", true); - } else { - append_extension = prefs->getBool("/dialogs/save_as/append_extension", true); - } - set_choice("Extension", append_extension ? "true" : "false"); // set_boolean_extension missing - - // Export as SVG1.1? - bool export_as_svg1_1 = prefs->getBool(_preferenceBase + "/dialogs/s/enable_svgexport", false); - set_choice("SVG1.1", export_as_svg1_1 ? "true" : "false"); - - // ===== Filters ===== - - if (_dialogType != CUSTOM_TYPE) { - createFilterMenu(); - } - - // ===== Templates ===== - - // Allow easy access to the user's own templates folder. - using namespace Inkscape::IO::Resource; - char const *templates = Inkscape::IO::Resource::get_path(USER, TEMPLATES); - if (Inkscape::IO::file_test(templates, G_FILE_TEST_EXISTS) && - Inkscape::IO::file_test(templates, G_FILE_TEST_IS_DIR) && g_path_is_absolute(templates)) { - add_shortcut_folder(Gio::File::create_for_path(templates)); - } - - // ===== Buttons ===== - - add_button(_("_Cancel"), Gtk::ResponseType::CANCEL); - add_button(_("_Save"), Gtk::ResponseType::OK); - set_default_response(Gtk::ResponseType::OK); - - // ===== Initial Value ===== - - // Set the directory or filename. Do this last, after dialog is completely set up. - if (dir.size() > 0) { - std::string udir(dir); - std::string::size_type len = udir.length(); - // Leaving a trailing backslash on the directory name leads to the infamous - // double-directory bug on win32. - if ((len != 0) && (udir[len - 1] == '\\')) { - udir.erase(len - 1); - } - - auto file = Gio::File::create_for_path(udir); - auto display_name = Glib::filename_to_utf8(file->get_basename()); - Gio::FileType type = file->query_file_type(); - switch (type) { - case Gio::FileType::UNKNOWN: - set_file(file); // Set directory. - set_current_name(display_name); // Set entry (Glib::ustring). - break; - case Gio::FileType::REGULAR: - // The extension set here is over-written when called by sp_file_save_dialog(). - set_file(file); // Set directory (but not entry). - set_current_name(display_name); // Set entry. - break; - case Gio::FileType::DIRECTORY: - set_current_folder(file); // Set directory. - break; - default: - std::cerr << "FileDialogImplGtk: Unknown file type: " << (int)type << std::endl; - } - } - - property_filter().signal_changed().connect([this]() { filefilterChanged(); }); - // signal_selection_changed().connect([this]() { filenameChanged(); }); // Gone? -} - -/** - * Show this dialog modally. Return true if user hits [OK] - */ -bool FileSaveDialogImplGtk::show() -{ - set_modal(true); // Window - sp_transientize(*this); - - int response = dialog_run(*this); // Dialog - - if (response == Gtk::ResponseType::OK) { - - Inkscape::Preferences *prefs = Inkscape::Preferences::get(); - - // Store changes of "Choices". - bool append_extension = get_choice("Extension") == "true"; - bool save_as_svg1_1 = get_choice("SVG1.1") == "true"; - if (save_method == Inkscape::Extension::FILE_SAVE_METHOD_SAVE_COPY) { - prefs->setBool("/dialogs/save_copy/append_extension", append_extension); - prefs->setBool("/dialogs/save_copy/enable_svgexport", save_as_svg1_1); - } else { - prefs->setBool("/dialogs/save_as/append_extension", append_extension); - prefs->setBool("/dialogs/save_as/enable_svgexport", save_as_svg1_1); - } - - auto extension = getExtension(); - Inkscape::Extension::store_file_extension_in_prefs((extension != nullptr ? extension->get_id() : ""), save_method); - return true; - } - - return false; -} // show() - -// Given filename, find module for saving. If found, update all. -bool FileSaveDialogImplGtk::setExtension(Glib::ustring const &filename_utf8) -{ - // Find module - Glib::ustring filename_folded = filename_utf8.casefold(); - Inkscape::Extension::Extension* key = nullptr; - for (auto const &iter : knownExtensions) { - auto ext = Glib::ustring(iter.second->get_extension()).casefold(); - if (Glib::str_has_suffix(filename_folded, ext)) { - key = iter.second; - } - } - - if (key) { - // Update all. - setExtension(key); - return true; - } - - // This happens when saving shortcuts. - // std::cerr << "FileSaveDialogImpGtk: no extension to handle this file type: " << filename_utf8 << std::endl; - return false; -} - -// Given module, set filter and filename (if required). -// If module is null, try to find module from current name. -void FileSaveDialogImplGtk::setExtension(Inkscape::Extension::Extension *key) -{ - if (!key) { - // Try to use filename, return if successful - if (setExtension(get_current_name())) { - return; - } - } - - // Save module. - FileDialog::setExtension(key); - setFilterFromExtension(key); - setFilenameFromExtension(key); -} - -void FileSaveDialogImplGtk::setFilterFromExtension(Inkscape::Extension::Extension *key) -{ - if (key) { - set_filter(extensionFilterMap[key]); - } -} - -void FileSaveDialogImplGtk::setFilenameFromExtension(Inkscape::Extension::Extension *key) -{ - auto filename_utf8 = get_current_name(); // UTF8 encoded! - auto output = dynamic_cast(getExtension()); - if (output && get_choice("Extension") == "true") { - // Append the file extension if it's not already present and display it in the file name entry field. - appendExtension(filename_utf8, output); - set_current_name(filename_utf8); - } -} - -void FileSaveDialogImplGtk::createFilterMenu() -{ - Inkscape::Extension::DB::OutputList extension_list; - Inkscape::Extension::db.get_output_list(extension_list); - knownExtensions.clear(); - - addFilter(_("Guess from extension"), "*"); // No output module! - - for (auto omod : extension_list) { - // Export types are either exported vector types, or any raster type. - if (!omod->is_exported() && omod->is_raster() != (_dialogType == EXPORT_TYPES)) - continue; - - // This extension is limited to save copy only. - if (omod->savecopy_only() && save_method != Inkscape::Extension::FILE_SAVE_METHOD_SAVE_COPY) - continue; - - Glib::ustring extension = omod->get_extension(); - addFilter(omod->get_filetypename(true), extension, omod); - knownExtensions.insert(std::pair(extension.casefold(), omod)); - } -} - -/** - * Callback for filefilter. - */ -void FileSaveDialogImplGtk::filefilterChanged() -{ - auto key = filterExtensionMap[get_filter()]; - FileDialog::setExtension(key); - setFilenameFromExtension(key); -} - -/** - * Called when user types in filename entry. - * Updates filter dropdown and extension module to match filename. - */ -void FileSaveDialogImplGtk::filenameChanged() { - - Glib::ustring filename_utf8 = get_current_name(); - - // Find filename extension. - Glib::ustring::size_type pos = filename_utf8.rfind('.'); - if ( pos == Glib::ustring::npos ) { - // No extension. - return; - } - Glib::ustring ext = filename_utf8.substr( pos ).casefold(); - - if (auto output = dynamic_cast(getExtension())) { - if (Glib::ustring(output->get_extension()).casefold() == ext) { - // Extension already set correctly. - return; - } - } - - // This does not include bitmap types for which one must use the Export dialog. - if (knownExtensions.find(ext) == knownExtensions.end()) { - // Unknown extension. This happens when typing in a new extension. - // std::cerr << "FileSaveDialogImplGtk::fileNameChanged: unknown extension: " << ext << std::endl; - return; - } - - auto key = knownExtensions[ext]; - FileDialog::setExtension(key); - setFilterFromExtension(key); -} - -} // namespace Inkscape::UI::Dialog - -/* - Local Variables: - mode:c++ - c-file-style:"stroustrup" - c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) - indent-tabs-mode:nil - fill-column:99 - End: -*/ -// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 : diff --git a/src/ui/dialog/filedialogimpl-gtkmm.h b/src/ui/dialog/filedialogimpl-gtkmm.h deleted file mode 100644 index b60b776cb7..0000000000 --- a/src/ui/dialog/filedialogimpl-gtkmm.h +++ /dev/null @@ -1,166 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/** @file - * @brief Implementation of the file dialog interfaces defined in filedialogimpl.h - */ -/* Authors: - * Bob Jamison - * Johan Engelen - * Joel Holdsworth - * Bruno Dilly - * Others from The Inkscape Organization - * - * Copyright (C) 2004-2008 Authors - * Copyright (C) 2004-2007 The Inkscape Organization - * - * Released under GNU GPL v2+, read the file 'COPYING' for more information. - */ - -#ifndef SEEN_FILE_DIALOG_IMPL_GTKMM_H -#define SEEN_FILE_DIALOG_IMPL_GTKMM_H - -#include -#include -#include -#include -#include - -#include "filedialog.h" - -namespace Gtk { -class Entry; -class FileFilter; -class Window; -} // namespace Gtk - -namespace Inkscape { - -class URI; - -namespace UI { - -namespace View { -class SVGViewWidget; -} // namespace View - -namespace Dialog { - -/*######################################################################### -### F I L E D I A L O G B A S E C L A S S -#########################################################################*/ - -/** - * This class is the base implementation for the others. This - * reduces redundancies and bugs. - */ -class FileDialogBaseGtk : public Gtk::FileChooserDialog -{ -public: - FileDialogBaseGtk(Gtk::Window &parentWindow, Glib::ustring const &title, - Gtk::FileChooser::Action dialogType, FileDialogType type, - char const *preferenceBase); - - ~FileDialogBaseGtk() override; - - /** - * Add a Gtk filter to our specially controlled filter dropdown. - */ - Glib::RefPtr addFilter(const Glib::ustring &name, Glib::ustring pattern = "", - Inkscape::Extension::Extension *mod = nullptr); - - Glib::ustring extToPattern(const Glib::ustring &extension) const; - -protected: - Glib::ustring const _preferenceBase; - - /** - * What type of 'open' are we? (open, import, place, etc) - */ - FileDialogType _dialogType; - - /** - * Maps extension <-> filter. - */ - std::map, Inkscape::Extension::Extension *> filterExtensionMap; - std::map> extensionFilterMap; -}; - - -//######################################################################## -//# F I L E S A V E -//######################################################################## - -/** - * Our implementation of the FileSaveDialog interface. - */ -class FileSaveDialogImplGtk final - : public FileSaveDialog - , public FileDialogBaseGtk -{ -public: - FileSaveDialogImplGtk(Gtk::Window &parentWindow, - const std::string &dir, - FileDialogType fileTypes, - const Glib::ustring &title, - const Glib::ustring &default_key, - const gchar* docTitle, - const Inkscape::Extension::FileSaveMethod save_method); - - bool show() final; - - // One at a time. - const Glib::RefPtr getFile() override { return get_file(); } - - void setCurrentName(Glib::ustring name) override { set_current_name(name); } - Glib::RefPtr getCurrentDirectory() override { return get_current_folder(); } - - // Sets module for saving, updating GUI if necessary. - bool setExtension(Glib::ustring const &filename_utf8); - void setExtension(Inkscape::Extension::Extension *key) override; - - void addFilterMenu(const Glib::ustring &name, Glib::ustring pattern = {}, - Inkscape::Extension::Extension *mod = nullptr) override - { - addFilter(name, pattern, mod); - } - -private: - /** - * The file save method (essentially whether the dialog was invoked by "Save as ..." or "Save a - * copy ..."), which is used to determine file extensions and save paths. - */ - Inkscape::Extension::FileSaveMethod save_method; - - /** - * Create a filter menu for this type of dialog - */ - void createFilterMenu(); - - /** - * Callback for filefilter. - */ - void filefilterChanged(); - void setFilterFromExtension(Inkscape::Extension::Extension *key); - - /** - * Callback for filename. - */ - void filenameChanged(); - void setFilenameFromExtension(Inkscape::Extension::Extension *key); -}; - -} // namespace Dialog -} // namespace UI -} // namespace Inkscape - -#endif // SEEN_FILE_DIALOG_IMPL_GTKMM_H - -/* - Local Variables: - mode:c++ - c-file-style:"stroustrup" - c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) - indent-tabs-mode:nil - fill-column:99 - End: -*/ -// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 : diff --git a/src/ui/widget/preferences-widget.cpp b/src/ui/widget/preferences-widget.cpp index 00e06323b0..eed5fd9c56 100644 --- a/src/ui/widget/preferences-widget.cpp +++ b/src/ui/widget/preferences-widget.cpp @@ -37,7 +37,6 @@ #include "io/sys.h" #include "ui/dialog/choose-file.h" #include "ui/dialog/choose-file-utils.h" -#include "ui/dialog/filedialog.h" #include "ui/icon-loader.h" #include "ui/pack.h" #include "ui/util.h" -- GitLab From 64eb6351d559517df07b8b3da5f70d100d55a595 Mon Sep 17 00:00:00 2001 From: Tavmjong Bah Date: Sat, 15 Mar 2025 20:21:05 +0100 Subject: [PATCH 09/11] Small tweek suggested by mkov. --- src/actions/actions-file-window.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/actions/actions-file-window.cpp b/src/actions/actions-file-window.cpp index 11ee0727e9..9e8a8dfc16 100644 --- a/src/actions/actions-file-window.cpp +++ b/src/actions/actions-file-window.cpp @@ -47,7 +47,7 @@ document_open(InkscapeWindow* win) // Open File Dialog auto files = Inkscape::choose_file_open_images(_("Select file(s) to open"), win, "/dialog/open/path", _("Open")); auto *app = InkscapeApplication::instance(); - for (auto file : files) { + for (auto& file : files) { app->create_window(file); } } -- GitLab From c54dd482d9a07252052cf52ad0e843f380760f00 Mon Sep 17 00:00:00 2001 From: Tavmjong Bah Date: Sat, 15 Mar 2025 20:25:52 +0100 Subject: [PATCH 10/11] Fix translations. --- po/POTFILES.src.in | 1 - 1 file changed, 1 deletion(-) diff --git a/po/POTFILES.src.in b/po/POTFILES.src.in index 23f0cf645a..4b7622c2a6 100644 --- a/po/POTFILES.src.in +++ b/po/POTFILES.src.in @@ -292,7 +292,6 @@ ${_build_dir}/share/templates/templates.h ../src/ui/dialog/export-single.cpp ../src/ui/dialog/export.cpp ../src/ui/dialog/extensions-gallery.cpp -../src/ui/dialog/filedialogimpl-gtkmm.cpp ../src/ui/dialog/fill-and-stroke.cpp ../src/ui/dialog/filter-effects-dialog.cpp ../src/ui/dialog/find.cpp -- GitLab From b2c21b5e0eb45e6ef3337b88c280337ef2b3abe5 Mon Sep 17 00:00:00 2001 From: Tavmjong Bah Date: Sat, 15 Mar 2025 21:08:50 +0100 Subject: [PATCH 11/11] Fix translations, try 2 (files correct but out of order). --- po/POTFILES.src.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/po/POTFILES.src.in b/po/POTFILES.src.in index 4b7622c2a6..50e24abeea 100644 --- a/po/POTFILES.src.in +++ b/po/POTFILES.src.in @@ -276,8 +276,8 @@ ${_build_dir}/share/templates/templates.h ../src/ui/desktop/menubar.cpp ../src/ui/dialog/attrdialog.cpp ../src/ui/dialog/calligraphic-profile-rename.cpp -../src/ui/dialog/choose-file.cpp ../src/ui/dialog/choose-file-utils.cpp +../src/ui/dialog/choose-file.cpp ../src/ui/dialog/clonetiler.cpp ../src/ui/dialog/color-item.cpp ../src/ui/dialog/command-palette.cpp -- GitLab