[glade/glade-3-8] Comited backport of GtkComboBoxText support



commit bd1c3ebe3b84137b476e5a1aeb3ffaa3dfb44fc0
Author: Rafał Mużyło <galtgendo o2 pl>
Date:   Mon Oct 7 16:10:06 2013 -0300

    Comited backport of GtkComboBoxText support
    
    Closes Bug 689667 "backport support for GtkComboBoxText"

 plugins/gtk+/Makefile.am             |    5 +-
 plugins/gtk+/glade-gtk.c             |  212 ++++++++++++
 plugins/gtk+/glade-string-list.c     |  618 ++++++++++++++++++++++++++++++++++
 plugins/gtk+/glade-string-list.h     |   43 +++
 plugins/gtk+/gtk+.xml.in             |   23 ++
 plugins/gtk+/icons/16x16/Makefile.am |    1 +
 plugins/gtk+/icons/22x22/Makefile.am |    1 +
 7 files changed, 901 insertions(+), 2 deletions(-)
---
diff --git a/plugins/gtk+/Makefile.am b/plugins/gtk+/Makefile.am
index d70ade1..ee03044 100644
--- a/plugins/gtk+/Makefile.am
+++ b/plugins/gtk+/Makefile.am
@@ -25,7 +25,7 @@ libgladegtk_la_SOURCES     = glade-gtk.c glade-accels.c glade-attributes.c glade
        glade-icon-sources.c glade-button-editor.c glade-tool-button-editor.c glade-image-editor.c \
        glade-image-item-editor.c glade-icon-factory-editor.c glade-store-editor.c glade-label-editor.c \
        glade-cell-renderer-editor.c glade-treeview-editor.c glade-entry-editor.c glade-activatable-editor.c \
-       glade-tool-item-group-editor.c
+       glade-tool-item-group-editor.c glade-string-list.c
 
 libgladegtk_la_LDFLAGS     = -module -avoid-version $(AM_LDFLAGS)
 libgladegtk_la_LIBADD      = $(libgladeui) $(GTK_LIBS)
@@ -35,7 +35,8 @@ libgladegtkinclude_HEADERS = glade-gtk.h glade-accels.h glade-attributes.h glade
        glade-text-button.h glade-icon-sources.h glade-button-editor.h \
        glade-tool-button-editor.h glade-image-editor.h glade-image-item-editor.h glade-icon-factory-editor.h 
\
        glade-store-editor.h glade-label-editor.h glade-cell-renderer-editor.h glade-treeview-editor.h \
-       glade-entry-editor.h glade-activatable-editor.h glade-tool-item-group-editor.h
+       glade-entry-editor.h glade-activatable-editor.h glade-tool-item-group-editor.h \
+       glade-string-list.h
 
 if PLATFORM_WIN32
 libgladegtk_la_LDFLAGS += -no-undefined
diff --git a/plugins/gtk+/glade-gtk.c b/plugins/gtk+/glade-gtk.c
index c784341..e5a1138 100644
--- a/plugins/gtk+/glade-gtk.c
+++ b/plugins/gtk+/glade-gtk.c
@@ -44,6 +44,7 @@
 #include "glade-entry-editor.h"
 #include "glade-activatable-editor.h"
 #include "glade-tool-item-group-editor.h"
+#include "glade-string-list.h"
 
 #include <gladeui/glade-editor-property.h>
 #include <gladeui/glade-base-editor.h>
@@ -9491,6 +9492,217 @@ glade_gtk_combo_box_entry_set_property (GladeWidgetAdaptor *adaptor,
                                                                  id, value);
 }
 
