[gtk+/portal: 10/14] Add combobox and checkbutton support to GtkFileChooserNative
- From: Matthias Clasen <matthiasc src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gtk+/portal: 10/14] Add combobox and checkbutton support to GtkFileChooserNative
- Date: Mon, 4 Jul 2016 04:51:59 +0000 (UTC)
commit b90e54c845113cbe28ff9da8907c5c0a5ee0fe65
Author: Matthias Clasen <mclasen redhat com>
Date: Mon Jun 27 16:47:11 2016 -0400
Add combobox and checkbutton support to GtkFileChooserNative
This commit adds API for adding combo boxes and check buttons
to GtkFileChooser, and getting the selected value back
in ::response. In contrast to gtk_file_chooser_set_extra_widget,
these APIs are abstract and suitable for implementation
in GtkFileChooserNative.
This commit includes implementations for the regular filechooser
as well as for the portal one.
gtk/gtkfilechooser.c | 96 +++++++++++++++++++++++++
gtk/gtkfilechooser.h | 17 +++++
gtk/gtkfilechoosernative.c | 131 +++++++++++++++++++++++++++++++++
gtk/gtkfilechoosernativeportal.c | 128 ++++++++++++++++-----------------
gtk/gtkfilechoosernativeprivate.h | 9 +++
gtk/gtkfilechooserprivate.h | 16 ++++-
gtk/gtkfilechooserutils.c | 49 +++++++++++++
gtk/gtkfilechooserwidget.c | 143 +++++++++++++++++++++++++++++++++++++
8 files changed, 523 insertions(+), 66 deletions(-)
---
diff --git a/gtk/gtkfilechooser.c b/gtk/gtkfilechooser.c
index 101decb..18cc5af 100644
--- a/gtk/gtkfilechooser.c
+++ b/gtk/gtkfilechooser.c
@@ -2263,3 +2263,99 @@ gtk_file_chooser_get_do_overwrite_confirmation (GtkFileChooser *chooser)
return do_overwrite_confirmation;
}
+
+/**
+ * gtk_file_chooser_add_choice:
+ * @chooser: a #GtkFileChooser
+ * @id: id for the added choice
+ * @label: user-visible label for the added choice
+ * @options: ids for the options of the choice, or %NULL for a boolean choice
+ * @option_labels: user-visible labels for the options, must be the same length as @options
+ *
+ * Adds a 'choice' to the file chooser. This is typically implemented
+ * as a combobox or, for boolean choices, as a checkbutton. You can select
+ * a value using gtk_file_chooser_set_choice() before the dialog is shown,
+ * and you can obtain the user-selected value in the ::response signal handler
+ * using gtk_file_chooser_get_choice().
+ *
+ * Compare gtk_file_chooser_set_extra_widget().
+ *
+ * Since: 3.22
+ */
+void
+gtk_file_chooser_add_choice (GtkFileChooser *chooser,
+ const char *id,
+ const char *label,
+ const char **options,
+ const char **option_labels)
+{
+ GtkFileChooserIface *iface = GTK_FILE_CHOOSER_GET_IFACE (chooser);
+
+ if (iface->add_choice)
+ iface->add_choice (chooser, id, label, options, option_labels);
+}
+
+/**
+ * gtk_file_chooser_remove_choice:
+ * @chooser: a #GtkFileChooser
+ * @id: the ID of the choice to remove
+ *
+ * Removes a 'choice' that has been added with gtk_file_chooser_add_choice().
+ *
+ * Since: 3.22
+ */
+void
+gtk_file_chooser_remove_choice (GtkFileChooser *chooser,
+ const char *id)
+{
+ GtkFileChooserIface *iface = GTK_FILE_CHOOSER_GET_IFACE (chooser);
+
+ if (iface->remove_choice)
+ iface->remove_choice (chooser, id);
+}
+
+/**
+ * gtk_file_chooser_set_choice:
+ * @chooser: a #GtkFileChooser
+ * @id: the ID of the choice to set
+ * @selected: the ID of the option to select
+ *
+ * Selects an option in a 'choice' that has been added with
+ * gtk_file_chooser_add_choice(). For a boolean choice, the
+ * possible options are "true" and "false".
+ *
+ * Since: 3.22
+ */
+void
+gtk_file_chooser_set_choice (GtkFileChooser *chooser,
+ const char *id,
+ const char *option)
+{
+ GtkFileChooserIface *iface = GTK_FILE_CHOOSER_GET_IFACE (chooser);
+
+ if (iface->set_choice)
+ iface->set_choice (chooser, id, option);
+}
+
+/**
+ * gtk_file_chooser_get_choice:
+ * @chooser: a #GtkFileChooser
+ * @id: the ID of the choice to get
+ *
+ * Gets the currently selected option in the 'choice' with the given ID.
+ *
+ * Returns: the ID of the currenly selected option
+ * Since: 3.22
+ */
+const char *
+gtk_file_chooser_get_choice (GtkFileChooser *chooser,
+ const char *id)
+{
+ GtkFileChooserIface *iface = GTK_FILE_CHOOSER_GET_IFACE (chooser);
+
+ if (iface->get_choice)
+ return iface->get_choice (chooser, id);
+
+ return NULL;
+}
+
diff --git a/gtk/gtkfilechooser.h b/gtk/gtkfilechooser.h
index d1f5543..92cdbb3 100644
--- a/gtk/gtkfilechooser.h
+++ b/gtk/gtkfilechooser.h
@@ -304,6 +304,23 @@ gboolean gtk_file_chooser_remove_shortcut_folder_uri (GtkFileChooser *chooser,
GDK_AVAILABLE_IN_ALL
GSList *gtk_file_chooser_list_shortcut_folder_uris (GtkFileChooser *chooser);
+GDK_AVAILABLE_IN_3_22
+void gtk_file_chooser_add_choice (GtkFileChooser *chooser,
+ const char *id,
+ const char *label,
+ const char **options,
+ const char **option_labels);
+GDK_AVAILABLE_IN_3_22
+void gtk_file_chooser_remove_choice (GtkFileChooser *chooser,
+ const char *id);
+GDK_AVAILABLE_IN_3_22
+void gtk_file_chooser_set_choice (GtkFileChooser *chooser,
+ const char *id,
+ const char *option);
+GDK_AVAILABLE_IN_3_22
+const char *gtk_file_chooser_get_choice (GtkFileChooser *chooser,
+ const char *id);
+
G_END_DECLS
#endif /* __GTK_FILE_CHOOSER_H__ */
diff --git a/gtk/gtkfilechoosernative.c b/gtk/gtkfilechoosernative.c
index 6e347eb..e72c95f 100644
--- a/gtk/gtkfilechoosernative.c
+++ b/gtk/gtkfilechoosernative.c
@@ -303,6 +303,132 @@ gtk_file_chooser_native_set_cancel_label (GtkFileChooserNative *self,
g_object_notify_by_pspec (G_OBJECT (self), native_props[PROP_CANCEL_LABEL]);
}
+static GtkFileChooserNativeChoice *
+find_choice (GtkFileChooserNative *self,
+ const char *id)
+{
+ GSList *l;
+
+ for (l = self->choices; l; l = l->next)
+ {
+ GtkFileChooserNativeChoice *choice = l->data;
+
+ if (strcmp (choice->id, id) == 0)
+ return choice;
+ }
+
+ return NULL;
+}
+
+static void
+gtk_file_chooser_native_choice_free (GtkFileChooserNativeChoice *choice)
+{
+ g_free (choice->id);
+ g_free (choice->label);
+ g_strfreev (choice->options);
+ g_strfreev (choice->option_labels);
+ g_free (choice->selected);
+ g_free (choice);
+}
+
+static void
+gtk_file_chooser_native_add_choice (GtkFileChooser *chooser,
+ const char *id,
+ const char *label,
+ const char **options,
+ const char **option_labels)
+{
+ GtkFileChooserNative *self = GTK_FILE_CHOOSER_NATIVE (chooser);
+ GtkFileChooserNativeChoice *choice = find_choice (self, id);
+
+ if (choice != NULL)
+ {
+ g_warning ("Choice with id %s already added to %s %p", id, G_OBJECT_TYPE_NAME (self), self);
+ return;
+ }
+
+ g_assert ((options == NULL && option_labels == NULL) ||
+ g_strv_length ((char **)options) == g_strv_length ((char **)option_labels));
+
+ choice = g_new0 (GtkFileChooserNativeChoice, 1);
+ choice->id = g_strdup (id);
+ choice->label = g_strdup (label);
+ choice->options = g_strdupv ((char **)options);
+ choice->option_labels = g_strdupv ((char **)option_labels);
+ choice->selected = NULL;
+
+ self->choices = g_slist_append (self->choices, choice);
+
+ gtk_file_chooser_add_choice (GTK_FILE_CHOOSER (self->dialog),
+ id, label, options, option_labels);
+}
+
+static void
+gtk_file_chooser_native_remove_choice (GtkFileChooser *chooser,
+ const char *id)
+{
+ GtkFileChooserNative *self = GTK_FILE_CHOOSER_NATIVE (chooser);
+ GtkFileChooserNativeChoice *choice = find_choice (self, id);
+
+ if (choice == NULL)
+ {
+ g_warning ("No choice with id %s found in %s %p", id, G_OBJECT_TYPE_NAME (self), self);
+ return;
+ }
+
+ self->choices = g_slist_remove (self->choices, choice);
+
+ gtk_file_chooser_native_choice_free (choice);
+
+ gtk_file_chooser_remove_choice (GTK_FILE_CHOOSER (self->dialog), id);
+}
+
+static void
+gtk_file_chooser_native_set_choice (GtkFileChooser *chooser,
+ const char *id,
+ const char *selected)
+{
+ GtkFileChooserNative *self = GTK_FILE_CHOOSER_NATIVE (chooser);
+ GtkFileChooserNativeChoice *choice = find_choice (self, id);
+
+ if (choice == NULL)
+ {
+ g_warning ("No choice with id %s found in %s %p", id, G_OBJECT_TYPE_NAME (self), self);
+ return;
+ }
+
+ if ((choice->options && !g_strv_contains ((const char *const*)choice->options, selected)) ||
+ (!choice->options && !g_str_equal (selected, "true") && !g_str_equal (selected, "false")))
+ {
+ g_warning ("Not a valid option for %s: %s", id, selected);
+ return;
+ }
+
+ g_free (choice->selected);
+ choice->selected = g_strdup (selected);
+
+ gtk_file_chooser_set_choice (GTK_FILE_CHOOSER (self->dialog), id, selected);
+}
+
+static const char *
+gtk_file_chooser_native_get_choice (GtkFileChooser *chooser,
+ const char *id)
+{
+ GtkFileChooserNative *self = GTK_FILE_CHOOSER_NATIVE (chooser);
+ GtkFileChooserNativeChoice *choice = find_choice (self, id);
+
+ if (choice == NULL)
+ {
+ g_warning ("No choice with id %s found in %s %p", id, G_OBJECT_TYPE_NAME (self), self);
+ return NULL;
+ }
+
+ if (self->mode == MODE_FALLBACK)
+ return gtk_file_chooser_get_choice (GTK_FILE_CHOOSER (self->dialog), id);
+
+ return choice->selected;
+}
+
static void
gtk_file_chooser_native_set_property (GObject *object,
guint prop_id,
@@ -366,6 +492,7 @@ gtk_file_chooser_native_finalize (GObject *object)
gtk_widget_destroy (self->dialog);
g_slist_free_full (self->custom_files, g_object_unref);
+ g_slist_free_full (self->choices, (GDestroyNotify)gtk_file_chooser_native_choice_free);
G_OBJECT_CLASS (gtk_file_chooser_native_parent_class)->finalize (object);
}
@@ -685,4 +812,8 @@ _gtk_file_chooser_native_iface_init (GtkFileChooserIface *iface)
iface->set_current_name = gtk_file_chooser_native_set_current_name;
iface->set_current_folder = gtk_file_chooser_native_set_current_folder;
iface->get_files = gtk_file_chooser_native_get_files;
+ iface->add_choice = gtk_file_chooser_native_add_choice;
+ iface->remove_choice = gtk_file_chooser_native_remove_choice;
+ iface->set_choice = gtk_file_chooser_native_set_choice;
+ iface->get_choice = gtk_file_chooser_native_get_choice;
}
diff --git a/gtk/gtkfilechoosernativeportal.c b/gtk/gtkfilechoosernativeportal.c
index cf2e016..a42748a 100644
--- a/gtk/gtkfilechoosernativeportal.c
+++ b/gtk/gtkfilechoosernativeportal.c
@@ -55,7 +55,6 @@ typedef struct {
GDBusConnection *connection;
char *portal_handle;
guint portal_response_signal_id;
- GDBusSignalCallback signal_callback;
gboolean modal;
gboolean hidden;
@@ -88,73 +87,35 @@ filechooser_portal_data_free (FilechooserPortalData *data)
}
static void
-one_file_response (GDBusConnection *connection,
- const gchar *sender_name,
- const gchar *object_path,
- const gchar *interface_name,
- const gchar *signal_name,
- GVariant *parameters,
- gpointer user_data)
+response_cb (GDBusConnection *connection,
+ const gchar *sender_name,
+ const gchar *object_path,
+ const gchar *interface_name,
+ const gchar *signal_name,
+ GVariant *parameters,
+ gpointer user_data)
{
GtkFileChooserNative *self = user_data;
FilechooserPortalData *data = self->mode_data;
guint32 portal_response;
int gtk_response;
- char *uri, *handle;
- GVariant *response_data;
-
- g_variant_get (parameters, "(&ou&s@a{sv})", &handle, &portal_response, &uri, &response_data);
-
- if (data->portal_handle == NULL ||
- strcmp (handle, data->portal_handle) != 0)
- return;
-
- g_slist_free_full (self->custom_files, g_object_unref);
- self->custom_files = g_slist_prepend (NULL, g_file_new_for_uri (uri));
-
- switch (portal_response)
- {
- case 0:
- gtk_response = GTK_RESPONSE_OK;
- break;
- case 1:
- gtk_response = GTK_RESPONSE_CANCEL;
- break;
- case 2:
- default:
- gtk_response = GTK_RESPONSE_DELETE_EVENT;
- break;
- }
-
- filechooser_portal_data_free (data);
- self->mode_data = NULL;
-
- _gtk_native_dialog_emit_response (GTK_NATIVE_DIALOG (self), gtk_response);
-}
-
-static void
-multi_file_response (GDBusConnection *connection,
- const gchar *sender_name,
- const gchar *object_path,
- const gchar *interface_name,
- const gchar *signal_name,
- GVariant *parameters,
- gpointer user_data)
-{
- GtkFileChooserNative *self = user_data;
- FilechooserPortalData *data = self->mode_data;
- guint32 portal_response;
- int gtk_response;
- char *handle;
- char **uris;
+ const char **uris;
int i;
GVariant *response_data;
+ g_autoptr (GVariant) choices = NULL;
- g_variant_get (parameters, "(&ou^a&s@a{sv})", &handle, &portal_response, &uris, &response_data);
+ g_variant_get (parameters, "(u@a{sv})", &portal_response, &response_data);
+ g_variant_lookup (response_data, "uris", "^a&s", &uris);
- if (data->portal_handle == NULL ||
- strcmp (handle, data->portal_handle) != 0)
- return;
+ choices = g_variant_lookup_value (response_data, "choices", G_VARIANT_TYPE ("a(ss)"));
+ if (choices)
+ for (i = 0; i < g_variant_n_children (choices); i++)
+ {
+ const char *id;
+ const char *selected;
+ g_variant_get_child (choices, i, "(&s&s)", &id, &selected);
+ gtk_file_chooser_set_choice (GTK_FILE_CHOOSER (self), id, selected);
+ }
g_slist_free_full (self->custom_files, g_object_unref);
self->custom_files = NULL;
@@ -251,7 +212,7 @@ open_file_msg_cb (GObject *source_object,
data->portal_handle,
NULL,
G_DBUS_SIGNAL_FLAGS_NO_MATCH_RULE,
- data->signal_callback,
+ response_cb,
self, NULL);
}
@@ -276,6 +237,44 @@ get_filters (GtkFileChooser *self)
return g_variant_builder_end (&builder);
}
+static GVariant *
+gtk_file_chooser_native_choice_to_variant (GtkFileChooserNativeChoice *choice)
+{
+ GVariantBuilder choices;
+ int i;
+
+ g_variant_builder_init (&choices, G_VARIANT_TYPE ("a(ss)"));
+ if (choice->options)
+ {
+ for (i = 0; choice->options[i]; i++)
+ g_variant_builder_add (&choices, "(&s&s)", choice->options[i], choice->option_labels[i]);
+ }
+
+ return g_variant_new ("(&s&s@a(ss)&s)",
+ choice->id,
+ choice->label,
+ g_variant_builder_end (&choices),
+ choice->selected ? choice->selected : "");
+}
+
+static GVariant *
+serialize_choices (GtkFileChooserNative *self)
+{
+ GVariantBuilder builder;
+ GSList *l;
+
+ g_variant_builder_init (&builder, G_VARIANT_TYPE ("a(ssa(ss)s)"));
+ for (l = self->choices; l; l = l->next)
+ {
+ GtkFileChooserNativeChoice *choice = l->data;
+
+ g_variant_builder_add (&builder, "@(ssa(ss)s)",
+ gtk_file_chooser_native_choice_to_variant (choice));
+ }
+
+ return g_variant_builder_end (&builder);
+}
+
gboolean
gtk_file_chooser_native_portal_show (GtkFileChooserNative *self)
{
@@ -339,11 +338,6 @@ gtk_file_chooser_native_portal_show (GtkFileChooserNative *self)
data->self = g_object_ref (self);
data->connection = connection;
- if (strcmp (method_name, "OpenFiles") == 0)
- data->signal_callback = multi_file_response;
- else
- data->signal_callback = one_file_response;
-
message = g_dbus_message_new_method_call ("org.freedesktop.portal.Desktop",
"/org/freedesktop/portal/desktop",
"org.freedesktop.portal.FileChooser",
@@ -401,6 +395,10 @@ gtk_file_chooser_native_portal_show (GtkFileChooserNative *self)
g_free (path);
}
+ if (GTK_FILE_CHOOSER_NATIVE (self)->choices)
+ g_variant_builder_add (&opt_builder, "{sv}", "choices",
+ serialize_choices (GTK_FILE_CHOOSER_NATIVE (self)));
+
g_dbus_message_set_body (message,
g_variant_new ("(ss@a{sv})",
parent_window_str ? parent_window_str : "",
diff --git a/gtk/gtkfilechoosernativeprivate.h b/gtk/gtkfilechoosernativeprivate.h
index d2eedba..9a932ec 100644
--- a/gtk/gtkfilechoosernativeprivate.h
+++ b/gtk/gtkfilechoosernativeprivate.h
@@ -23,6 +23,14 @@
G_BEGIN_DECLS
+typedef struct {
+ char *id;
+ char *label;
+ char **options;
+ char **option_labels;
+ char *selected;
+} GtkFileChooserNativeChoice;
+
struct _GtkFileChooserNative
{
GtkNativeDialog parent_instance;
@@ -36,6 +44,7 @@ struct _GtkFileChooserNative
GFile *current_folder;
GFile *current_file;
char *current_name;
+ GSList *choices;
/* Fallback mode */
GtkWidget *dialog;
diff --git a/gtk/gtkfilechooserprivate.h b/gtk/gtkfilechooserprivate.h
index 2280da9..0094beb 100644
--- a/gtk/gtkfilechooserprivate.h
+++ b/gtk/gtkfilechooserprivate.h
@@ -87,7 +87,7 @@ struct _GtkFileChooserIface
GFile *file,
GError **error);
GSList * (*list_shortcut_folders) (GtkFileChooser *chooser);
-
+
/* Signals
*/
void (*current_folder_changed) (GtkFileChooser *chooser);
@@ -95,6 +95,20 @@ struct _GtkFileChooserIface
void (*update_preview) (GtkFileChooser *chooser);
void (*file_activated) (GtkFileChooser *chooser);
GtkFileChooserConfirmation (*confirm_overwrite) (GtkFileChooser *chooser);
+
+ /* 3.22 additions */
+ void (*add_choice) (GtkFileChooser *chooser,
+ const char *id,
+ const char *label,
+ const char **options,
+ const char **option_labels);
+ void (*remove_choice) (GtkFileChooser *chooser,
+ const char *id);
+ void (*set_choice) (GtkFileChooser *chooser,
+ const char *id,
+ const char *option);
+ const char * (*get_choice) (GtkFileChooser *chooser,
+ const char *id);
};
GtkFileSystem *_gtk_file_chooser_get_file_system (GtkFileChooser *chooser);
diff --git a/gtk/gtkfilechooserutils.c b/gtk/gtkfilechooserutils.c
index 53246ca..7965ab0 100644
--- a/gtk/gtkfilechooserutils.c
+++ b/gtk/gtkfilechooserutils.c
@@ -68,6 +68,19 @@ static void delegate_file_activated (GtkFileChooser *choose
static GtkFileChooserConfirmation delegate_confirm_overwrite (GtkFileChooser *chooser,
gpointer data);
+static void delegate_add_choice (GtkFileChooser *chooser,
+ const char *id,
+ const char *label,
+ const char **options,
+ const char **option_labels);
+static void delegate_remove_choice (GtkFileChooser *chooser,
+ const char *id);
+static void delegate_set_choice (GtkFileChooser *chooser,
+ const char *id,
+ const char *option);
+static const char * delegate_get_choice (GtkFileChooser *chooser,
+ const char *id);
+
/**
* _gtk_file_chooser_install_properties:
@@ -149,6 +162,10 @@ _gtk_file_chooser_delegate_iface_init (GtkFileChooserIface *iface)
iface->add_shortcut_folder = delegate_add_shortcut_folder;
iface->remove_shortcut_folder = delegate_remove_shortcut_folder;
iface->list_shortcut_folders = delegate_list_shortcut_folders;
+ iface->add_choice = delegate_add_choice;
+ iface->remove_choice = delegate_remove_choice;
+ iface->set_choice = delegate_set_choice;
+ iface->get_choice = delegate_get_choice;
}
/**
@@ -499,3 +516,35 @@ _gtk_file_chooser_label_for_file (GFile *file)
return label;
}
+static void
+delegate_add_choice (GtkFileChooser *chooser,
+ const char *id,
+ const char *label,
+ const char **options,
+ const char **option_labels)
+{
+ gtk_file_chooser_add_choice (get_delegate (chooser),
+ id, label, options, option_labels);
+}
+static void
+delegate_remove_choice (GtkFileChooser *chooser,
+ const char *id)
+{
+ gtk_file_chooser_remove_choice (get_delegate (chooser), id);
+}
+
+static void
+delegate_set_choice (GtkFileChooser *chooser,
+ const char *id,
+ const char *option)
+{
+ gtk_file_chooser_set_choice (get_delegate (chooser), id, option);
+}
+
+
+static const char *
+delegate_get_choice (GtkFileChooser *chooser,
+ const char *id)
+{
+ return gtk_file_chooser_get_choice (get_delegate (chooser), id);
+}
diff --git a/gtk/gtkfilechooserwidget.c b/gtk/gtkfilechooserwidget.c
index 79a099e..a9868f2 100644
--- a/gtk/gtkfilechooserwidget.c
+++ b/gtk/gtkfilechooserwidget.c
@@ -66,6 +66,7 @@
#include "gtktreeprivate.h"
#include "gtktreeselection.h"
#include "gtkbox.h"
+#include "gtkcheckbutton.h"
#include "gtkwindowgroup.h"
#include "gtkintl.h"
#include "gtkshow.h"
@@ -289,6 +290,9 @@ struct _GtkFileChooserWidgetPrivate {
GtkWidget *external_entry;
+ GtkWidget *choice_box;
+ GHashTable *choices;
+
/* Handles */
GCancellable *file_list_drag_data_received_cancellable;
GCancellable *update_current_folder_cancellable;
@@ -507,6 +511,20 @@ static void gtk_file_chooser_widget_get_default_size (GtkFileCho
static gboolean gtk_file_chooser_widget_should_respond (GtkFileChooserEmbed *chooser_embed);
static void gtk_file_chooser_widget_initial_focus (GtkFileChooserEmbed *chooser_embed);
+static void gtk_file_chooser_widget_add_choice (GtkFileChooser *chooser,
+ const char *id,
+ const char *label,
+ const char **options,
+ const char **option_labels);
+static void gtk_file_chooser_widget_remove_choice (GtkFileChooser *chooser,
+ const char *id);
+static void gtk_file_chooser_widget_set_choice (GtkFileChooser *chooser,
+ const char *id,
+ const char *option);
+static const char *gtk_file_chooser_widget_get_choice (GtkFileChooser *chooser,
+ const char *id);
+
+
static void add_selection_to_recent_list (GtkFileChooserWidget *impl);
static void location_popup_handler (GtkFileChooserWidget *impl,
@@ -625,6 +643,10 @@ gtk_file_chooser_widget_iface_init (GtkFileChooserIface *iface)
iface->add_shortcut_folder = gtk_file_chooser_widget_add_shortcut_folder;
iface->remove_shortcut_folder = gtk_file_chooser_widget_remove_shortcut_folder;
iface->list_shortcut_folders = gtk_file_chooser_widget_list_shortcut_folders;
+ iface->add_choice = gtk_file_chooser_widget_add_choice;
+ iface->remove_choice = gtk_file_chooser_widget_remove_choice;
+ iface->set_choice = gtk_file_chooser_widget_set_choice;
+ iface->get_choice = gtk_file_chooser_widget_get_choice;
}
static void
@@ -8676,3 +8698,124 @@ gtk_file_chooser_widget_new (GtkFileChooserAction action)
"action", action,
NULL);
}
+
+static void
+gtk_file_chooser_widget_add_choice (GtkFileChooser *chooser,
+ const char *id,
+ const char *label,
+ const char **options,
+ const char **option_labels)
+{
+ GtkFileChooserWidget *impl = GTK_FILE_CHOOSER_WIDGET (chooser);
+ GtkFileChooserWidgetPrivate *priv = impl->priv;
+ GtkWidget *widget;
+
+ if (priv->choices == NULL)
+ {
+ priv->choices = g_hash_table_new (g_str_hash, g_str_equal);
+ priv->choice_box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 12);
+ set_extra_widget (impl, priv->choice_box);
+ }
+ else if (g_hash_table_lookup (priv->choices, id))
+ {
+ g_warning ("Duplicate choice %s", id);
+ return;
+ }
+
+ if (options)
+ {
+ GtkWidget *box;
+ GtkWidget *combo;
+ int i;
+
+ box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6);
+ gtk_container_add (GTK_CONTAINER (box), gtk_label_new (label));
+
+ combo = gtk_combo_box_text_new ();
+ g_hash_table_insert (priv->choices, g_strdup (id), combo);
+ gtk_container_add (GTK_CONTAINER (box), combo);
+
+ for (i = 0; options[i]; i++)
+ gtk_combo_box_text_append (GTK_COMBO_BOX_TEXT (combo),
+ options[i], option_labels[i]);
+
+ widget = box;
+ }
+ else
+ {
+ GtkWidget *check;
+
+ check = gtk_check_button_new_with_label (label);
+ g_hash_table_insert (priv->choices, g_strdup (id), check);
+
+ widget = check;
+ }
+
+ gtk_widget_show_all (widget);
+ gtk_container_add (GTK_CONTAINER (priv->choice_box), widget);
+}
+
+static void
+gtk_file_chooser_widget_remove_choice (GtkFileChooser *chooser,
+ const char *id)
+{
+ GtkFileChooserWidget *impl = GTK_FILE_CHOOSER_WIDGET (chooser);
+ GtkFileChooserWidgetPrivate *priv = impl->priv;
+ GtkWidget *widget;
+
+ if (priv->choices == NULL)
+ return;
+
+ widget = (GtkWidget *)g_hash_table_lookup (priv->choices, id);
+ g_hash_table_remove (priv->choices, id);
+ gtk_container_remove (GTK_CONTAINER (priv->choice_box), widget);
+
+ if (g_hash_table_size (priv->choices) == 0)
+ {
+ set_extra_widget (impl, NULL);
+ g_hash_table_unref (priv->choices);
+ priv->choices = NULL;
+ priv->choice_box = NULL;
+ }
+}
+
+static void
+gtk_file_chooser_widget_set_choice (GtkFileChooser *chooser,
+ const char *id,
+ const char *option)
+{
+ GtkFileChooserWidget *impl = GTK_FILE_CHOOSER_WIDGET (chooser);
+ GtkFileChooserWidgetPrivate *priv = impl->priv;
+ GtkWidget *widget;
+
+ if (priv->choices == NULL)
+ return;
+
+ widget = (GtkWidget *)g_hash_table_lookup (priv->choices, id);
+
+ if (GTK_IS_COMBO_BOX (widget))
+ gtk_combo_box_set_active_id (GTK_COMBO_BOX (widget), option);
+ else if (GTK_IS_TOGGLE_BUTTON (widget))
+ gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (widget), g_str_equal (option, "true"));
+}
+
+static const char *
+gtk_file_chooser_widget_get_choice (GtkFileChooser *chooser,
+ const char *id)
+{
+ GtkFileChooserWidget *impl = GTK_FILE_CHOOSER_WIDGET (chooser);
+ GtkFileChooserWidgetPrivate *priv = impl->priv;
+ GtkWidget *widget;
+
+ if (priv->choices == NULL)
+ return NULL;
+
+ widget = (GtkWidget *)g_hash_table_lookup (priv->choices, id);
+ if (GTK_IS_COMBO_BOX (widget))
+ return gtk_combo_box_get_active_id (GTK_COMBO_BOX (widget));
+ else if (GTK_IS_TOGGLE_BUTTON (widget))
+ return gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget)) ? "true" : "false";
+
+ return NULL;
+}
+
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]