[gimp] libgimp, libgimpwidgets: supporting GFile properties in…



commit 42143881d821528b1c2a09590d49dd1b49037354
Author: Jehan <jehan girinstud io>
Date:   Fri Jun 17 15:08:16 2022 +0200

    libgimp, libgimpwidgets: supporting GFile properties in…
    
    … GimpProcedureDialog.
    
    - gimp_prop_file_chooser_button_new() now works also with properties
      G_PARAM_SPEC_OBJECT having a value_type == G_TYPE_FILE (additionally
      to GIMP_PARAM_SPEC_CONFIG_PATH properties).
    - gimp_procedure_dialog_get_widget() will now create a
      GtkFileChooserButton in open mode for such a GFile property.
    - New gimp_procedure_dialog_get_file_chooser() API to create
      GtkFileChooserButton for GFile properties in other modes.
    
    Current limitation: GtkFileChooserButton doesn't have a label. This
    should be fixed, probably by creating another custom widget with would
    be a labelized file chooser button.

 libgimp/gimpproceduredialog.c    |  79 +++++++++++++++++++++++++++
 libgimp/gimpproceduredialog.h    |   3 ++
 libgimp/gimpui.def               |   1 +
 libgimpwidgets/gimppropwidgets.c | 112 +++++++++++++++++++++++++++++----------
 4 files changed, 166 insertions(+), 29 deletions(-)
---
diff --git a/libgimp/gimpproceduredialog.c b/libgimp/gimpproceduredialog.c
index 88bb885360..f92b919046 100644
--- a/libgimp/gimpproceduredialog.c
+++ b/libgimp/gimpproceduredialog.c
@@ -562,6 +562,11 @@ gimp_procedure_dialog_new (GimpProcedure       *procedure,
  *         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.
+ * - %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.
  *
  * If the @widget_type is not supported for the actual type of
  * @property, the function will fail. To keep the default, set to
@@ -714,6 +719,12 @@ gimp_procedure_dialog_get_widget (GimpProcedureDialog *dialog,
           gtk_widget_set_hexpand (widget, FALSE);
         }
     }