+/* ----------------------------- GtkComboBoxText ------------------------------ */
+#define GLADE_TAG_ITEMS  "items"
+#define GLADE_TAG_ITEM   "item"
+
+void
+glade_gtk_combo_box_text_post_create (GladeWidgetAdaptor *adaptor,
+                                     GObject            *object, 
+                                     GladeCreateReason   reason)
+{
+  GladeWidget *gwidget;
+
+  /* Chain Up */
+  GWA_GET_CLASS (GTK_TYPE_COMBO_BOX)->post_create (adaptor, object, reason);
+
+  /* No editor, no model, no cells on a GtkComboBoxText, just the items. */
+  gwidget = glade_widget_get_from_gobject (object);
+  if (gwidget)
+    glade_widget_get_action (gwidget, "launch_editor")->sensitive = FALSE;
+}
+
+GladeEditorProperty *
+glade_gtk_combo_box_text_create_eprop (GladeWidgetAdaptor * adaptor,
+                                      GladePropertyClass * klass, 
+                                      gboolean use_command)
+{
+  GladeEditorProperty *eprop;
+  GParamSpec          *pspec;
+
+  pspec = klass->pspec;
+
+  if (pspec->value_type == GLADE_TYPE_STRING_LIST)
+    {
+      eprop = glade_eprop_string_list_new (klass, use_command, TRUE);
+    }
+  else
+    eprop = GWA_GET_CLASS
+        (GTK_TYPE_WIDGET)->create_eprop (adaptor, klass, use_command);
+
+  return eprop;
+}
+
+gchar *
+glade_gtk_combo_box_text_string_from_value (GladeWidgetAdaptor * adaptor,
+                                           GladePropertyClass * klass,
+                                           const GValue * value)
+{
+  GParamSpec          *pspec;
+
+  pspec = klass->pspec;
+
+  if (pspec->value_type == GLADE_TYPE_STRING_LIST)
+    {
+      GList *list = g_value_get_boxed (value);
+
+      return glade_string_list_to_string (list);
+    }
+  else
+    return GWA_GET_CLASS
+        (GTK_TYPE_COMBO_BOX)->string_from_value (adaptor, klass, value, GLADE_PROJECT_FORMAT_GTKBUILDER);
+}
+
+void
+glade_gtk_combo_box_text_set_property (GladeWidgetAdaptor * adaptor,
+                                      GObject * object,
+                                      const gchar * id, const GValue * value)
+{
+  if (!strcmp (id, "glade-items"))
+    {
+      GList *string_list, *l;
+      GladeString *string;
+      gint active;
+
+      string_list = g_value_get_boxed (value);
+
+      active = gtk_combo_box_get_active (GTK_COMBO_BOX (object));
+
+      /* Update comboboxtext items */
+      gtk_list_store_clear (GTK_LIST_STORE (gtk_combo_box_get_model (GTK_COMBO_BOX (object))));
+
+      for (l = string_list; l; l = l->next)
+       {
+         string = l->data;
+
+         gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT (object), string->string);
+       }
+
+      gtk_combo_box_set_active (GTK_COMBO_BOX (object),
+                               CLAMP (active, 0, g_list_length (string_list) - 1));
+    }
+  else
+    GWA_GET_CLASS (GTK_TYPE_COMBO_BOX)->set_property (adaptor, object, id, value);
+}
+
+static void
+glade_gtk_combo_box_text_read_items (GladeWidget * widget, GladeXmlNode * node)
+{
+  GladeXmlNode *items_node;
+  GladeXmlNode *item_node;
+  GList        *string_list = NULL;
+
+  if ((items_node =
+       glade_xml_search_child (node, GLADE_TAG_ITEMS)) != NULL)
+    {
+
+      for (item_node = glade_xml_node_get_children (items_node);
+          item_node; item_node = glade_xml_node_next (item_node))
+       {
+         gchar *str, *comment, *context;
+         gboolean translatable;
+
+         if (!glade_xml_node_verify (item_node, GLADE_TAG_ITEM))
+           continue;
+
+          if ((str = glade_xml_get_content (item_node)) == NULL)
+           continue;
+
+         context      = glade_xml_get_property_string (item_node, GLADE_TAG_CONTEXT);
+         comment      = glade_xml_get_property_string (item_node, GLADE_TAG_COMMENT);
+          translatable = glade_xml_get_property_boolean (item_node, GLADE_TAG_TRANSLATABLE, FALSE);
+
+         string_list = 
+           glade_string_list_append (string_list,
+                                     str, comment, context, translatable);
+
+         g_free (str);
+         g_free (context);
+         g_free (comment);
+       }
+
+      glade_widget_property_set (widget, "glade-items", string_list);
+      glade_string_list_free (string_list);
+    }
+}
+
+void
+glade_gtk_combo_box_text_read_widget (GladeWidgetAdaptor * adaptor,
+                                     GladeWidget * widget, GladeXmlNode * node)
+{
+  if (!glade_xml_node_verify (node, GLADE_XML_TAG_WIDGET(GLADE_XML_TAG_BUILDER_WIDGET)))
+    return;
+
+  /* First chain up and read in all the normal properties.. */
+  GWA_GET_CLASS (GTK_TYPE_COMBO_BOX)->read_widget (adaptor, widget, node);
+
+  glade_gtk_combo_box_text_read_items (widget, node);
+}
+
+static void
+glade_gtk_combo_box_text_write_items (GladeWidget * widget,
+                                     GladeXmlContext * context,
+                                     GladeXmlNode * node)
+{
+  GladeXmlNode *item_node;
+  GList *string_list = NULL, *l;
+  GladeString *string;
+
+  if (!glade_widget_property_get (widget, "glade-items", &string_list) || !string_list)
+    return;
+
+  for (l = string_list; l; l = l->next)
+    {
+      string = l->data;
+
+      item_node = glade_xml_node_new (context, GLADE_TAG_ITEM);
+      glade_xml_node_append_child (node, item_node);
+
+      glade_xml_set_content (item_node, string->string);
+
+      if (string->translatable)
+        glade_xml_node_set_property_string (item_node,
+                                            GLADE_TAG_TRANSLATABLE,
+                                            GLADE_XML_TAG_I18N_TRUE);
+
+      if (string->comment)
+        glade_xml_node_set_property_string (item_node,
+                                            GLADE_TAG_COMMENT,
+                                            string->comment);
+
+      if (string->context)
+        glade_xml_node_set_property_string (item_node,
+                                            GLADE_TAG_CONTEXT,
+                                            string->context);
+    }
+}
+
+void
+glade_gtk_combo_box_text_write_widget (GladeWidgetAdaptor * adaptor,
+                                      GladeWidget * widget,
+                                      GladeXmlContext * context, GladeXmlNode * node)
+{
+  GladeXmlNode *attrs_node;
+
+  if (!glade_xml_node_verify (node, GLADE_XML_TAG_WIDGET(GLADE_XML_TAG_BUILDER_WIDGET)))
+    return;
+
+  /* First chain up and read in all the normal properties.. */
+  GWA_GET_CLASS (GTK_TYPE_WIDGET)->write_widget (adaptor, widget, context,
+                                                 node);
+
+  attrs_node = glade_xml_node_new (context, GLADE_TAG_ITEMS);
+
+  glade_gtk_combo_box_text_write_items (widget, context, attrs_node);
+
+  if (!glade_xml_node_get_children (attrs_node))
+    glade_xml_node_delete (attrs_node);
+  else
+    glade_xml_node_append_child (node, attrs_node);
+
+}
+
+
 /* ----------------------------- GtkSpinButton ------------------------------ */
 static void
 glade_gtk_spin_button_set_adjustment (GObject *object, const GValue *value)
