summaryrefslogtreecommitdiff
path: root/plugins/gtk+
diff options
context:
space:
mode:
Diffstat (limited to 'plugins/gtk+')
-rw-r--r--plugins/gtk+/Makefile.am5
-rw-r--r--plugins/gtk+/glade-gtk.c212
-rw-r--r--plugins/gtk+/glade-string-list.c618
-rw-r--r--plugins/gtk+/glade-string-list.h43
-rw-r--r--plugins/gtk+/gtk+.xml.in23
-rw-r--r--plugins/gtk+/icons/16x16/Makefile.am1
-rw-r--r--plugins/gtk+/icons/22x22/Makefile.am1
7 files changed, 901 insertions, 2 deletions
diff --git a/plugins/gtk+/Makefile.am b/plugins/gtk+/Makefile.am
index d70ade17..ee03044f 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 c784341f..e5a11383 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 00000000..085c3210
--- /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 00000000..06a00902
--- /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 69e477d1..61f4f381 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 d9f560b9..4e3791f0 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 54210218..44d3c2e8 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 \