diff --git a/po/POTFILES.src.in b/po/POTFILES.src.in index 539da215648e71a372b26832d86a2467522ece80..50e24abeea2267c9b6e920ab529e0c21d0ca2187 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-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 @@ -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 @@ -317,6 +316,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/actions/actions-file-window.cpp b/src/actions/actions-file-window.cpp index ea22579cf59945a79abb712dc0746896836600c3..9e8a8dfc16bb2f455a5bc25d51d3c6d92db83118 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/extension/prefdialog/parameter-path.cpp b/src/extension/prefdialog/parameter-path.cpp index 58860e57422c8ce38027593f103cee45b68adac5..bce31f092a2b975456287ae8f39a0a15d9cc210c 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/file.cpp b/src/file.cpp index d399bc39daeee64e702dfdff57845d93731c5b91..549e914f6c900af7e7043fbbc0b678c9505cef40 100644 --- a/src/file.cpp +++ b/src/file.cpp @@ -65,7 +65,8 @@ #include "selection.h" #include "style.h" #include "svg/svg.h" // for sp_svg_transform_write, used in sp_import_document -#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/interface.h" #include "ui/tools/tool-base.h" @@ -153,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 @@ -385,43 +339,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(); @@ -431,7 +396,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; @@ -799,7 +764,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) @@ -996,52 +962,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 79a4ba7b5f0c15ae7e40da7747aba4f6c4ee65e3..980d240d7ddc54ce286a4eef364bbe73d532088e 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/helper/CMakeLists.txt b/src/helper/CMakeLists.txt index c47a1bf5f78c55af10f9205e35e27e96136cde1c..39207383c8fa97df5883747771cf262a5adc146b 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/helper/choose-file.cpp b/src/helper/choose-file.cpp deleted file mode 100644 index c338bc0237def56987578feae825159a33587ca9..0000000000000000000000000000000000000000 --- a/src/helper/choose-file.cpp +++ /dev/null @@ -1,176 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later - -#include "choose-file.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -namespace Inkscape { - -Glib::RefPtr create_file_dialog(Glib::ustring const &title, - Glib::ustring const &accept_label) -{ - auto const file_dialog = Gtk::FileDialog::create(); - file_dialog->set_title(title); - file_dialog->set_accept_label(accept_label); - return file_dialog; -} - -void set_filters(Gtk::FileDialog &file_dialog, - Glib::RefPtr> const &filters) -{ - file_dialog.set_filters(filters); - if (filters->get_n_items() > 0) { - file_dialog.set_default_filter(filters->get_item(0)); - } -} - -void set_filter(Gtk::FileDialog &file_dialog, Glib::RefPtr const &filter) -{ - auto const filters = Gio::ListStore::create(); - filters->append(filter); - set_filters(file_dialog, filters); -} - -using StartMethod = void (Gtk::FileDialog::*) - (Gtk::Window &, Gio::SlotAsyncReady const &, - Glib::RefPtr const &); - -using FinishMethod = Glib::RefPtr (Gtk::FileDialog::*) - (Glib::RefPtr const &); - -[[nodiscard]] static auto run(Gtk::FileDialog &file_dialog, Gtk::Window &parent, - std::string ¤t_folder, - StartMethod const start, FinishMethod const finish) -{ - file_dialog.set_initial_folder(Gio::File::create_for_path(current_folder)); - - bool responded = false; - std::string file_path; - - (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; - - current_folder = file->get_parent()->get_path(); - } 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 file_path; -} - -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) -{ - if (!parent) return {}; - - if (current_folder.empty()) { - current_folder = Glib::get_home_dir(); - } - - 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); - - file_dialog->set_initial_name(file_name); - - return run(*file_dialog, *parent, current_folder, - &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 {}; - - if (current_folder.empty()) { - current_folder = Glib::get_home_dir(); - } - - auto const file_dialog = create_file_dialog(title, _("Open")); - - 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); - } - 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) -{ - return _choose_file_open(title, parent, {}, mime_types, current_folder); -} - -std::string choose_file_open(Glib::ustring const &title, Gtk::Window *parent, - std::vector> const &filters, - std::string ¤t_folder) -{ - return _choose_file_open(title, parent, filters, {}, current_folder); -} - -} // namespace Inkscape - -/* - 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/helper/choose-file.h b/src/helper/choose-file.h deleted file mode 100644 index 553654de1844a4c0093e6d011ca169ea761683ce..0000000000000000000000000000000000000000 --- a/src/helper/choose-file.h +++ /dev/null @@ -1,76 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later - -#ifndef SEEN_CHOOSE_FILE_H -#define SEEN_CHOOSE_FILE_H - -#include -#include -#include -#include - -namespace Glib { -class ustring; -} // namespace Glib - -namespace Gio { -template class ListStore; -} // namespace Gio - -namespace Gtk { -class FileDialog; -class FileFilter; -class Window; -} // namespace Gtk - -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); - -/// 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. -/// @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 -[[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); - -/// 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 -[[nodiscard]] -std::string choose_file_open(Glib::ustring const &title, Gtk::Window *parent, - std::vector const &mime_types, - std::string& current_folder); -/// 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 -[[nodiscard]] -std::string choose_file_open(Glib::ustring const &title, Gtk::Window *parent, - std::vector> const &filters, - std::string& current_folder); - -} // namespace Inkscape - -#endif // SEEN_CHOOSE_FILE_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/CMakeLists.txt b/src/ui/CMakeLists.txt index 11b01a92a3806f05741f7277e06a208c3dffaf69..df176e03431ccbf30a5b47adb1941b7a8799563c 100644 --- a/src/ui/CMakeLists.txt +++ b/src/ui/CMakeLists.txt @@ -113,12 +113,15 @@ 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/choose-file-utils.cpp dialog/dialog-base.cpp dialog/dialog-container.cpp dialog/dialog-data.cpp @@ -132,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 @@ -158,6 +159,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 +331,8 @@ set(ui_SRC dialog/align-and-distribute.h 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 @@ -347,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 @@ -373,6 +375,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/ui/dialog/choose-file-utils.cpp b/src/ui/dialog/choose-file-utils.cpp new file mode 100644 index 0000000000000000000000000000000000000000..838635cd37a644d0aa422d672c19a7621a231e61 --- /dev/null +++ b/src/ui/dialog/choose-file-utils.cpp @@ -0,0 +1,214 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "choose-file-utils.h" + +#include + +#include +#include // Glib::FileTest +#include +#include // Glib::get_home_dir(), etc. +#include + +#include "preferences.h" + +#include "extension/db.h" +#include "extension/input.h" +#include "extension/output.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(); + } +} + +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; +} + +// 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(bool for_save) { + + 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) { + + // 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! + } + 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); + + + // 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 + +/* + 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 0000000000000000000000000000000000000000..3572d3c2f1e0c3ea1f6b39dc0bf00a73c9680c89 --- /dev/null +++ b/src/ui/dialog/choose-file-utils.h @@ -0,0 +1,48 @@ +// 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 Gio { +template class ListStore; +} // namespace Gio + +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); + +/// 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(bool for_save = 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/choose-file.cpp b/src/ui/dialog/choose-file.cpp new file mode 100644 index 0000000000000000000000000000000000000000..f0500e93a863fd94cff0eb83cee38f085b0e8586 --- /dev/null +++ b/src/ui/dialog/choose-file.cpp @@ -0,0 +1,257 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "choose-file.h" + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "preferences.h" +#include "choose-file-utils.h" + +namespace Inkscape { + +Glib::RefPtr create_file_dialog(Glib::ustring const &title, + Glib::ustring const &accept_label) +{ + auto const file_dialog = Gtk::FileDialog::create(); + file_dialog->set_title(title); + file_dialog->set_accept_label(accept_label); + return file_dialog; +} + +void set_filters(Gtk::FileDialog &file_dialog, + Glib::RefPtr> const &filters) +{ + file_dialog.set_filters(filters); + if (filters->get_n_items() > 0) { + file_dialog.set_default_filter(filters->get_item(0)); + } +} + +void set_filter(Gtk::FileDialog &file_dialog, Glib::RefPtr const &filter) +{ + auto const filters = Gio::ListStore::create(); + filters->append(filter); + set_filters(file_dialog, filters); +} + +using StartMethod = void (Gtk::FileDialog::*) + (Gtk::Window &, Gio::SlotAsyncReady const &, + Glib::RefPtr const &); + +using FinishMethod = Glib::RefPtr (Gtk::FileDialog::*) + (Glib::RefPtr const &); + +[[nodiscard]] static auto run(Gtk::FileDialog &file_dialog, Gtk::Window &parent, + std::string ¤t_folder, + StartMethod const start, FinishMethod const finish) +{ + file_dialog.set_initial_folder(Gio::File::create_for_path(current_folder)); + + bool responded = false; + Glib::RefPtr file; + + (file_dialog.*start)(parent, [&](Glib::RefPtr const &result) + { + try { + responded = true; + + file = (file_dialog.*finish)(result); + if (!file) { + return; + } + + current_folder = file->get_parent()->get_path(); + } 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 file; +} + +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) +{ + if (!parent) return {}; + + if (current_folder.empty()) { + current_folder = Glib::get_home_dir(); + } + + auto const file_dialog = create_file_dialog(title, _("Save")); + + 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); + + return run(*file_dialog, *parent, current_folder, + &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, + 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, accept.empty() ? _("Open") : accept); + + if (filters_model) { + set_filters(*file_dialog, filters_model); + } + + return run(*file_dialog, *parent, current_folder, + &Gtk::FileDialog::open, &Gtk::FileDialog::open_finish); +} + +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) +{ + 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); +} + +Glib::RefPtr choose_file_open(Glib::ustring const &title, Gtk::Window *parent, + std::vector> const &filters, + std::string ¤t_folder, + Glib::ustring const &accept) +{ + 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); +} + +// 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: + 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.h b/src/ui/dialog/choose-file.h new file mode 100644 index 0000000000000000000000000000000000000000..1c58dd337b83d21528e2c23f8d04014240d9c653 --- /dev/null +++ b/src/ui/dialog/choose-file.h @@ -0,0 +1,110 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + +#ifndef SEEN_CHOOSE_FILE_H +#define SEEN_CHOOSE_FILE_H + +#include +#include +#include +#include +#include + +namespace Gio { +template class ListStore; +class File; +} // namespace Gio + +namespace Gtk { +class FileDialog; +class FileFilter; +class Window; +} // namespace Gtk + +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); + +/// 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. +/// @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::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. +/// @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 Gio::File for selected file. +[[nodiscard]] +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 Gio::File for selected file. +[[nodiscard]] +Glib::RefPtr choose_file_open(Glib::ustring const &title, Gtk::Window *parent, + std::vector> const &filters, + 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 + +/* + 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 5bf3cdaf729fae9f9f75aef2cb718ad9fff9678d..7d75af9a0a2b8d1a55d1560af2cc425bb736f5c5 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 @@ -69,12 +70,13 @@ #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" #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" @@ -1122,8 +1124,6 @@ void DocumentProperties::addExternalScript(){ } } -static Inkscape::UI::Dialog::FileOpenDialog * selectPrefsFileInstance = nullptr; - void DocumentProperties::browseExternalScript() { // Get the current directory for finding files. @@ -1131,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/document-resources.cpp b/src/ui/dialog/document-resources.cpp index 8d329f8825a75b06945bca47b7c852ceb178223d..c22ac665e2dfbe056b6fb716879383c6b9adbfd9 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/export-single.cpp b/src/ui/dialog/export-single.cpp index 7b9c3cf02231a182b38cd488209b739da3719879..9f7326dbf7564dcced0e4f083e0d57cf5cf967cf 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/dialog/filedialog.cpp b/src/ui/dialog/filedialog.cpp deleted file mode 100644 index 22faa715ab6c49c7392ce6b715851480aa894b22..0000000000000000000000000000000000000000 --- a/src/ui/dialog/filedialog.cpp +++ /dev/null @@ -1,198 +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; -} - -// 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! - 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 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 -//######################################################################## - -/** - * 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 67c37864a47a6434c9ff86221477532c31f0079f..0000000000000000000000000000000000000000 --- a/src/ui/dialog/filedialog.h +++ /dev/null @@ -1,208 +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); - -/** - * 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. - */ -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 "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. - */ -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 2e69eb2f6ae897c67c3467017607dba86d78bd35..0000000000000000000000000000000000000000 --- a/src/ui/dialog/filedialogimpl-gtkmm.cpp +++ /dev/null @@ -1,497 +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 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 -//######################################################################## - -/** - * 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 2dd8de432466ba2e502b48b55718bc84b38b0c41..0000000000000000000000000000000000000000 --- a/src/ui/dialog/filedialogimpl-gtkmm.h +++ /dev/null @@ -1,210 +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 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 -//######################################################################## - -/** - * 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/dialog/filter-effects-dialog.cpp b/src/ui/dialog/filter-effects-dialog.cpp index e1c8cd014e46f1219095f0d2fbaa7d85239dcb33..60e72f6276f8f834dbb0ae198c3370a346b4de58 100644 --- a/src/ui/dialog/filter-effects-dialog.cpp +++ b/src/ui/dialog/filter-effects-dialog.cpp @@ -83,7 +83,8 @@ #include "ui/builder-utils.h" #include "ui/column-menu-builder.h" #include "ui/controller.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/pack.h" #include "ui/util.h" @@ -573,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 @@ -640,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/global-palettes.cpp b/src/ui/dialog/global-palettes.cpp index dd4b5fd5d0c7b919af4a385c5bfa165e71aae5d2..f525c40947b3ab0c9418d33aec58206739687900 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 017961ff6c89999484db660f532e7b6eadc2dd1b..2937153ae1f0a4a4ab54ae17a3dfbadc510953e0 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 eca667bd1906b8dbd1f0196767fc76a10013d292..6e08174bf6f7748175fe6aaac27b504426902d3e 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/startup.cpp b/src/ui/dialog/startup.cpp index 10708bea847e8755a1794e82ea90c85f74e8f4cf..1c12761f73a7250a64d8da55c3973a31ad22a012 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,7 +44,8 @@ #include "preferences.h" #include "ui/builder-utils.h" #include "ui/controller.h" -#include "ui/dialog/filedialog.h" +#include "ui/dialog/choose-file.h" +#include "ui/dialog/choose-file-utils.h" #include "ui/shortcuts.h" #include "ui/themes.h" #include "ui/util.h" @@ -402,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/dialog/swatches.cpp b/src/ui/dialog/swatches.cpp index 41d99ec8e1662f5fe60bbf6960876988e88fe578..c9256f4b2fab32fac10bc7d25eb1f4bea2191fa4 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/shortcuts.cpp b/src/ui/shortcuts.cpp index 2dfe345b96bf357a07891c9dcd8e024e5f9a15b7..ad832f42882a8d1f40f54e7640e6c20ee4115720 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; }; diff --git a/src/ui/widget/export-lists.cpp b/src/ui/widget/export-lists.cpp index 65a95e485911f3a23e0e01c49fa668bcd7c2ad12..63c945c3bd05105857a433fa664acae6c6f769d4 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; diff --git a/src/ui/widget/image-properties.cpp b/src/ui/widget/image-properties.cpp index 8bc781838952e4ead6346df674f2a40d2476046d..71df9f31be9389552fcedbd215344457eade8371 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 01f68a4deda98a96365945ff95d6f58614bd6be5..eed5fd9c56111104b0e2c1f3d2426b1503f795dc 100644 --- a/src/ui/widget/preferences-widget.cpp +++ b/src/ui/widget/preferences-widget.cpp @@ -35,7 +35,8 @@ #include "selection-chemistry.h" #include "include/gtkmm_version.h" #include "io/sys.h" -#include "ui/dialog/filedialog.h" +#include "ui/dialog/choose-file.h" +#include "ui/dialog/choose-file-utils.h" #include "ui/icon-loader.h" #include "ui/pack.h" #include "ui/util.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()); } }