diff --git a/plugins/gtk+/glade-string-list.c b/plugins/gtk+/glade-string-list.c
new file mode 100644
index 0000000..085c321
--- /dev/null
+++ b/plugins/gtk+/glade-string-list.c
@@ -0,0 +1,618 @@
+/*
+ * glade-string-list.c - Editing support for lists of translatable strings
+ *
+ * Copyright (C) 2010 Openismus GmbH
+ *
+ * Author(s):
+ *      Tristan Van Berkom <tvb gnome org>
+ *
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public 
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include <config.h>
+
+#include <string.h>
+#include <stdlib.h>
+#include <gdk/gdkkeysyms.h>
+#include <gtk/gtk.h>
+#include <gladeui/glade.h>
+#include <glib/gi18n-lib.h>
+
+#include "glade-string-list.h"
+
+
+/**************************************************************
+ *            GladeStringList boxed type stuff here           *
+ **************************************************************/
+static GladeString *
+glade_string_new (const gchar *string,
+                 const gchar *comment,
+                 const gchar *context,
+                 gboolean     translatable)
+{
+  GladeString *gstring = g_slice_new0 (GladeString);
+
+  gstring->string       = g_strdup (string);
+  gstring->comment      = g_strdup (comment);
+  gstring->context      = g_strdup (context);
+  gstring->translatable = translatable;
+
+  return gstring;
+}
+
+static GladeString *
+glade_string_copy (GladeString *string)
+{
+  return glade_string_new (string->string, 
+                          string->comment, 
+                          string->context, 
+                          string->translatable);
+}
+
+static void
+glade_string_free (GladeString *string)
+{
+  g_free (string->string);
+  g_free (string->comment);
+  g_free (string->context);
+  g_slice_free (GladeString, string);
+}
+
+GList *
+glade_string_list_append (GList   *list,
+                         gchar   *string,
+                         gchar   *comment,
+                         gchar   *context,
+                         gboolean translatable)
+{
+  GladeString *gstring;
+
+  gstring = glade_string_new (string, comment, context, translatable);
+
+  return g_list_append (list, gstring);
+}
+
+GList *
+glade_string_list_copy (GList *string_list)
+{
+  GList *ret = NULL, *list;
+  GladeString *string, *copy;
+
+  for (list = string_list; list; list = list->next)
+    {
+      string = list->data;
+
+      copy = glade_string_copy (string);
+
+      ret = g_list_prepend (ret, copy);
+    }
+
+  return g_list_reverse (ret);
+}
+
+void
+glade_string_list_free (GList * string_list)
+{
+  g_list_foreach (string_list, (GFunc)glade_string_free, NULL);
+  g_list_free (string_list);
+}
+
+GType
+glade_string_list_get_type (void)
+{
+  static GType type_id = 0;
+
+  if (!type_id)
+    type_id = g_boxed_type_register_static
+        ("GladeStringList",
+         (GBoxedCopyFunc) glade_string_list_copy,
+         (GBoxedFreeFunc) glade_string_list_free);
+  return type_id;
+}
+
+
+gchar *
+glade_string_list_to_string (GList   *list)
+{
+  GString *string = g_string_new ("");
+  GList *l;
+
+  for (l = list; l; l = l->next)
+    {
+      GladeString *str = l->data;
+
+      if (l != list)
+       g_string_append_c (string, ',');
+
+      g_string_append_printf (string, "%s:%s:%s:%d", 
+                             str->string,
+                             str->comment ? str->comment : "",
+                             str->context ? str->context : "",
+                             str->translatable);
+    }
+
+  return g_string_free (string, FALSE);
+}
+
+/**************************************************************
+ *              GladeEditorProperty stuff here
+ **************************************************************/
+typedef struct
+{
+  GladeEditorProperty parent_instance;
+
+  GtkTreeModel *model;
+  GtkWidget    *view;
+
+  guint  translatable : 1;
+  guint  want_focus : 1;
+
+  guint  editing_index;
+
+  guint  changed_id;
+  guint  update_id;
+  GList *pending_string_list;
+} GladeEPropStringList;
+
+enum
+{
+  COLUMN_STRING,
+  COLUMN_INDEX,
+  COLUMN_DUMMY,
+  NUM_COLUMNS
+};
+
+GLADE_MAKE_EPROP (GladeEPropStringList, glade_eprop_string_list)
+#define GLADE_EPROP_STRING_LIST(obj)                                   \
+  (G_TYPE_CHECK_INSTANCE_CAST ((obj), GLADE_TYPE_EPROP_STRING_LIST, GladeEPropStringList))
+
+static void
+glade_eprop_string_list_finalize (GObject * object)
+{
+  GladeEPropStringList *eprop_string_list = GLADE_EPROP_STRING_LIST (object);
+  GObjectClass *parent_class =
+      g_type_class_peek_parent (G_OBJECT_GET_CLASS (object));
+
+  if (eprop_string_list->update_id)
+    {
+      g_source_remove (eprop_string_list->update_id);
+      eprop_string_list->update_id = 0;
+    }
+
+  if (eprop_string_list->changed_id)
+    {
+      g_source_remove (eprop_string_list->changed_id);
+      eprop_string_list->changed_id = 0;
+    }
+
+  if (eprop_string_list->pending_string_list)
+    {
+      glade_string_list_free (eprop_string_list->pending_string_list);
+      eprop_string_list->pending_string_list = NULL;
+    }
+
+  /* Chain up */
+  G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static gboolean
+update_string_list_idle (GladeEditorProperty * eprop)
+{
+  GladeEPropStringList *eprop_string_list = GLADE_EPROP_STRING_LIST (eprop);
+  GValue value = { 0, };
+
+  eprop_string_list->want_focus = TRUE;
+
+  g_value_init (&value, GLADE_TYPE_STRING_LIST);
+  g_value_take_boxed (&value, eprop_string_list->pending_string_list);
+  glade_editor_property_commit (eprop, &value);
+  g_value_unset (&value);
+
+  eprop_string_list->want_focus = FALSE;
+
+  eprop_string_list->pending_string_list = NULL;
+  eprop_string_list->update_id = 0;
+    
+  return FALSE;
+}
+
+static gboolean
+data_changed_idle (GladeEditorProperty *eprop)
+{
+  GladeEPropStringList *eprop_string_list = GLADE_EPROP_STRING_LIST (eprop);
+  GladeProperty        *property = eprop->property;
+  GladeString          *string, *copy;
+  GList                *string_list = NULL;
+  GList                *new_list = NULL;
+  GtkTreeIter           iter;
+  guint                 index;
+
+  /* Create a new list based on the order and contents
+   * of the model state */
+  glade_property_get (property, &string_list);
+
+  if (gtk_tree_model_get_iter_first (eprop_string_list->model, &iter))
+    {
+      do
+        {
+          gtk_tree_model_get (eprop_string_list->model, &iter,
+                              COLUMN_INDEX, &index, -1);
+
+          if ((string = g_list_nth_data (string_list, index)) != NULL)
+            {
+             copy = glade_string_copy (string);
+             new_list = g_list_prepend (new_list, copy);
+            }
+        }
+      while (gtk_tree_model_iter_next (eprop_string_list->model, &iter));
+    }
+
+  new_list = g_list_reverse (new_list);
+
+  if (eprop_string_list->pending_string_list)
+    glade_string_list_free (eprop_string_list->pending_string_list);
+  eprop_string_list->pending_string_list = new_list;
+
+  /* We're already in an idle, just call it directly here */
+  update_string_list_idle (eprop);
+
+  eprop_string_list->changed_id = 0;
+  return FALSE;
+}
+
+static void
+row_deleted (GtkTreeModel * tree_model,
+            GtkTreePath * path, GladeEditorProperty * eprop)
+{
+  GladeEPropStringList *eprop_string_list = GLADE_EPROP_STRING_LIST (eprop);
+
+  if (eprop->loading)
+    return;
+
+  eprop_string_list->editing_index = 0;
+
+  if (eprop_string_list->changed_id == 0)
+    eprop_string_list->changed_id = 
+      g_idle_add ((GSourceFunc) data_changed_idle, eprop);
+}
+
+static void
+glade_eprop_string_list_load (GladeEditorProperty * eprop, GladeProperty * property)
+{
+  GladeEPropStringList *eprop_string_list = GLADE_EPROP_STRING_LIST (eprop);
+  GladeEditorPropertyClass *parent_class =
+      g_type_class_peek_parent (G_OBJECT_GET_CLASS (eprop));
+  GList *string_list, *list;
+  GtkTreeIter iter;
+  guint i;
+
+  g_signal_handlers_block_by_func (eprop_string_list->model, row_deleted, eprop);
+  gtk_list_store_clear (GTK_LIST_STORE (eprop_string_list->model));
+  g_signal_handlers_unblock_by_func (eprop_string_list->model, row_deleted, eprop);
+
+  parent_class->load (eprop, property);
+
+  if (!property)
+    return;
+
+  glade_property_get (property, &string_list);
+
+  for (list = string_list, i = 0; list; list = list->next, i++)
+    {
+      GladeString *string = list->data;
+
+      gtk_list_store_append (GTK_LIST_STORE (eprop_string_list->model), &iter);
+      gtk_list_store_set (GTK_LIST_STORE (eprop_string_list->model), &iter,
+                         COLUMN_STRING, string->string,
+                         COLUMN_INDEX, i,
+                         COLUMN_DUMMY, FALSE,
+                         -1);
+    }
+
+  gtk_list_store_append (GTK_LIST_STORE (eprop_string_list->model), &iter);
+  gtk_list_store_set (GTK_LIST_STORE (eprop_string_list->model), &iter,
+                     COLUMN_STRING, _("<Type Here>"),
+                     COLUMN_INDEX, i,
+                     COLUMN_DUMMY, TRUE,
+                     -1);
+
+  if (eprop_string_list->want_focus)
+    {
+      GtkTreePath *path = gtk_tree_path_new_from_indices (eprop_string_list->editing_index, -1);
+      GtkTreeViewColumn *column = gtk_tree_view_get_column (GTK_TREE_VIEW (eprop_string_list->view), 0);
+
+      gtk_widget_grab_focus (eprop_string_list->view);
+      gtk_tree_view_set_cursor (GTK_TREE_VIEW (eprop_string_list->view), path, column, FALSE);
+
+      gtk_tree_path_free (path);
+    }
+}
+
+static void
+string_edited (GtkCellRendererText *renderer,
+              gchar               *path,
+              gchar               *new_text,
+              GladeEditorProperty *eprop)
+{
+  GladeEPropStringList *eprop_string_list = GLADE_EPROP_STRING_LIST (eprop);
+  GtkTreePath          *tree_path = gtk_tree_path_new_from_string (path);
+  GtkTreeIter           iter;
+  gboolean              dummy;
+  guint                 index;
+  GladeProperty        *property = eprop->property;
+  GList                *string_list = NULL;
+
+  gtk_tree_model_get_iter (eprop_string_list->model, &iter, tree_path);
+  gtk_tree_model_get (eprop_string_list->model, &iter,
+                     COLUMN_INDEX, &index,
+                     COLUMN_DUMMY, &dummy,
+                     -1);
+
+  glade_property_get (property, &string_list);
+
+  if (string_list)
+    string_list = glade_string_list_copy (string_list);
+
+  if (dummy)
+    {
+      if (new_text && new_text[0] && strcmp (new_text, _("<Type Here>")) != 0)
+       string_list = 
+         glade_string_list_append (string_list,
+                                   new_text, NULL, NULL, 
+                                   eprop_string_list->translatable);
+    }
+  else if (new_text && new_text[0])
+    {
+      GladeString *string = 
+       g_list_nth_data (string_list, index);
+
+      g_free (string->string);
+      string->string = g_strdup (new_text);
+    }
+  else
+    {
+      GList *node = g_list_nth (string_list, index);
+      glade_string_free (node->data);
+      string_list = 
+       g_list_delete_link (string_list, node);
+    }
+
+  eprop_string_list->editing_index = index;
+
+  if (eprop_string_list->pending_string_list)
+    glade_string_list_free (eprop_string_list->pending_string_list);
+  eprop_string_list->pending_string_list = string_list;
+
+  if (eprop_string_list->update_id == 0)
+    eprop_string_list->update_id = 
+      g_idle_add ((GSourceFunc) update_string_list_idle, eprop);
+
+  gtk_tree_path_free (tree_path);
+}
+
+static void
+i18n_icon_activate (GtkCellRenderer     *renderer,
+                   const gchar         *path,
+                   GladeEditorProperty *eprop)
+{
+  GladeEPropStringList *eprop_string_list = GLADE_EPROP_STRING_LIST (eprop);
+  GtkTreePath          *tree_path = gtk_tree_path_new_from_string (path);
+  GtkTreeIter           iter;
+  guint                 index;
+  GladeProperty        *property = eprop->property;
+  GList                *string_list = NULL;
+  GladeString          *string;
+  gboolean              has_context_dummy;
+
+  gtk_tree_model_get_iter (eprop_string_list->model, &iter, tree_path);
+  gtk_tree_model_get (eprop_string_list->model, &iter,
+                     COLUMN_INDEX, &index,
+                     -1);
+
+  glade_property_get (property, &string_list);
+  string_list = glade_string_list_copy (string_list);
+
+  string = g_list_nth_data (string_list, index);
+
+  if (glade_editor_property_show_i18n_dialog (NULL,
+                                              GLADE_PROJECT_FORMAT_GTKBUILDER,
+                                              &string->string,
+                                              &string->context,
+                                              &string->comment,
+                                              &has_context_dummy,
+                                              &string->translatable))
+    {
+      eprop_string_list->editing_index = index;
+
+      if (eprop_string_list->pending_string_list)
+       glade_string_list_free (eprop_string_list->pending_string_list);
+      eprop_string_list->pending_string_list = string_list;
+
+      if (eprop_string_list->update_id == 0)
+       eprop_string_list->update_id = 
+         g_idle_add ((GSourceFunc) update_string_list_idle, eprop);
+    }
+  else
+    glade_string_list_free (string_list);
+
+  gtk_tree_path_free (tree_path);
+}
+
+static void
+cell_data_func (GtkTreeViewColumn   *column,
+               GtkCellRenderer     *renderer,
+               GtkTreeModel        *model,
+               GtkTreeIter         *iter,
+               GladeEditorProperty *eprop)
+{
+  GladeEPropStringList *eprop_string_list = GLADE_EPROP_STRING_LIST (eprop);
+  gboolean dummy;
+  GdkColor  color;
+
+  gtk_tree_model_get (model, iter, COLUMN_DUMMY, &dummy, -1);
+
+  if (GTK_IS_CELL_RENDERER_TEXT (renderer))
+    {
+      GtkStyle* context = gtk_widget_get_style (eprop_string_list->view);
+
+      if (dummy)
+       {
+         color = context->fg[GTK_STATE_INSENSITIVE];
+         g_object_set (renderer, 
+                       "style", PANGO_STYLE_ITALIC,
+                       "foreground-gdk", &color,
+                       NULL);
+       }
+      else
+       {
+         color = context->fg[GTK_STATE_NORMAL];
+         g_object_set (renderer,
+                       "style", PANGO_STYLE_NORMAL,
+                       "foreground-gdk", &color,
+                       NULL);
+       }
+    }
+  else if (GLADE_IS_CELL_RENDERER_ICON (renderer))
+    g_object_set (renderer, "visible", !dummy && eprop_string_list->translatable, NULL);
+}
+
+static gboolean
+treeview_key_press (GtkWidget           *treeview,
+                   GdkEventKey         *event, 
+                   GladeEditorProperty *eprop)
+{
+
+  /* Delete rows from the store, this will trigger "row-deleted" which will
+   * handle the property update in an idle handler */
+  if (event->keyval == GDK_KEY_Delete)
+    {
+      GladeEPropStringList *eprop_string_list = GLADE_EPROP_STRING_LIST (eprop);
+      GtkTreeSelection *selection;
+      GtkTreeIter iter;
+      GList *selected_rows, *l;
+
+      selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (treeview));
+
+      if ((selected_rows = 
+          gtk_tree_selection_get_selected_rows (selection, NULL)) != NULL)
+       {
+         for (l = selected_rows; l; l = l->next)
+           {
+             GtkTreePath *path = l->data;
+
+             if (gtk_tree_model_get_iter (eprop_string_list->model, &iter, path))
+               gtk_list_store_remove (GTK_LIST_STORE (eprop_string_list->model), &iter);
+           }
+
+         g_list_foreach (selected_rows, (GFunc)gtk_tree_path_free, NULL);
+         g_list_free (selected_rows);
+       }
+      return TRUE;
+    }
+
+  return FALSE;
+}
+
+static GtkWidget *
+glade_eprop_string_list_create_input (GladeEditorProperty * eprop)
+{
+  GladeEPropStringList *eprop_string_list = GLADE_EPROP_STRING_LIST (eprop);
+  GtkTreeViewColumn    *column;
+  GtkCellRenderer      *renderer;
+  GtkWidget            *swindow;
+
+  eprop_string_list->view = gtk_tree_view_new ();
+  gtk_widget_set_size_request (eprop_string_list->view, -1, 150);
+  column                  = gtk_tree_view_column_new ();
+
+  /* Text renderer */
+  renderer = gtk_cell_renderer_text_new ();
+  g_object_set (G_OBJECT (renderer), 
+               "editable", TRUE,
+               "ellipsize", PANGO_ELLIPSIZE_END,
+               NULL);
+  g_signal_connect (G_OBJECT (renderer), "edited",
+                   G_CALLBACK (string_edited), eprop);
+
+  gtk_tree_view_column_pack_start (column, renderer, TRUE);
+  gtk_tree_view_column_set_attributes (column, renderer,
+                                      "text", COLUMN_STRING,
+                                      NULL);
+  gtk_tree_view_column_set_cell_data_func (column, renderer,
+                                          (GtkTreeCellDataFunc)cell_data_func,
+                                          eprop, NULL);
+
+  /* i18n icon renderer */
+  renderer = glade_cell_renderer_icon_new ();
+  g_object_set (G_OBJECT (renderer), "icon-name", GTK_STOCK_EDIT, NULL);
+  g_signal_connect (G_OBJECT (renderer), "activate",
+                   G_CALLBACK (i18n_icon_activate), eprop);
+
+  gtk_tree_view_column_pack_start (column, renderer, FALSE);
+  gtk_tree_view_column_set_cell_data_func (column, renderer,
+                                          (GtkTreeCellDataFunc)cell_data_func,
+                                          eprop, NULL);
+
+  eprop_string_list->model = (GtkTreeModel *)gtk_list_store_new (NUM_COLUMNS,
+                                                                G_TYPE_STRING,
+                                                                G_TYPE_UINT,
+                                                                G_TYPE_BOOLEAN);
+
+
+  g_signal_connect (G_OBJECT (eprop_string_list->model), "row-deleted",
+                   G_CALLBACK (row_deleted), eprop);
+
+  gtk_tree_view_append_column (GTK_TREE_VIEW (eprop_string_list->view), column);
+
+  gtk_tree_view_set_model (GTK_TREE_VIEW (eprop_string_list->view),
+                          eprop_string_list->model);
+
+  gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (eprop_string_list->view), FALSE);
+  gtk_tree_view_set_reorderable (GTK_TREE_VIEW (eprop_string_list->view), TRUE);
+
+  g_signal_connect (eprop_string_list->view, "key-press-event",
+                    G_CALLBACK (treeview_key_press), eprop);
+
+  swindow = gtk_scrolled_window_new (NULL, NULL);
+
+  gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (swindow),
+                                 GTK_POLICY_AUTOMATIC,
+                                 GTK_POLICY_AUTOMATIC);
+  gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (swindow), GTK_SHADOW_IN);
+  gtk_container_add (GTK_CONTAINER (swindow), eprop_string_list->view);
+
+  gtk_widget_show (eprop_string_list->view);
+  gtk_widget_show (swindow);
+
+  return swindow;
+}
+
+GladeEditorProperty *
+glade_eprop_string_list_new (GladePropertyClass *pclass,
+                            gboolean            use_command,
+                            gboolean            translatable)
+{
+  GladeEditorProperty *eprop = 
+    g_object_new (GLADE_TYPE_EPROP_STRING_LIST, 
+                 "property-class", pclass,
+                 "use-command", use_command,
+                 NULL);
+
+  GladeEPropStringList *eprop_string_list = GLADE_EPROP_STRING_LIST (eprop);
+
+  eprop_string_list->translatable = translatable;
+
+  return eprop;
+}
diff --git a/plugins/gtk+/glade-string-list.h b/plugins/gtk+/glade-string-list.h
new file mode 100644
index 0000000..06a0090
--- /dev/null
+++ b/plugins/gtk+/glade-string-list.h
@@ -0,0 +1,43 @@
+#ifndef __GLADE_STRING_LIST_H__
+#define __GLADE_STRING_LIST_H__
+
+#include <glib-object.h>
+#include <gladeui/glade.h>
+
+G_BEGIN_DECLS
+
+
+#define GLADE_TYPE_EPROP_STRING_LIST       (glade_eprop_string_list_get_type())
+#define        GLADE_TYPE_STRING_LIST             (glade_string_list_get_type())
+
+/* The GladeStringList boxed type is a GList * of GladeString structs */
+typedef struct _GladeString             GladeString;
+
+struct _GladeString {
+  gchar    *string;
+  gchar    *comment;
+  gchar    *context;
+  gboolean  translatable;
+};
+
+GType        glade_eprop_string_list_get_type    (void) G_GNUC_CONST;
+GType        glade_string_list_get_type          (void) G_GNUC_CONST;
+
+void         glade_string_list_free              (GList   *list);
+GList       *glade_string_list_copy              (GList   *list);
+
+GList       *glade_string_list_append            (GList   *list,
+                                                 gchar   *string,
+                                                 gchar   *comment,
+                                                 gchar   *context,
+                                                 gboolean translatable);
+
+gchar       *glade_string_list_to_string         (GList   *list);
+
+GladeEditorProperty *glade_eprop_string_list_new (GladePropertyClass *pclass,
+                                                 gboolean            use_command,
+                                                 gboolean            translatable);
+
+G_END_DECLS
+
+#endif   /* __GLADE_STRING_LIST_H__ */
diff --git a/plugins/gtk+/gtk+.xml.in b/plugins/gtk+/gtk+.xml.in
index 69e477d..61f4f38 100644
--- a/plugins/gtk+/gtk+.xml.in
+++ b/plugins/gtk+/gtk+.xml.in
@@ -1234,6 +1234,28 @@ embedded in another object</_tooltip>
       <set-property-function>glade_gtk_combo_box_entry_set_property</set-property-function>
     </glade-widget-class>
 
