[gtk+/open-with-dialog] app-chooser-combobox: add a method to trigger the GtkAppChooserDialog



commit 67e842be87f7fca790a8172042304dbe11be6ca3
Author: Cosimo Cecchi <cosimoc gnome org>
Date:   Thu Nov 25 17:17:45 2010 +0100

    app-chooser-combobox: add a method to trigger the GtkAppChooserDialog
    
    It's an optional special item in the combobox, turned off by default.

 gtk/gtkappchoosercombobox.c |  252 +++++++++++++++++++++++++++++++++++++++----
 gtk/gtkappchoosercombobox.h |    4 +
 tests/testappchoosercombo.c |    3 +
 3 files changed, 238 insertions(+), 21 deletions(-)
---
diff --git a/gtk/gtkappchoosercombobox.c b/gtk/gtkappchoosercombobox.c
index 625f536..db7d532 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 b124c7a..e593031 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 59a44fa..d393aec 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));
 



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