diff --git a/app/plug-in/gimpplugin-proc.c b/app/plug-in/gimpplugin-proc.c index 8d88ea1597..dc66d314fa 100644 --- a/app/plug-in/gimpplugin-proc.c +++ b/app/plug-in/gimpplugin-proc.c @@ -292,8 +292,11 @@ GIMP_IS_PARAM_SPEC_RUN_MODE (GParamSpec *pspec) } static inline gboolean -GIMP_IS_PARAM_SPEC_FILE (GParamSpec *pspec) +gimp_plug_in_is_file_spec (GParamSpec *pspec) { + /* This will work both for GimpParamSpecFile specs and + * GParamSpecObject with a GFile value. + */ return (G_IS_PARAM_SPEC_OBJECT (pspec) && pspec->value_type == G_TYPE_FILE); } @@ -334,7 +337,7 @@ gimp_plug_in_set_file_proc_load_handler (GimpPlugIn *plug_in, if (((procedure->num_args < 2) || (procedure->num_values < 1) || ! GIMP_IS_PARAM_SPEC_RUN_MODE (procedure->args[0]) || - ! GIMP_IS_PARAM_SPEC_FILE (procedure->args[1]) || + ! gimp_plug_in_is_file_spec (procedure->args[1]) || (! proc->generic_file_proc && ! GIMP_IS_PARAM_SPEC_IMAGE (procedure->values[0])))) { @@ -393,7 +396,7 @@ gimp_plug_in_set_file_proc_save_handler (GimpPlugIn *plug_in, if ((procedure->num_args < 4) || ! GIMP_IS_PARAM_SPEC_RUN_MODE (procedure->args[0]) || ! GIMP_IS_PARAM_SPEC_IMAGE (procedure->args[1]) || - ! GIMP_IS_PARAM_SPEC_FILE (procedure->args[2]) || + ! gimp_plug_in_is_file_spec (procedure->args[2]) || ! GIMP_IS_PARAM_SPEC_EXPORT_OPTIONS (procedure->args[3])) { g_set_error (error, GIMP_PDB_ERROR, GIMP_PDB_ERROR_FAILED, @@ -592,7 +595,7 @@ gimp_plug_in_set_file_proc_handles_vector (GimpPlugIn *plug_in, if (procedure->num_args < 4 || procedure->num_values < 1 || ! GIMP_IS_PARAM_SPEC_RUN_MODE (procedure->args[0]) || - ! GIMP_IS_PARAM_SPEC_FILE (procedure->args[1]) || + ! gimp_plug_in_is_file_spec (procedure->args[1]) || ! G_IS_PARAM_SPEC_INT (procedure->args[2]) || ! G_IS_PARAM_SPEC_INT (procedure->args[3]) || ! GIMP_IS_PARAM_SPEC_IMAGE (procedure->values[0])) diff --git a/app/plug-in/gimppluginprocedure.c b/app/plug-in/gimppluginprocedure.c index 8b03156086..67289824f9 100644 --- a/app/plug-in/gimppluginprocedure.c +++ b/app/plug-in/gimppluginprocedure.c @@ -447,13 +447,6 @@ GIMP_IS_PARAM_SPEC_RUN_MODE (GParamSpec *pspec) pspec->value_type == GIMP_TYPE_RUN_MODE); } -static inline gboolean -GIMP_IS_PARAM_SPEC_FILE (GParamSpec *pspec) -{ - return (G_IS_PARAM_SPEC_OBJECT (pspec) && - pspec->value_type == G_TYPE_FILE); -} - static gboolean gimp_plug_in_procedure_validate_args (GimpPlugInProcedure *proc, Gimp *gimp, diff --git a/app/plug-in/plug-in-rc.c b/app/plug-in/plug-in-rc.c index f4550da692..ddf632fc28 100644 --- a/app/plug-in/plug-in-rc.c +++ b/app/plug-in/plug-in-rc.c @@ -1014,6 +1014,22 @@ plug_in_proc_arg_deserialize (GScanner *scanner, goto error; } break; + + case GP_PARAM_DEF_TYPE_FILE: + if (! gimp_scanner_parse_int (scanner, + (gint *) ¶m_def.meta.m_file.action) || + ! gimp_scanner_parse_int (scanner, + ¶m_def.meta.m_file.none_ok)) + { + token = G_TOKEN_INT; + goto error; + } + if (! gimp_scanner_parse_string (scanner, + ¶m_def.meta.m_file.default_uri)) + { + token = G_TOKEN_STRING; + goto error; + } break; } @@ -1082,6 +1098,10 @@ plug_in_proc_arg_deserialize (GScanner *scanner, case GP_PARAM_DEF_TYPE_RESOURCE: break; + + case GP_PARAM_DEF_TYPE_FILE: + g_free (param_def.meta.m_file.default_uri); + break; } return token; @@ -1273,6 +1293,14 @@ plug_in_rc_write_proc_arg (GimpConfigWriter *writer, param_def.meta.m_resource.default_to_context, param_def.meta.m_resource.default_resource_id); break; + + case GP_PARAM_DEF_TYPE_FILE: + gimp_config_writer_printf (writer, "%d %d", + param_def.meta.m_file.action, + param_def.meta.m_file.none_ok); + gimp_config_writer_string (writer, + param_def.meta.m_file.default_uri); + break; } gimp_config_writer_close (writer); diff --git a/libgimp/gimpenums.c.tail b/libgimp/gimpenums.c.tail index b16091c31b..fee13c8dbf 100644 --- a/libgimp/gimpenums.c.tail +++ b/libgimp/gimpenums.c.tail @@ -21,6 +21,7 @@ static const GimpGetTypeFunc get_type_funcs[] = gimp_desaturate_mode_get_type, gimp_dodge_burn_type_get_type, gimp_export_capabilities_get_type, + gimp_file_chooser_action_get_type, gimp_fill_type_get_type, gimp_foreground_extract_mode_get_type, gimp_gradient_blend_color_space_get_type, @@ -86,6 +87,7 @@ static const gchar * const type_names[] = "GimpDesaturateMode", "GimpDodgeBurnType", "GimpExportCapabilities", + "GimpFileChooserAction", "GimpFillType", "GimpForegroundExtractMode", "GimpGradientBlendColorSpace", diff --git a/libgimp/gimpexportprocedure.c b/libgimp/gimpexportprocedure.c index 5fb39347e5..a5d1dae414 100644 --- a/libgimp/gimpexportprocedure.c +++ b/libgimp/gimpexportprocedure.c @@ -248,6 +248,8 @@ gimp_export_procedure_constructed (GObject *object) gimp_procedure_add_file_argument (procedure, "file", "File", "The file to export to", + GIMP_FILE_CHOOSER_ACTION_SAVE, + FALSE, NULL, GIMP_PARAM_READWRITE); _gimp_procedure_add_argument (procedure, diff --git a/libgimp/gimpgpparams-body.c b/libgimp/gimpgpparams-body.c index bd124e9075..6808bbdd3e 100644 --- a/libgimp/gimpgpparams-body.c +++ b/libgimp/gimpgpparams-body.c @@ -340,6 +340,25 @@ _gimp_gp_param_def_to_param_spec (const GPParamDef *param_def) flags); break; + + case GP_PARAM_DEF_TYPE_FILE: + if (! strcmp (param_def->type_name, "GimpParamFile")) + { + GFile *file = NULL; + GParamSpec *pspec; + + if (param_def->meta.m_file.default_uri && + strlen (param_def->meta.m_file.default_uri) > 0) + file = g_file_new_for_uri (param_def->meta.m_file.default_uri); + + pspec = gimp_param_spec_file (name, nick, blurb, + param_def->meta.m_file.action, + param_def->meta.m_file.none_ok, + file, flags); + g_clear_object (&file); + return pspec; + } + break; } g_warning ("%s: GParamSpec type unsupported '%s'", G_STRFUNC, @@ -647,6 +666,17 @@ _gimp_param_spec_to_gp_param_def (GParamSpec *pspec, else param_def->meta.m_resource.default_resource_id = 0; } + else if (pspec_type == GIMP_TYPE_PARAM_FILE) + { + GimpParamSpecFile *fspec = GIMP_PARAM_SPEC_FILE (pspec); + GimpParamSpecObject *ospec = GIMP_PARAM_SPEC_OBJECT (pspec); + + param_def->param_def_type = GP_PARAM_DEF_TYPE_FILE; + + param_def->meta.m_file.none_ok = fspec->none_ok; + param_def->meta.m_file.default_uri = + ospec->_default_value ? g_file_get_uri (G_FILE (ospec->_default_value)) : NULL; + } else if (GIMP_IS_PARAM_SPEC_CORE_OBJECT_ARRAY (pspec)) { param_def->param_def_type = GP_PARAM_DEF_TYPE_ID_ARRAY; diff --git a/libgimp/gimploadprocedure.c b/libgimp/gimploadprocedure.c index 5edc221bb2..86bfc700ae 100644 --- a/libgimp/gimploadprocedure.c +++ b/libgimp/gimploadprocedure.c @@ -114,6 +114,8 @@ gimp_load_procedure_constructed (GObject *object) gimp_procedure_add_file_argument (procedure, "file", "File", "The file to load", + GIMP_FILE_CHOOSER_ACTION_OPEN, + FALSE, NULL, GIMP_PARAM_READWRITE); gimp_procedure_add_image_return_value (procedure, "image", diff --git a/libgimp/gimpprocedure-params.c b/libgimp/gimpprocedure-params.c index 4c7c6884b1..6cae4bb354 100644 --- a/libgimp/gimpprocedure-params.c +++ b/libgimp/gimpprocedure-params.c @@ -2276,50 +2276,64 @@ gimp_procedure_add_path_return_value (GimpProcedure *procedure, /** * gimp_procedure_add_file_argument: - * @procedure: the #GimpProcedure. - * @name: the name of the argument to be created. - * @nick: the label used in #GimpProcedureDialog. - * @blurb: a more detailed help description. - * @flags: argument flags. + * @procedure: The #GimpProcedure. + * @name: The name of the argument to be created. + * @nick: The label used in #GimpProcedureDialog. + * @blurb: A more detailed help description. + * @action: The type of file to expect. + * @none_ok: Whether %NULL is allowed. + * @default_file: (nullable): File to use if none is assigned. + * @flags: Argument flags. * * Add a new #GFile argument to @procedure. * * Since: 3.0 **/ void -gimp_procedure_add_file_argument (GimpProcedure *procedure, - const gchar *name, - const gchar *nick, - const gchar *blurb, - GParamFlags flags) +gimp_procedure_add_file_argument (GimpProcedure *procedure, + const gchar *name, + const gchar *nick, + const gchar *blurb, + GimpFileChooserAction action, + gboolean none_ok, + GFile *default_file, + GParamFlags flags) { _gimp_procedure_add_argument (procedure, - g_param_spec_object (name, nick, blurb, - G_TYPE_FILE, flags)); + gimp_param_spec_file (name, nick, blurb, + action, none_ok, + default_file, flags)); } /** * gimp_procedure_add_file_aux_argument: - * @procedure: the #GimpProcedure. - * @name: the name of the argument to be created. - * @nick: the label used in #GimpProcedureDialog. - * @blurb: a more detailed help description. - * @flags: argument flags. + * @procedure: The #GimpProcedure. + * @name: The name of the argument to be created. + * @nick: The label used in #GimpProcedureDialog. + * @blurb: A more detailed help description. + * @action: The type of file to expect. + * @none_ok: Whether %NULL is allowed. + * @default_file: (nullable): File to use if none is assigned. + * @flags: Argument flags. * * Add a new #GFile auxiliary argument to @procedure. * * Since: 3.0 **/ void -gimp_procedure_add_file_aux_argument (GimpProcedure *procedure, - const gchar *name, - const gchar *nick, - const gchar *blurb, - GParamFlags flags) +gimp_procedure_add_file_aux_argument (GimpProcedure *procedure, + const gchar *name, + const gchar *nick, + const gchar *blurb, + GimpFileChooserAction action, + gboolean none_ok, + GFile *default_file, + GParamFlags flags) { _gimp_procedure_add_aux_argument (procedure, - g_param_spec_object (name, nick, blurb, - G_TYPE_FILE, flags)); + gimp_param_spec_file (name, nick, blurb, + action, none_ok, + default_file, flags)); } /** @@ -2342,8 +2356,9 @@ gimp_procedure_add_file_return_value (GimpProcedure *procedure, GParamFlags flags) { _gimp_procedure_add_return_value (procedure, - g_param_spec_object (name, nick, blurb, - G_TYPE_FILE, flags)); + gimp_param_spec_file (name, nick, blurb, + GIMP_FILE_CHOOSER_ACTION_ANY, + TRUE, NULL, flags)); } /** diff --git a/libgimp/gimpprocedure-params.h b/libgimp/gimpprocedure-params.h index 7bbea010e0..8e455a55a2 100644 --- a/libgimp/gimpprocedure-params.h +++ b/libgimp/gimpprocedure-params.h @@ -994,21 +994,27 @@ void gimp_procedure_add_path_return_value (GimpProcedure *procedure gboolean none_ok, GParamFlags flags); -void gimp_procedure_add_file_argument (GimpProcedure *procedure, - const gchar *name, - const gchar *nick, - const gchar *blurb, - GParamFlags flags); -void gimp_procedure_add_file_aux_argument (GimpProcedure *procedure, - const gchar *name, - const gchar *nick, - const gchar *blurb, - GParamFlags flags); -void gimp_procedure_add_file_return_value (GimpProcedure *procedure, - const gchar *name, - const gchar *nick, - const gchar *blurb, - GParamFlags flags); +void gimp_procedure_add_file_argument (GimpProcedure *procedure, + const gchar *name, + const gchar *nick, + const gchar *blurb, + GimpFileChooserAction action, + gboolean none_ok, + GFile *default_value, + GParamFlags flags); +void gimp_procedure_add_file_aux_argument (GimpProcedure *procedure, + const gchar *name, + const gchar *nick, + const gchar *blurb, + GimpFileChooserAction action, + gboolean none_ok, + GFile *default_value, + GParamFlags flags); +void gimp_procedure_add_file_return_value (GimpProcedure *procedure, + const gchar *name, + const gchar *nick, + const gchar *blurb, + GParamFlags flags); void gimp_procedure_add_resource_argument (GimpProcedure *procedure, const gchar *name, diff --git a/libgimp/gimpproceduredialog.c b/libgimp/gimpproceduredialog.c index b7f198f328..24545661a7 100644 --- a/libgimp/gimpproceduredialog.c +++ b/libgimp/gimpproceduredialog.c @@ -657,11 +657,14 @@ gimp_procedure_dialog_set_ok_label (GimpProcedureDialog *dialog, * non-editable color area with a label. * * %GIMP_TYPE_COLOR_BUTTON: a color button with no label. * * %GIMP_TYPE_COLOR_AREA: a color area with no label. + * - %GIMP_TYPE_PARAM_FILE: + * * %GTK_FILE_CHOOSER_BUTTON (default): generic file chooser widget + * using the action mode of the param spec. * - %G_TYPE_PARAM_FILE: * * %GTK_FILE_CHOOSER_BUTTON (default): generic file chooser button - * in %GTK_FILE_CHOOSER_ACTION_OPEN mode. Please use - * gimp_procedure_dialog_get_file_chooser() to create buttons in - * other modes. + * in %GTK_FILE_CHOOSER_ACTION_OPEN mode. Please use + * [method@ProcedureDialog.get_file_chooser] to create buttons in + * other modes or better, use a %GIMP_TYPE_PARAM_FILE argument. * * If the @widget_type is not supported for the actual type of * @property, the function will fail. To keep the default, set to @@ -837,6 +840,13 @@ gimp_procedure_dialog_get_widget (GimpProcedureDialog *dialog, gtk_widget_set_hexpand (widget, FALSE); } } + else if (GIMP_IS_PARAM_SPEC_FILE (pspec)) + { + GimpParamSpecFile *fspec = GIMP_PARAM_SPEC_FILE (pspec); + + widget = gimp_procedure_dialog_get_file_chooser (dialog, property, + (GtkFileChooserAction) fspec->action); + } else if (G_IS_PARAM_SPEC_OBJECT (pspec) && pspec->value_type == G_TYPE_FILE) { widget = gimp_prop_file_chooser_button_new (G_OBJECT (priv->config), @@ -1618,6 +1628,12 @@ gimp_procedure_dialog_get_label (GimpProcedureDialog *dialog, * If a widget has already been created for this procedure, it will be * returned instead (whatever its actual widget type). * + * Note: it doesn't work for [enum@Gtk.FileChooserAction.SAVE] and + * [enum@Gtk.FileChooserAction.CREATE_FOLDER] @action yet. + * + * As for [enum@Gimp.FileChooserAction.ANY], it should never be used for + * a procedure argument if you intend to display a widget for it. + * * Returns: (transfer none): the #GtkWidget representing @property. The * object belongs to @dialog and must not be * freed. @@ -1633,6 +1649,9 @@ gimp_procedure_dialog_get_file_chooser (GimpProcedureDialog *dialog, g_return_val_if_fail (GIMP_IS_PROCEDURE_DIALOG (dialog), NULL); g_return_val_if_fail (property != NULL, NULL); + g_return_val_if_fail (action != GIMP_FILE_CHOOSER_ACTION_ANY && + action != GIMP_FILE_CHOOSER_ACTION_SAVE && + action != GIMP_FILE_CHOOSER_ACTION_CREATE_FOLDER, NULL); priv = gimp_procedure_dialog_get_instance_private (dialog); pspec = g_object_class_find_property (G_OBJECT_GET_CLASS (priv->config), @@ -1646,7 +1665,7 @@ gimp_procedure_dialog_get_file_chooser (GimpProcedureDialog *dialog, } g_return_val_if_fail (GIMP_IS_PARAM_SPEC_CONFIG_PATH (pspec) || - (G_IS_PARAM_SPEC_OBJECT (pspec) && pspec->value_type == G_TYPE_FILE), + (G_IS_PARAM_SPEC_OBJECT (pspec) && pspec->value_type == G_TYPE_FILE), NULL); /* First check if it already exists. */ diff --git a/libgimp/gimpthumbnailprocedure.c b/libgimp/gimpthumbnailprocedure.c index d31cb2f6ec..342bf82c0f 100644 --- a/libgimp/gimpthumbnailprocedure.c +++ b/libgimp/gimpthumbnailprocedure.c @@ -85,6 +85,8 @@ gimp_thumbnail_procedure_constructed (GObject *object) gimp_procedure_add_file_argument (procedure, "file", "File", "The file to load the thumbnail from", + GIMP_FILE_CHOOSER_ACTION_OPEN, + FALSE, NULL, GIMP_PARAM_READWRITE); gimp_procedure_add_int_argument (procedure, "thumb-size", diff --git a/libgimpbase/gimpbase.def b/libgimpbase/gimpbase.def index 6ffe519ddd..b3af9507fe 100644 --- a/libgimpbase/gimpbase.def +++ b/libgimpbase/gimpbase.def @@ -62,6 +62,7 @@ EXPORTS gimp_escape_uline gimp_export_capabilities_get_type gimp_export_options_get_type + gimp_file_chooser_action_get_type gimp_file_get_utf8_name gimp_file_has_extension gimp_file_show_in_file_manager @@ -132,6 +133,7 @@ EXPORTS gimp_param_core_object_array_get_type gimp_param_double_array_get_type gimp_param_export_options_get_type + gimp_param_file_get_type gimp_param_int32_array_get_type gimp_param_memsize_get_type gimp_param_object_get_type @@ -141,6 +143,7 @@ EXPORTS gimp_param_spec_core_object_array gimp_param_spec_double_array gimp_param_spec_export_options + gimp_param_spec_file gimp_param_spec_int32_array gimp_param_spec_memsize gimp_param_spec_object_duplicate diff --git a/libgimpbase/gimpbaseenums.c b/libgimpbase/gimpbaseenums.c index 490e08b1e5..eee17911a9 100644 --- a/libgimpbase/gimpbaseenums.c +++ b/libgimpbase/gimpbaseenums.c @@ -1960,6 +1960,42 @@ gimp_export_capabilities_get_type (void) return type; } +GType +gimp_file_chooser_action_get_type (void) +{ + static const GEnumValue values[] = + { + { GIMP_FILE_CHOOSER_ACTION_ANY, "GIMP_FILE_CHOOSER_ACTION_ANY", "any" }, + { GIMP_FILE_CHOOSER_ACTION_OPEN, "GIMP_FILE_CHOOSER_ACTION_OPEN", "open" }, + { GIMP_FILE_CHOOSER_ACTION_SAVE, "GIMP_FILE_CHOOSER_ACTION_SAVE", "save" }, + { GIMP_FILE_CHOOSER_ACTION_SELECT_FOLDER, "GIMP_FILE_CHOOSER_ACTION_SELECT_FOLDER", "select-folder" }, + { GIMP_FILE_CHOOSER_ACTION_CREATE_FOLDER, "GIMP_FILE_CHOOSER_ACTION_CREATE_FOLDER", "create-folder" }, + { 0, NULL, NULL } + }; + + static const GimpEnumDesc descs[] = + { + { GIMP_FILE_CHOOSER_ACTION_ANY, "GIMP_FILE_CHOOSER_ACTION_ANY", NULL }, + { GIMP_FILE_CHOOSER_ACTION_OPEN, "GIMP_FILE_CHOOSER_ACTION_OPEN", NULL }, + { GIMP_FILE_CHOOSER_ACTION_SAVE, "GIMP_FILE_CHOOSER_ACTION_SAVE", NULL }, + { GIMP_FILE_CHOOSER_ACTION_SELECT_FOLDER, "GIMP_FILE_CHOOSER_ACTION_SELECT_FOLDER", NULL }, + { GIMP_FILE_CHOOSER_ACTION_CREATE_FOLDER, "GIMP_FILE_CHOOSER_ACTION_CREATE_FOLDER", NULL }, + { 0, NULL, NULL } + }; + + static GType type = 0; + + if (G_UNLIKELY (! type)) + { + type = g_enum_register_static ("GimpFileChooserAction", values); + gimp_type_set_translation_domain (type, GETTEXT_PACKAGE "-libgimp"); + gimp_type_set_translation_context (type, "file-chooser-action"); + gimp_enum_set_value_descriptions (type, descs); + } + + return type; +} + /* Generated data ends here */ diff --git a/libgimpbase/gimpbaseenums.h b/libgimpbase/gimpbaseenums.h index 33cbb6b192..5960533e9f 100644 --- a/libgimpbase/gimpbaseenums.h +++ b/libgimpbase/gimpbaseenums.h @@ -1338,6 +1338,33 @@ typedef enum } GimpExportCapabilities; +/** + * GimpFileChooserAction: + * @GIMP_FILE_CHOOSER_ACTION_ANY: No restriction. + * @GIMP_FILE_CHOOSER_ACTION_OPEN: Opens an existing file. + * @GIMP_FILE_CHOOSER_ACTION_SAVE: Saves a file (over a new file or an existing one. + * @GIMP_FILE_CHOOSER_ACTION_SELECT_FOLDER: Picks an existing folder. + * @GIMP_FILE_CHOOSER_ACTION_CREATE_FOLDER: Picks an existing or new folder. + * + * A type of file to choose from when actions are expected to choose a + * file. This is basically a mapping to %GtkFileChooserAction except for + * [enum@Gimp.FileChooserAction.ANY] which should not be used for any + * GUI functions since we can't know what you are looking for. + **/ +#define GIMP_TYPE_FILE_CHOOSER_ACTION (gimp_file_chooser_action_get_type ()) + +GType gimp_file_chooser_action_get_type (void) G_GNUC_CONST; + +typedef enum +{ + GIMP_FILE_CHOOSER_ACTION_ANY = -1, + GIMP_FILE_CHOOSER_ACTION_OPEN = 0, + GIMP_FILE_CHOOSER_ACTION_SAVE = 1, + GIMP_FILE_CHOOSER_ACTION_SELECT_FOLDER = 2, + GIMP_FILE_CHOOSER_ACTION_CREATE_FOLDER = 3, +} GimpFileChooserAction; + + G_END_DECLS #endif /* __GIMP_BASE_ENUMS_H__ */ diff --git a/libgimpbase/gimpchoice.c b/libgimpbase/gimpchoice.c index 080dc46bc5..ce35c8facd 100644 --- a/libgimpbase/gimpchoice.c +++ b/libgimpbase/gimpchoice.c @@ -21,6 +21,7 @@ #include "config.h" #include +#include #include #include "gimpbasetypes.h" diff --git a/libgimpbase/gimpparamspecs.c b/libgimpbase/gimpparamspecs.c index 51a95f550c..4958c118e2 100644 --- a/libgimpbase/gimpparamspecs.c +++ b/libgimpbase/gimpparamspecs.c @@ -216,6 +216,187 @@ gimp_param_spec_object_duplicate (GParamSpec *pspec) } +/* + * GIMP_TYPE_PARAM_FILE + */ + +static void gimp_param_file_class_init (GimpParamSpecObjectClass *klass); +static void gimp_param_file_init (GimpParamSpecFile *fspec); + +static gboolean gimp_param_spec_file_validate (GParamSpec *pspec, + GValue *value); +static GParamSpec * gimp_param_spec_file_duplicate (GParamSpec *pspec); + + +/** + * gimp_param_file_get_type: + * + * Reveals the object type + * + * Returns: the #GType for a file param object. + * + * Since: 3.0 + **/ +GType +gimp_param_file_get_type (void) +{ + static GType type = 0; + + if (! type) + { + const GTypeInfo info = + { + sizeof (GimpParamSpecObjectClass), + NULL, NULL, + (GClassInitFunc) gimp_param_file_class_init, + NULL, NULL, + sizeof (GimpParamSpecFile), + 0, + (GInstanceInitFunc) gimp_param_file_init + }; + + type = g_type_register_static (GIMP_TYPE_PARAM_OBJECT, + "GimpParamFile", &info, 0); + } + + return type; +} + +static void +gimp_param_file_class_init (GimpParamSpecObjectClass *klass) +{ + GParamSpecClass *pclass = G_PARAM_SPEC_CLASS (klass); + GimpParamSpecObjectClass *oclass = GIMP_PARAM_SPEC_OBJECT_CLASS (klass); + + pclass->value_type = G_TYPE_FILE; + pclass->value_validate = gimp_param_spec_file_validate; + oclass->duplicate = gimp_param_spec_file_duplicate; +} + +static void +gimp_param_file_init (GimpParamSpecFile *fspec) +{ + fspec->none_ok = TRUE; + fspec->action = GIMP_FILE_CHOOSER_ACTION_OPEN; +} + +static gboolean +gimp_param_spec_file_validate (GParamSpec *pspec, + GValue *value) +{ + GimpParamSpecFile *fspec = GIMP_PARAM_SPEC_FILE (pspec); + GimpParamSpecObject *ospec = GIMP_PARAM_SPEC_OBJECT (pspec); + GFile *file = value->data[0].v_pointer; + gboolean modifying = FALSE; + + if (file == NULL && ! fspec->none_ok && ospec->_default_value != NULL) + { + modifying = TRUE; + } + else if (file != NULL) + { + gboolean exists = g_file_query_exists (file, NULL); + GFileType type = g_file_query_file_type (file, G_FILE_QUERY_INFO_NONE, NULL); + + switch (fspec->action) + { + case GIMP_FILE_CHOOSER_ACTION_OPEN: + modifying = (! exists || type != G_FILE_TYPE_REGULAR); + break; + case GIMP_FILE_CHOOSER_ACTION_SAVE: + modifying = (exists && type != G_FILE_TYPE_REGULAR); + break; + case GIMP_FILE_CHOOSER_ACTION_SELECT_FOLDER: + modifying = (! exists || type != G_FILE_TYPE_DIRECTORY); + break; + case GIMP_FILE_CHOOSER_ACTION_CREATE_FOLDER: + modifying = (exists && type != G_FILE_TYPE_DIRECTORY); + break; + case GIMP_FILE_CHOOSER_ACTION_ANY: + break; + } + } + + if (modifying) + { + g_clear_object (&file); + value->data[0].v_pointer = ospec->_default_value ? g_object_ref (ospec->_default_value) : NULL; + } + + return modifying; +} + +static GParamSpec * +gimp_param_spec_file_duplicate (GParamSpec *pspec) +{ + GimpParamSpecObject *ospec; + GimpParamSpecFile *fspec; + GParamSpec *duplicate; + + g_return_val_if_fail (GIMP_IS_PARAM_SPEC_FILE (pspec), NULL); + + ospec = GIMP_PARAM_SPEC_OBJECT (pspec); + fspec = GIMP_PARAM_SPEC_FILE (pspec); + duplicate = gimp_param_spec_file (pspec->name, + g_param_spec_get_nick (pspec), + g_param_spec_get_blurb (pspec), + fspec->action, fspec->none_ok, + G_FILE (ospec->_default_value), + pspec->flags); + return duplicate; +} + +/** + * gimp_param_spec_file: + * @name: Canonical name of the param + * @nick: Nickname of the param + * @blurb: Brief description of param. + * @action: The type of file to expect. + * @none_ok: Whether %NULL is allowed. + * @default_value: (nullable): File to use if none is assigned. + * @flags: a combination of #GParamFlags + * + * Creates a param spec to hold a file param. + * See g_param_spec_internal() for more information. + * + * Returns: (transfer full): a newly allocated #GParamSpec instance + * + * Since: 3.0 + **/ +GParamSpec * +gimp_param_spec_file (const gchar *name, + const gchar *nick, + const gchar *blurb, + GimpFileChooserAction action, + gboolean none_ok, + GFile *default_value, + GParamFlags flags) +{ + GimpParamSpecFile *fspec; + GimpParamSpecObject *ospec; + + g_return_val_if_fail (default_value == NULL || G_IS_FILE (default_value), NULL); + + fspec = g_param_spec_internal (GIMP_TYPE_PARAM_FILE, + name, nick, blurb, flags); + + g_return_val_if_fail (fspec, NULL); + + fspec->action = action; + fspec->none_ok = none_ok; + + ospec = GIMP_PARAM_SPEC_OBJECT (fspec); + ospec->_has_default = TRUE; + /* Note that we don't check none_ok and allows even NULL as default + * value. What we won't allow will be trying to set a NULL value + * later. + */ + ospec->_default_value = default_value ? g_object_ref (G_OBJECT (default_value)) : NULL; + + return G_PARAM_SPEC (fspec); +} + + /* * GIMP_TYPE_ARRAY */ diff --git a/libgimpbase/gimpparamspecs.h b/libgimpbase/gimpparamspecs.h index ecd258eaf6..0543936685 100644 --- a/libgimpbase/gimpparamspecs.h +++ b/libgimpbase/gimpparamspecs.h @@ -152,6 +152,37 @@ gboolean gimp_param_spec_object_has_default (GParamSpec *pspec); GParamSpec * gimp_param_spec_object_duplicate (GParamSpec *pspec); +/* + * GIMP_TYPE_PARAM_FILE + */ + +#define GIMP_VALUE_HOLDS_FILE(value) (G_TYPE_CHECK_VALUE_TYPE ((value), G_TYPE_FILE)) + +#define GIMP_TYPE_PARAM_FILE (gimp_param_file_get_type ()) +#define GIMP_PARAM_SPEC_FILE(pspec) (G_TYPE_CHECK_INSTANCE_CAST ((pspec), GIMP_TYPE_PARAM_FILE, GimpParamSpecFile)) +#define GIMP_IS_PARAM_SPEC_FILE(pspec) (G_TYPE_CHECK_INSTANCE_TYPE ((pspec), GIMP_TYPE_PARAM_FILE)) + +typedef struct _GimpParamSpecFile GimpParamSpecFile; + +struct _GimpParamSpecFile +{ + GimpParamSpecObject parent_instance; + + /*< private >*/ + GimpFileChooserAction action; + gboolean none_ok; +}; + +GType gimp_param_file_get_type (void) G_GNUC_CONST; + +GParamSpec * gimp_param_spec_file (const gchar *name, + const gchar *nick, + const gchar *blurb, + GimpFileChooserAction action, + gboolean none_ok, + GFile *default_value, + GParamFlags flags); + /* * GIMP_TYPE_ARRAY diff --git a/libgimpbase/gimpprotocol.c b/libgimpbase/gimpprotocol.c index 5d1bdae71c..5d740997d0 100644 --- a/libgimpbase/gimpprotocol.c +++ b/libgimpbase/gimpprotocol.c @@ -19,6 +19,7 @@ #include "config.h" #include +#include #include #include "gimpbasetypes.h" @@ -1293,6 +1294,21 @@ _gp_param_def_read (GIOChannel *channel, user_data)) return FALSE; break; + + case GP_PARAM_DEF_TYPE_FILE: + if (! _gimp_wire_read_int32 (channel, + (guint32 *) ¶m_def->meta.m_file.action, 1, + user_data)) + return FALSE; + if (! _gimp_wire_read_int32 (channel, + (guint32 *) ¶m_def->meta.m_file.none_ok, 1, + user_data)) + return FALSE; + if (! _gimp_wire_read_string (channel, + ¶m_def->meta.m_file.default_uri, 1, + user_data)) + return FALSE; + break; } return TRUE; @@ -1349,6 +1365,10 @@ _gp_param_def_destroy (GPParamDef *param_def) case GP_PARAM_DEF_TYPE_RESOURCE: break; + + case GP_PARAM_DEF_TYPE_FILE: + g_free (param_def->meta.m_file.default_uri); + break; } } @@ -1641,6 +1661,21 @@ _gp_param_def_write (GIOChannel *channel, user_data)) return FALSE; break; + + case GP_PARAM_DEF_TYPE_FILE: + if (! _gimp_wire_write_int32 (channel, + (guint32 *) ¶m_def->meta.m_file.action, 1, + user_data)) + return FALSE; + if (! _gimp_wire_write_int32 (channel, + (guint32 *) ¶m_def->meta.m_file.none_ok, 1, + user_data)) + return FALSE; + if (! _gimp_wire_write_string (channel, + ¶m_def->meta.m_file.default_uri, 1, + user_data)) + return FALSE; + break; } return TRUE; diff --git a/libgimpbase/gimpprotocol.h b/libgimpbase/gimpprotocol.h index 9e7eea22ab..a3912f9e68 100644 --- a/libgimpbase/gimpprotocol.h +++ b/libgimpbase/gimpprotocol.h @@ -26,7 +26,7 @@ G_BEGIN_DECLS /* Increment every time the protocol changes */ -#define GIMP_PROTOCOL_VERSION 0x0114 +#define GIMP_PROTOCOL_VERSION 0x0115 enum @@ -60,7 +60,8 @@ typedef enum GP_PARAM_DEF_TYPE_ID, GP_PARAM_DEF_TYPE_ID_ARRAY, GP_PARAM_DEF_TYPE_EXPORT_OPTIONS, - GP_PARAM_DEF_TYPE_RESOURCE + GP_PARAM_DEF_TYPE_RESOURCE, + GP_PARAM_DEF_TYPE_FILE } GPParamDefType; typedef enum @@ -100,6 +101,7 @@ typedef struct _GPParamDefGeglColor GPParamDefGeglColor; typedef struct _GPParamDefID GPParamDefID; typedef struct _GPParamDefIDArray GPParamDefIDArray; typedef struct _GPParamDefResource GPParamDefResource; +typedef struct _GPParamDefFile GPParamDefFile; typedef struct _GPParam GPParam; typedef struct _GPParamArray GPParamArray; typedef struct _GPParamIDArray GPParamIDArray; @@ -239,6 +241,13 @@ struct _GPParamDefResource gint32 default_resource_id; }; +struct _GPParamDefFile +{ + GimpFileChooserAction action; + gint32 none_ok; + gchar *default_uri; +}; + struct _GPParamDef { GPParamDefType param_def_type; @@ -262,6 +271,7 @@ struct _GPParamDef GPParamDefIDArray m_id_array; GPParamDefChoice m_choice; GPParamDefResource m_resource; + GPParamDefFile m_file; } meta; }; diff --git a/libgimpbase/gimpunit.c b/libgimpbase/gimpunit.c index 3010c124e2..8691192951 100644 --- a/libgimpbase/gimpunit.c +++ b/libgimpbase/gimpunit.c @@ -25,6 +25,7 @@ #include #include +#include #include #include "gimpbasetypes.h" diff --git a/libgimpbase/gimpvaluearray.c b/libgimpbase/gimpvaluearray.c index 06706737d6..0e00916520 100644 --- a/libgimpbase/gimpvaluearray.c +++ b/libgimpbase/gimpvaluearray.c @@ -23,6 +23,7 @@ #include #include +#include #include #include diff --git a/libgimpconfig/gimpconfig-deserialize.c b/libgimpconfig/gimpconfig-deserialize.c index b892c2a79b..15247923d2 100644 --- a/libgimpconfig/gimpconfig-deserialize.c +++ b/libgimpconfig/gimpconfig-deserialize.c @@ -1135,7 +1135,7 @@ gimp_config_deserialize_file_value (GValue *value, if (path) { - GFile *file = g_file_new_for_path (path); + GFile *file = g_file_new_for_uri (path); g_value_take_object (value, file); g_free (path); diff --git a/libgimpconfig/gimpconfig-serialize.c b/libgimpconfig/gimpconfig-serialize.c index 4da6c4ec2f..377b237163 100644 --- a/libgimpconfig/gimpconfig-serialize.c +++ b/libgimpconfig/gimpconfig-serialize.c @@ -642,7 +642,7 @@ gimp_config_serialize_value (const GValue *value, if (file) { - gchar *path = g_file_get_path (file); + gchar *path = g_file_get_uri (file); gchar *unexpand = NULL; if (path) diff --git a/pdb/enums.pl b/pdb/enums.pl index b0344df6ee..8c4259522e 100644 --- a/pdb/enums.pl +++ b/pdb/enums.pl @@ -652,6 +652,20 @@ package Gimp::CodeGen::enums; GIMP_EXPORT_NEEDS_ALPHA => '1 << 9', GIMP_EXPORT_NEEDS_CROP => '1 << 10' } }, + GimpFileChooserAction => + { contig => 0, + header => 'libgimpbase/gimpbaseenums.h', + symbols => [ qw(GIMP_FILE_CHOOSER_ACTION_ANY + GIMP_FILE_CHOOSER_ACTION_OPEN + GIMP_FILE_CHOOSER_ACTION_SAVE + GIMP_FILE_CHOOSER_ACTION_SELECT_FOLDER + GIMP_FILE_CHOOSER_ACTION_CREATE_FOLDER) ], + mapping => { GIMP_FILE_CHOOSER_ACTION_ANY => '-1', + GIMP_FILE_CHOOSER_ACTION_OPEN => '0', + GIMP_FILE_CHOOSER_ACTION_SAVE => '1', + GIMP_FILE_CHOOSER_ACTION_SELECT_FOLDER => '2', + GIMP_FILE_CHOOSER_ACTION_CREATE_FOLDER => '3' } + }, GimpColorManagementMode => { contig => 1, header => 'libgimpconfig/gimpconfigenums.h', diff --git a/plug-ins/common/cml-explorer.c b/plug-ins/common/cml-explorer.c index cd918a41bc..b0076bf3a0 100644 --- a/plug-ins/common/cml-explorer.c +++ b/plug-ins/common/cml-explorer.c @@ -535,6 +535,8 @@ explorer_create_procedure (GimpPlugIn *plug_in, _("Parameter File"), _("The parameter file from which CML_explorer makes an image. " "This argument is only used in non-interactive runs."), + GIMP_FILE_CHOOSER_ACTION_OPEN, + FALSE, NULL, G_PARAM_READWRITE); gimp_procedure_add_bytes_aux_argument (procedure, "settings-data", diff --git a/plug-ins/common/file-cel.c b/plug-ins/common/file-cel.c index 8c47caf77b..7c68ef2a7e 100644 --- a/plug-ins/common/file-cel.c +++ b/plug-ins/common/file-cel.c @@ -157,6 +157,8 @@ cel_create_procedure (GimpPlugIn *plug_in, gimp_procedure_add_file_argument (procedure, "palette-file", _("_Palette file"), _("KCF file to load palette from"), + GIMP_FILE_CHOOSER_ACTION_OPEN, + FALSE, NULL, G_PARAM_READWRITE); } else if (! strcmp (name, EXPORT_PROC)) @@ -193,6 +195,8 @@ cel_create_procedure (GimpPlugIn *plug_in, gimp_procedure_add_file_argument (procedure, "palette-file", _("_Palette file"), _("File to save palette to"), + GIMP_FILE_CHOOSER_ACTION_SAVE, + FALSE, NULL, G_PARAM_READWRITE); } diff --git a/plug-ins/common/file-raw-data.c b/plug-ins/common/file-raw-data.c index a937127611..d14d6a5391 100644 --- a/plug-ins/common/file-raw-data.c +++ b/plug-ins/common/file-raw-data.c @@ -431,6 +431,8 @@ raw_create_procedure (GimpPlugIn *plug_in, gimp_procedure_add_file_argument (procedure, "palette-file", _("_Palette File"), _("The file containing palette data"), + GIMP_FILE_CHOOSER_ACTION_OPEN, + TRUE, NULL, G_PARAM_READWRITE); } else if (! strcmp (name, LOAD_HGT_PROC)) @@ -490,6 +492,8 @@ raw_create_procedure (GimpPlugIn *plug_in, gimp_procedure_add_file_argument (procedure, "palette-file", _("_Palette File"), _("The file containing palette data"), + GIMP_FILE_CHOOSER_ACTION_OPEN, + TRUE, NULL, G_PARAM_READWRITE); } else if (! strcmp (name, EXPORT_PROC)) diff --git a/plug-ins/file-fli/fli-gimp.c b/plug-ins/file-fli/fli-gimp.c index d5ca360735..ff62c1b89c 100644 --- a/plug-ins/file-fli/fli-gimp.c +++ b/plug-ins/file-fli/fli-gimp.c @@ -273,9 +273,10 @@ fli_create_procedure (GimpPlugIn *plug_in, "Jens Ch. Restemeier", "1997"); - gimp_procedure_add_file_argument (procedure, "file", - "File", + gimp_procedure_add_file_argument (procedure, "file", "File", "The local file to get info about", + GIMP_FILE_CHOOSER_ACTION_OPEN, + FALSE, NULL, G_PARAM_READWRITE); gimp_procedure_add_int_return_value (procedure, "width", diff --git a/plug-ins/script-fu/libscriptfu/script-fu-arg.c b/plug-ins/script-fu/libscriptfu/script-fu-arg.c index 7f518a5eb2..0088c82d0e 100644 --- a/plug-ins/script-fu/libscriptfu/script-fu-arg.c +++ b/plug-ins/script-fu/libscriptfu/script-fu-arg.c @@ -368,8 +368,9 @@ script_fu_arg_add_argument (SFArg *arg, const gchar *name, const gchar *nick) { - GString *blurb_gstring = script_fu_arg_get_blurb (arg); - gchar *blurb = blurb_gstring->str; + GString *blurb_gstring = script_fu_arg_get_blurb (arg); + gchar *blurb = blurb_gstring->str; + GimpFileChooserAction action = GIMP_FILE_CHOOSER_ACTION_ANY; switch (arg->type) { @@ -492,17 +493,21 @@ script_fu_arg_add_argument (SFArg *arg, break; case SF_FILENAME: + action = GIMP_FILE_CHOOSER_ACTION_OPEN; case SF_DIRNAME: { GParamSpec *pspec = NULL; + if (action == GIMP_FILE_CHOOSER_ACTION_ANY) + action = GIMP_FILE_CHOOSER_ACTION_SELECT_FOLDER; + gimp_procedure_add_file_argument (procedure, name, nick, blurb, + action, TRUE, NULL, G_PARAM_READWRITE | GIMP_PARAM_NO_VALIDATE); pspec = gimp_procedure_find_argument (procedure, name); pspec_set_default_file (pspec, arg->default_value.sfa_file.filename); - /* FUTURE: Default not now appear in PDB browser, but appears in widgets? */ } break; @@ -953,18 +958,14 @@ script_fu_arg_generate_name_and_nick (SFArg *arg, static void pspec_set_default_file (GParamSpec *pspec, const gchar *filepath) { - GValue gvalue = G_VALUE_INIT; - GFile *gfile = NULL; + GFile *gfile = NULL; - g_value_init (&gvalue, G_TYPE_FILE); - gfile = g_file_new_for_path (filepath); - g_value_set_object (&gvalue, gfile); - /* FIXME this is not correct. - * value_set_default sets the value, not the pspec. - * Should be something like: - * gimp_param_spec_file_set_default (pspec, gfile); - */ - g_param_value_set_default (pspec, &gvalue); + if (filepath != NULL && strlen (filepath) > 0) + gfile = g_file_new_for_path (filepath); + + gimp_param_spec_object_set_default (pspec, G_OBJECT (gfile)); + + g_clear_object (&gfile); } /* Append a string repr of an integer valued gvalue to given GString.