+
+    <glade-widget-class name="GtkComboBoxText" generic-name="comboboxtext" _title="Combo Box Text">
+      <post-create-function>glade_gtk_combo_box_text_post_create</post-create-function>
+      
<create-editor-property-function>glade_gtk_combo_box_text_create_eprop</create-editor-property-function>
+      <string-from-value-function>glade_gtk_combo_box_text_string_from_value</string-from-value-function>
+      <set-property-function>glade_gtk_combo_box_text_set_property</set-property-function>
+      <read-widget-function>glade_gtk_combo_box_text_read_widget</read-widget-function>
+      <write-widget-function>glade_gtk_combo_box_text_write_widget</write-widget-function>
+
+      <properties>
+        <property id="model" disabled="True"/>
+       <property id="glade-items" _name="Items" save="False" since="2.24">
+         <parameter-spec>
+           <type>GParamBoxed</type>
+           <value-type>GladeStringList</value-type>
+         </parameter-spec>
+         <_tooltip>The items to show in the combo box</_tooltip>
+       </property>
+      </properties>
+    </glade-widget-class>
+
+
     <glade-widget-class name="GtkProgressBar" generic-name="progressbar" _title="Progress Bar">
       <properties>
         <property id="text" translatable="True"/>
@@ -3554,6 +3576,7 @@ embedded in another object</_tooltip>
 
     <glade-widget-class-ref name="GtkComboBox"/>
     <glade-widget-class-ref name="GtkComboBoxEntry"/>