+  else if (G_IS_PARAM_SPEC_OBJECT (pspec) && pspec->value_type == G_TYPE_FILE)
+    {
+      widget = gimp_prop_file_chooser_button_new (G_OBJECT (dialog->priv->config),
+                                                  property, NULL,
+                                                  GTK_FILE_CHOOSER_ACTION_OPEN);
+    }
   else
     {
       g_warning ("%s: parameter %s has non supported type %s",
@@ -1204,6 +1215,74 @@ gimp_procedure_dialog_get_label (GimpProcedureDialog *dialog,
   return label;
 }
 
+/**
+ * gimp_procedure_dialog_get_file_chooser:
+ * @dialog:   the associated #GimpProcedureDialog.
+ * @property: name of the %GimpParamConfigPath or %GParamObject of value
+ *            type %GFile property to build a #GtkFileChooserButton for.
+ *            It must be a property of the #GimpProcedure @dialog has
+ *            been created for.
+ * @action:   The open mode for the widget.
+ *
+ * Creates a new %GtkFileChooserButton for @property which must
+ * necessarily be a config path or %GFile property.
+ * This can be used instead of gimp_procedure_dialog_get_widget() in
+ * particular if you want to create a button in non-open modes (i.e. to
+ * save files, and select or create folders).
+ *
+ * If a widget has already been created for this procedure, it will be
+ * returned instead (whatever its actual widget type).
+ *
+ * Returns: (transfer none): the #GtkWidget representing @property. The
+ *                           object belongs to @dialog and must not be
+ *                           freed.
+ */
+GtkWidget *
+gimp_procedure_dialog_get_file_chooser (GimpProcedureDialog  *dialog,
+                                        const gchar          *property,
+                                        GtkFileChooserAction  action)
+{
+  GtkWidget  *widget = NULL;
+  GParamSpec *pspec;
+
+  g_return_val_if_fail (GIMP_IS_PROCEDURE_DIALOG (dialog), NULL);
+  g_return_val_if_fail (property != NULL, NULL);
+
+  pspec = g_object_class_find_property (G_OBJECT_GET_CLASS (dialog->priv->config),
+                                        property);
+
+  if (! pspec)
+    {
+      g_warning ("%s: parameter %s does not exist.",
+                 G_STRFUNC, property);
+      return NULL;
+    }
+
+  g_return_val_if_fail (GIMP_IS_PARAM_SPEC_CONFIG_PATH (pspec) ||
+                        (G_IS_PARAM_SPEC_OBJECT (pspec) && pspec->value_type != G_TYPE_FILE),
+                        NULL);
+
+  /* First check if it already exists. */
+  widget = g_hash_table_lookup (dialog->priv->widgets, property);
+
+  if (widget)
+    return widget;
+
+  widget = gimp_prop_file_chooser_button_new (G_OBJECT (dialog->priv->config),
+                                              property, NULL, action);
+
+  /* TODO: make is a file chooser with label. */
+  /*gtk_size_group_add_widget (dialog->priv->label_group,
+                             gimp_labeled_get_label (GIMP_LABELED (widget)));
+
+  gimp_procedure_dialog_check_mnemonic (dialog, widget, property, NULL);*/
+  g_hash_table_insert (dialog->priv->widgets, g_strdup (property), widget);
+  if (g_object_is_floating (widget))
+    g_object_ref_sink (widget);
+
+  return widget;
+}
+
 /**
  * gimp_procedure_dialog_fill:
  * @dialog: the #GimpProcedureDialog.
diff --git a/libgimp/gimpproceduredialog.h b/libgimp/gimpproceduredialog.h
index dd2e4c5d3d..d977a065eb 100644
--- a/libgimp/gimpproceduredialog.h
+++ b/libgimp/gimpproceduredialog.h
@@ -97,6 +97,9 @@ GtkWidget * gimp_procedure_dialog_get_scale_entry   (GimpProcedureDialog *dialog
 GtkWidget * gimp_procedure_dialog_get_label         (GimpProcedureDialog *dialog,
                                                      const gchar         *label_id,
                                                      const gchar         *text);
+GtkWidget * gimp_procedure_dialog_get_file_chooser  (GimpProcedureDialog *dialog,
+                                                     const gchar         *property,
+                                                     GtkFileChooserAction action);
 
 GtkWidget * gimp_procedure_dialog_fill_box          (GimpProcedureDialog *dialog,
                                                      const gchar         *container_id,
diff --git a/libgimp/gimpui.def b/libgimp/gimpui.def
index 47563dc704..0ac1946f58 100644
--- a/libgimp/gimpui.def
+++ b/libgimp/gimpui.def
@@ -48,6 +48,7 @@ EXPORTS
        gimp_procedure_dialog_fill_frame
        gimp_procedure_dialog_fill_list
        gimp_procedure_dialog_get_color_widget
+       gimp_procedure_dialog_get_file_chooser
        gimp_procedure_dialog_get_int_combo
        gimp_procedure_dialog_get_int_radio
        gimp_procedure_dialog_get_label
diff --git a/libgimpwidgets/gimppropwidgets.c b/libgimpwidgets/gimppropwidgets.c
index ed43aa2c5d..a6f23af92a 100644
--- a/libgimpwidgets/gimppropwidgets.c
+++ b/libgimpwidgets/gimppropwidgets.c
@@ -2639,10 +2639,12 @@ static void        gimp_prop_file_chooser_button_notify   (GObject        *confi
  * gimp_prop_file_chooser_button_new:
  * @config:        object to which property is attached.
  * @property_name: name of path property.
- * @title:         the title of the browse dialog.
+ * @title: (nullable): the title of the browse dialog.
  * @action:        the open mode for the widget.
  *
  * Creates a #GtkFileChooserButton to edit the specified path property.
+ * @property_name must represent either a GIMP_PARAM_SPEC_CONFIG_PATH or
+ * a G_PARAM_SPEC_OBJECT where `value_type == G_TYPE_FILE`.
  *
  * Note that #GtkFileChooserButton implements the #GtkFileChooser
  * interface; you can use the #GtkFileChooser API with it.
@@ -2663,10 +2665,27 @@ gimp_prop_file_chooser_button_new (GObject              *config,
   g_return_val_if_fail (G_IS_OBJECT (config), NULL);
   g_return_val_if_fail (property_name != NULL, NULL);
 
-  param_spec = check_param_spec_w (config, property_name,
-                                   GIMP_TYPE_PARAM_CONFIG_PATH, G_STRFUNC);
+  param_spec = find_param_spec (config, property_name, G_STRFUNC);
   if (! param_spec)
-    return NULL;
+    {
+      g_warning ("%s: %s has no property named '%s'",
+                 G_STRFUNC, g_type_name (G_TYPE_FROM_INSTANCE (config)),
+                 property_name);
+      return NULL;
+    }
+
+  if (! GIMP_IS_PARAM_SPEC_CONFIG_PATH (param_spec) &&
+      (! G_IS_PARAM_SPEC_OBJECT (param_spec) || param_spec->value_type != G_TYPE_FILE))
+    {
+      g_warning ("%s: property '%s' of %s is neither a GIMP_PARAM_SPEC_CONFIG_PATH "
+                 "nor a G_PARAM_SPEC_OBJECT of value type G_TYPE_FILE.",
+                 G_STRFUNC, param_spec->name,
+                 g_type_name (param_spec->owner_type));
+      return NULL;
+    }
+
+  if (! title)
+    title = g_param_spec_get_nick (param_spec);
 
   button = gtk_file_chooser_button_new (title, action);
 
@@ -2719,17 +2738,27 @@ gimp_prop_file_chooser_button_setup (GtkWidget  *button,
                                      GObject    *config,
                                      GParamSpec *param_spec)
 {
-  gchar *value;
   GFile *file = NULL;
 
-  g_object_get (config,
-                param_spec->name, &value,
-                NULL);
+  if (GIMP_IS_PARAM_SPEC_CONFIG_PATH (param_spec))
+    {
+      gchar *value;
 
-  if (value)
+      g_object_get (config,
+                    param_spec->name, &value,
+                    NULL);
+
+      if (value)
+        {
+          file = gimp_file_new_for_config_path (value, NULL);
+          g_free (value);
+        }
+    }
+  else /* G_FILE */
     {
-      file = gimp_file_new_for_config_path (value, NULL);
-      g_free (value);
+      g_object_get (config,
+                    param_spec->name, &file,
+                    NULL);
     }
 
   if (file)
@@ -2766,8 +2795,6 @@ gimp_prop_file_chooser_button_callback (GtkFileChooser *button,
 {
   GParamSpec *param_spec;
   GFile      *file;
-  gchar      *value = NULL;
-  gchar      *v;
 
   param_spec = get_param_spec (G_OBJECT (button));
   if (! param_spec)
@@ -2775,29 +2802,56 @@ gimp_prop_file_chooser_button_callback (GtkFileChooser *button,
 
   file = gtk_file_chooser_get_file (button);
 
-  if (file)
+  if (GIMP_IS_PARAM_SPEC_CONFIG_PATH (param_spec))
     {
-      value = gimp_file_get_config_path (file, NULL);
-      g_object_unref (file);
-    }
+      gchar *value = NULL;
+      gchar *v;
 
-  g_object_get (config, param_spec->name, &v, NULL);
+      if (file)
+        {
+          value = gimp_file_get_config_path (file, NULL);
+          g_object_unref (file);
+        }
 
-  if (g_strcmp0 (v, value))
-    {
-      g_signal_handlers_block_by_func (config,
-                                       gimp_prop_file_chooser_button_notify,
-                                       button);
+      g_object_get (config, param_spec->name, &v, NULL);
 
-      g_object_set (config, param_spec->name, value, NULL);
+      if (g_strcmp0 (v, value))
+        {
+          g_signal_handlers_block_by_func (config,
+                                           gimp_prop_file_chooser_button_notify,
+                                           button);
 
-      g_signal_handlers_unblock_by_func (config,
-                                         gimp_prop_file_chooser_button_notify,
-                                         button);
+          g_object_set (config, param_spec->name, value, NULL);
+
+          g_signal_handlers_unblock_by_func (config,
+                                             gimp_prop_file_chooser_button_notify,
+                                             button);
+        }
+
+      g_free (value);
+      g_free (v);
     }
+  else /* G_FILE */
+    {
+      GFile *f = NULL;
 
-  g_free (value);
-  g_free (v);
+      g_object_get (config, param_spec->name, &f, NULL);
+
+      if (! f || ! file || ! g_file_equal (f, file))
+        {
+          g_signal_handlers_block_by_func (config,
+                                           gimp_prop_file_chooser_button_notify,
+                                           button);
+
+          g_object_set (config, param_spec->name, file, NULL);
+
+          g_signal_handlers_unblock_by_func (config,
+                                             gimp_prop_file_chooser_button_notify,
+                                             button);
+        }
+      g_clear_object (&f);
+    }
+  g_clear_object (&file);
 }
 
 static void


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]