diff options
author | Cosimo Cecchi <cosimoc@gnome.org> | 2010-11-25 17:17:45 +0100 |
---|---|---|
committer | Cosimo Cecchi <cosimoc@gnome.org> | 2010-11-25 17:30:01 +0100 |
commit | 67e842be87f7fca790a8172042304dbe11be6ca3 (patch) | |
tree | 4b5b8701b51ab6ef16ddea0dc315ec0af9e78778 | |
parent | a498d9a9bac007fb2b9b7ab3a960b853818867c2 (diff) | |
download | gtk+-67e842be87f7fca790a8172042304dbe11be6ca3.tar.gz |
app-chooser-combobox: add a method to trigger the GtkAppChooserDialog
It's an optional special item in the combobox, turned off by default.
-rw-r--r-- | gtk/gtkappchoosercombobox.c | 252 | ||||
-rw-r--r-- | gtk/gtkappchoosercombobox.h | 4 | ||||
-rw-r--r-- | tests/testappchoosercombo.c | 3 |
3 files changed, 238 insertions, 21 deletions
diff --git a/gtk/gtkappchoosercombobox.c b/gtk/gtkappchoosercombobox.c index 625f536ca0..db7d5327b1 100644 --- a/gtk/gtkappchoosercombobox.c +++ b/gtk/gtkappchoosercombobox.c @@ -26,14 +26,18 @@ #include "gtkappchoosercombobox.h" #include "gtkappchooser.h" +#include "gtkappchooserdialog.h" #include "gtkappchooserprivate.h" #include "gtkcelllayout.h" #include "gtkcellrendererpixbuf.h" #include "gtkcellrenderertext.h" #include "gtkcombobox.h" +#include "gtkdialog.h" +#include "gtkintl.h" enum { PROP_CONTENT_TYPE = 1, + PROP_SHOW_DIALOG_ITEM, }; enum { @@ -78,13 +82,27 @@ G_DEFINE_BOXED_TYPE (CustomAppComboData, custom_app_combo_data, static void app_chooser_iface_init (GtkAppChooserIface *iface); +static void real_insert_custom_item (GtkAppChooserComboBox *self, + const gchar *label, + GIcon *icon, + GtkAppChooserComboBoxItemFunc func, + gpointer user_data, + gboolean custom, + GtkTreeIter *iter); + +static void real_insert_separator (GtkAppChooserComboBox *self, + gboolean custom, + GtkTreeIter *iter); + G_DEFINE_TYPE_WITH_CODE (GtkAppChooserComboBox, gtk_app_chooser_combo_box, GTK_TYPE_COMBO_BOX, G_IMPLEMENT_INTERFACE (GTK_TYPE_APP_CHOOSER, app_chooser_iface_init)); struct _GtkAppChooserComboBoxPrivate { - gchar *content_type; GtkListStore *store; + + gchar *content_type; + gboolean show_dialog_item; }; static gboolean @@ -119,6 +137,140 @@ get_first_iter (GtkListStore *store, } } +typedef struct { + GtkAppChooserComboBox *self; + GAppInfo *info; + gint active_index; +} SelectAppData; + +static void +select_app_data_free (SelectAppData *data) +{ + g_clear_object (&data->self); + g_clear_object (&data->info); + + g_slice_free (SelectAppData, data); +} + +static gboolean +select_application_func_cb (GtkTreeModel *model, + GtkTreePath *path, + GtkTreeIter *iter, + gpointer user_data) +{ + SelectAppData *data = user_data; + GAppInfo *app_to_match = data->info, *app = NULL; + gboolean custom; + + gtk_tree_model_get (model, iter, + COLUMN_APP_INFO, &app, + COLUMN_CUSTOM, &custom, + -1); + + /* cutsom items are always after GAppInfos, so iterating further here + * is just useless. + */ + if (custom) + return TRUE; + + if (g_app_info_equal (app, app_to_match)) + { + gtk_combo_box_set_active_iter (GTK_COMBO_BOX (data->self), iter); + return TRUE; + } + + return FALSE; +} + +static void +gtk_app_chooser_combo_box_select_application (GtkAppChooserComboBox *self, + GAppInfo *info) +{ + SelectAppData *data; + + data = g_slice_new0 (SelectAppData); + data->self = g_object_ref (self); + data->info = g_object_ref (info); + + gtk_tree_model_foreach (GTK_TREE_MODEL (self->priv->store), + select_application_func_cb, data); + + select_app_data_free (data); +} + +static void +other_application_dialog_response_cb (GtkDialog *dialog, + gint response_id, + gpointer user_data) +{ + GtkAppChooserComboBox *self = user_data; + GAppInfo *info; + + if (response_id != GTK_RESPONSE_OK) + { + /* reset the active item, otherwise we are stuck on + * 'Other application...' + */ + gtk_combo_box_set_active (GTK_COMBO_BOX (self), 0); + gtk_widget_destroy (GTK_WIDGET (dialog)); + return; + } + + info = gtk_app_chooser_get_app_info (GTK_APP_CHOOSER (dialog)); + + /* refresh the combobox to get the new application */ + gtk_app_chooser_refresh (GTK_APP_CHOOSER (self)); + gtk_app_chooser_combo_box_select_application (self, info); + + g_object_unref (info); +} + +static void +other_application_item_activated_cb (GtkAppChooserComboBox *self, + gpointer _user_data) +{ + GtkWidget *dialog, *widget; + GtkWindow *toplevel; + + toplevel = GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (self))); + dialog = gtk_app_chooser_dialog_new_for_content_type (toplevel, GTK_DIALOG_DESTROY_WITH_PARENT, + self->priv->content_type); + widget = gtk_app_chooser_dialog_get_widget (GTK_APP_CHOOSER_DIALOG (dialog)); + g_object_set (widget, + "show-fallback", TRUE, + "show-other", TRUE, + NULL); + gtk_widget_show (dialog); + + g_signal_connect (dialog, "response", + G_CALLBACK (other_application_dialog_response_cb), self); +} + +static void +gtk_app_chooser_combo_box_ensure_dialog_item (GtkAppChooserComboBox *self, + GtkTreeIter *prev_iter) +{ + GIcon *icon; + GtkTreeIter iter; + + if (!self->priv->show_dialog_item) + return; + + icon = g_themed_icon_new ("application-x-executable"); + + gtk_list_store_insert_after (self->priv->store, &iter, prev_iter); + real_insert_separator (self, FALSE, &iter); + *prev_iter = iter; + + gtk_list_store_insert_after (self->priv->store, &iter, prev_iter); + real_insert_custom_item (self, + _("Other application..."), icon, + other_application_item_activated_cb, + NULL, FALSE, &iter); + + g_object_unref (icon); +} + static void gtk_app_chooser_combo_box_populate (GtkAppChooserComboBox *self) { @@ -163,6 +315,7 @@ gtk_app_chooser_combo_box_populate (GtkAppChooserComboBox *self) g_object_unref (icon); } + gtk_app_chooser_combo_box_ensure_dialog_item (self, &iter); gtk_combo_box_set_active (GTK_COMBO_BOX (self), 0); } @@ -195,6 +348,7 @@ gtk_app_chooser_combo_box_build_ui (GtkAppChooserComboBox *self) gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (self), cell, TRUE); gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (self), cell, "text", COLUMN_NAME, + "xpad", 6, NULL); gtk_app_chooser_combo_box_populate (self); @@ -228,20 +382,16 @@ gtk_app_chooser_combo_box_changed (GtkComboBox *object) { GtkAppChooserComboBox *self = GTK_APP_CHOOSER_COMBO_BOX (object); GtkTreeIter iter; - gboolean custom, separator; CustomAppComboData *custom_data = NULL; if (!gtk_combo_box_get_active_iter (object, &iter)) return; gtk_tree_model_get (GTK_TREE_MODEL (self->priv->store), &iter, - COLUMN_CUSTOM, &custom, - COLUMN_SEPARATOR, &separator, COLUMN_CALLBACK, &custom_data, -1); - if (custom && !separator && - custom_data != NULL && custom_data->func != NULL) + if (custom_data != NULL && custom_data->func != NULL) custom_data->func (self, custom_data->user_data); } @@ -297,6 +447,9 @@ gtk_app_chooser_combo_box_set_property (GObject *obj, case PROP_CONTENT_TYPE: self->priv->content_type = g_value_dup_string (value); break; + case PROP_SHOW_DIALOG_ITEM: + gtk_app_chooser_combo_box_set_show_dialog_item (self, g_value_get_boolean (value)); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, property_id, pspec); break; @@ -316,6 +469,9 @@ gtk_app_chooser_combo_box_get_property (GObject *obj, case PROP_CONTENT_TYPE: g_value_set_string (value, self->priv->content_type); break; + case PROP_SHOW_DIALOG_ITEM: + g_value_set_boolean (value, self->priv->show_dialog_item); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, property_id, pspec); break; @@ -344,6 +500,7 @@ gtk_app_chooser_combo_box_class_init (GtkAppChooserComboBoxClass *klass) { GObjectClass *oclass = G_OBJECT_CLASS (klass); GtkComboBoxClass *combo_class = GTK_COMBO_BOX_CLASS (klass); + GParamSpec *pspec; oclass->set_property = gtk_app_chooser_combo_box_set_property; oclass->get_property = gtk_app_chooser_combo_box_get_property; @@ -354,6 +511,13 @@ gtk_app_chooser_combo_box_class_init (GtkAppChooserComboBoxClass *klass) g_object_class_override_property (oclass, PROP_CONTENT_TYPE, "content-type"); + pspec = g_param_spec_boolean ("show-dialog-item", + P_("Include an 'Other...' item"), + P_("Whether the combobox should include an item that triggers a GtkAppChooserDialog"), + FALSE, + G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS); + g_object_class_install_property (oclass, PROP_SHOW_DIALOG_ITEM, pspec); + g_type_class_add_private (klass, sizeof (GtkAppChooserComboBoxPrivate)); } @@ -364,6 +528,41 @@ gtk_app_chooser_combo_box_init (GtkAppChooserComboBox *self) GtkAppChooserComboBoxPrivate); } +static void +real_insert_custom_item (GtkAppChooserComboBox *self, + const gchar *label, + GIcon *icon, + GtkAppChooserComboBoxItemFunc func, + gpointer user_data, + gboolean custom, + GtkTreeIter *iter) +{ + CustomAppComboData *data; + + data = g_slice_new0 (CustomAppComboData); + data->func = func; + data->user_data = user_data; + + gtk_list_store_set (self->priv->store, iter, + COLUMN_NAME, label, + COLUMN_ICON, icon, + COLUMN_CALLBACK, data, + COLUMN_CUSTOM, custom, + COLUMN_SEPARATOR, FALSE, + -1); +} + +static void +real_insert_separator (GtkAppChooserComboBox *self, + gboolean custom, + GtkTreeIter *iter) +{ + gtk_list_store_set (self->priv->store, iter, + COLUMN_CUSTOM, custom, + COLUMN_SEPARATOR, TRUE, + -1); +} + /** * gtk_app_chooser_combo_box_new: * @content_type: the content type to show applications for @@ -402,10 +601,7 @@ gtk_app_chooser_combo_box_append_separator (GtkAppChooserComboBox *self) g_return_if_fail (GTK_IS_APP_CHOOSER_COMBO_BOX (self)); gtk_list_store_append (self->priv->store, &iter); - gtk_list_store_set (self->priv->store, &iter, - COLUMN_CUSTOM, TRUE, - COLUMN_SEPARATOR, TRUE, - -1); + real_insert_separator (self, TRUE, &iter); } /** @@ -429,18 +625,32 @@ gtk_app_chooser_combo_box_append_custom_item (GtkAppChooserComboBox *sel gpointer user_data) { GtkTreeIter iter; - CustomAppComboData *data; - data = g_slice_new0 (CustomAppComboData); - data->func = func; - data->user_data = user_data; + g_return_if_fail (GTK_IS_APP_CHOOSER_COMBO_BOX (self)); gtk_list_store_append (self->priv->store, &iter); - gtk_list_store_set (self->priv->store, &iter, - COLUMN_NAME, label, - COLUMN_ICON, icon, - COLUMN_CALLBACK, data, - COLUMN_CUSTOM, TRUE, - COLUMN_SEPARATOR, FALSE, - -1); + real_insert_custom_item (self, label, icon, + func, user_data, TRUE, &iter); +} + +gboolean +gtk_app_chooser_combo_box_get_show_dialog_item (GtkAppChooserComboBox *self) +{ + g_return_val_if_fail (GTK_IS_APP_CHOOSER_COMBO_BOX (self), FALSE); + + return self->priv->show_dialog_item; +} + +void +gtk_app_chooser_combo_box_set_show_dialog_item (GtkAppChooserComboBox *self, + gboolean setting) +{ + if (self->priv->show_dialog_item != setting) + { + self->priv->show_dialog_item = setting; + + g_object_notify (G_OBJECT (self), "show-dialog-item"); + + gtk_app_chooser_refresh (GTK_APP_CHOOSER (self)); + } } diff --git a/gtk/gtkappchoosercombobox.h b/gtk/gtkappchoosercombobox.h index b124c7a65e..e593031799 100644 --- a/gtk/gtkappchoosercombobox.h +++ b/gtk/gtkappchoosercombobox.h @@ -70,4 +70,8 @@ void gtk_app_chooser_combo_box_append_custom_item (GtkAppChooserComboBox GtkAppChooserComboBoxItemFunc func, gpointer user_data); +void gtk_app_chooser_combo_box_set_show_dialog_item (GtkAppChooserComboBox *self, + gboolean setting); +gboolean gtk_app_chooser_combo_box_get_show_dialog_item (GtkAppChooserComboBox *self); + #endif /* __GTK_APP_CHOOSER_COMBO_BOX_H__ */ diff --git a/tests/testappchoosercombo.c b/tests/testappchoosercombo.c index 59a44fa496..d393aece89 100644 --- a/tests/testappchoosercombo.c +++ b/tests/testappchoosercombo.c @@ -92,6 +92,9 @@ main (int argc, special_item_activated_cb, NULL); + gtk_app_chooser_combo_box_set_show_dialog_item (GTK_APP_CHOOSER_COMBO_BOX (combobox), + TRUE); + /* test refresh on a combo */ gtk_app_chooser_refresh (GTK_APP_CHOOSER (combobox)); |