+    <glade-widget-class-ref name="GtkComboBoxText"/>
     <glade-widget-class-ref name="GtkProgressBar"/>
     <glade-widget-class-ref name="GtkSpinner"/>
 
diff --git a/plugins/gtk+/icons/16x16/Makefile.am b/plugins/gtk+/icons/16x16/Makefile.am
index d9f560b..4e3791f 100644
--- a/plugins/gtk+/icons/16x16/Makefile.am
+++ b/plugins/gtk+/icons/16x16/Makefile.am
@@ -37,6 +37,7 @@ icons_DATA = \
         widget-gtk-combo.png \
         widget-gtk-combobox.png \
         widget-gtk-comboboxentry.png \
+        widget-gtk-comboboxtext.png \
         widget-gtk-curve.png \
         widget-gtk-custom.png \
         widget-gtk-default.png \
diff --git a/plugins/gtk+/icons/22x22/Makefile.am b/plugins/gtk+/icons/22x22/Makefile.am
index 5421021..44d3c2e 100644
--- a/plugins/gtk+/icons/22x22/Makefile.am
+++ b/plugins/gtk+/icons/22x22/Makefile.am
@@ -36,6 +36,7 @@ icons_DATA = \
         widget-gtk-combo.png \
         widget-gtk-combobox.png \
         widget-gtk-comboboxentry.png \
+        widget-gtk-comboboxtext.png \
         widget-gtk-curve.png \
         widget-gtk-custom.png \
         widget-gtk-default.png \


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