/* * glade-gtk-cell-layout.c - GladeWidgetAdaptor for GtkCellLayout * * Copyright (C) 2013 Tristan Van Berkom * * Authors: * Tristan Van Berkom * * 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 #include #include #include "glade-gtk.h" #include "glade-gtk-cell-renderer.h" #include "glade-gtk-tree-view.h" #include "glade-cell-renderer-editor.h" #include "glade-treeview-editor.h" gboolean glade_gtk_cell_layout_add_verify (GladeWidgetAdaptor *adaptor, GtkWidget *container, GtkWidget *child, gboolean user_feedback) { if (!GTK_IS_CELL_RENDERER (child)) { if (user_feedback) { GladeWidgetAdaptor *cell_adaptor = glade_widget_adaptor_get_by_type (GTK_TYPE_CELL_RENDERER); glade_util_ui_message (glade_app_get_window (), GLADE_UI_INFO, NULL, ONLY_THIS_GOES_IN_THAT_MSG, glade_widget_adaptor_get_title (cell_adaptor), glade_widget_adaptor_get_title (adaptor)); } return FALSE; } return TRUE; } void glade_gtk_cell_layout_add_child (GladeWidgetAdaptor *adaptor, GObject *container, GObject *child) { GladeWidget *gmodel = NULL; GladeWidget *grenderer = glade_widget_get_from_gobject (child); if (GTK_IS_ICON_VIEW (container) && (gmodel = glade_cell_renderer_get_model (grenderer)) != NULL) gtk_icon_view_set_model (GTK_ICON_VIEW (container), NULL); gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (container), GTK_CELL_RENDERER (child), TRUE); if (gmodel) gtk_icon_view_set_model (GTK_ICON_VIEW (container), GTK_TREE_MODEL (glade_widget_get_object (gmodel))); glade_gtk_cell_renderer_sync_attributes (child); } void glade_gtk_cell_layout_remove_child (GladeWidgetAdaptor *adaptor, GObject *container, GObject *child) { GtkCellLayout *layout = GTK_CELL_LAYOUT (container); GList *l, *children = gtk_cell_layout_get_cells (layout); /* Add a reference to every cell except the one we want to remove */ for (l = children; l; l = g_list_next (l)) if (l->data != child) g_object_ref (l->data); else l->data = NULL; /* remove every cell */ gtk_cell_layout_clear (layout); /* pack others cell renderers */ for (l = children; l; l = g_list_next (l)) { if (l->data == NULL) continue; gtk_cell_layout_pack_start (layout, GTK_CELL_RENDERER (l->data), TRUE); /* Remove our transient reference */ g_object_unref (l->data); } g_list_free (children); } GList * glade_gtk_cell_layout_get_children (GladeWidgetAdaptor *adaptor, GObject *container) { return gtk_cell_layout_get_cells (GTK_CELL_LAYOUT (container)); } void glade_gtk_cell_layout_get_child_property (GladeWidgetAdaptor *adaptor, GObject *container, GObject *child, const gchar *property_name, GValue *value) { if (strcmp (property_name, "position") == 0) { GList *cells = gtk_cell_layout_get_cells (GTK_CELL_LAYOUT (container)); /* We have to fake it, assume we are loading and always return the last item */ g_value_set_int (value, g_list_length (cells) - 1); g_list_free (cells); } else /* Chain Up */ GWA_GET_CLASS (GTK_TYPE_CONTAINER)->child_get_property (adaptor, container, child, property_name, value); } void glade_gtk_cell_layout_set_child_property (GladeWidgetAdaptor *adaptor, GObject *container, GObject *child, const gchar *property_name, const GValue *value) { if (strcmp (property_name, "position") == 0) { /* Need verify on position property !!! XXX */ gtk_cell_layout_reorder (GTK_CELL_LAYOUT (container), GTK_CELL_RENDERER (child), g_value_get_int (value)); } else /* Chain Up */ GWA_GET_CLASS (GTK_TYPE_CONTAINER)->child_set_property (adaptor, container, child, property_name, value); } static void glade_gtk_cell_renderer_read_attributes (GladeWidget *widget, GladeXmlNode *node) { GladeXmlNode *attrs_node; GladeProperty *attr_prop, *use_attr_prop; GladeXmlNode *prop; gchar *name, *column_str, *attr_prop_name, *use_attr_name; if ((attrs_node = glade_xml_search_child (node, GLADE_TAG_ATTRIBUTES)) == NULL) return; for (prop = glade_xml_node_get_children (attrs_node); prop; prop = glade_xml_node_next (prop)) { if (!glade_xml_node_verify_silent (prop, GLADE_TAG_ATTRIBUTE)) continue; name = glade_xml_get_property_string_required (prop, GLADE_TAG_NAME, NULL); column_str = glade_xml_get_content (prop); attr_prop_name = g_strdup_printf ("attr-%s", name); use_attr_name = g_strdup_printf ("use-attr-%s", name); attr_prop = glade_widget_get_property (widget, attr_prop_name); use_attr_prop = glade_widget_get_property (widget, use_attr_name); if (attr_prop && use_attr_prop) { gboolean use_attribute = FALSE; glade_property_get (use_attr_prop, &use_attribute); if (use_attribute) glade_property_set (attr_prop, (gint)g_ascii_strtoll (column_str, NULL, 10)); } g_free (name); g_free (column_str); g_free (attr_prop_name); g_free (use_attr_name); } } void glade_gtk_cell_layout_read_child (GladeWidgetAdaptor *adaptor, GladeWidget *widget, GladeXmlNode *node) { GladeXmlNode *widget_node; GladeWidget *child_widget; gchar *internal_name; if (!glade_xml_node_verify (node, GLADE_XML_TAG_CHILD)) return; internal_name = glade_xml_get_property_string (node, GLADE_XML_TAG_INTERNAL_CHILD); if ((widget_node = glade_xml_search_child (node, GLADE_XML_TAG_WIDGET)) != NULL) { /* Combo box is a special brand of cell-layout, it can also have the internal entry */ if ((child_widget = glade_widget_read (glade_widget_get_project (widget), widget, widget_node, internal_name)) != NULL) { /* Dont set any packing properties on internal children here, * its possible but just not relevant for known celllayouts... * i.e. maybe GtkTreeViewColumn will expose the internal button ? * but no need for packing properties there either. */ if (!internal_name) { glade_widget_add_child (widget, child_widget, FALSE); glade_gtk_cell_renderer_read_attributes (child_widget, node); g_idle_add ((GSourceFunc) glade_gtk_cell_renderer_sync_attributes, glade_widget_get_object (child_widget)); } } } g_free (internal_name); } static void glade_gtk_cell_renderer_write_attributes (GladeWidget *widget, GladeXmlContext *context, GladeXmlNode *node) { GladeProperty *property; GladePropertyClass *pclass; GladeXmlNode *attrs_node; gchar *attr_name; GList *l; static gint attr_len = 0; if (!attr_len) attr_len = strlen ("attr-"); attrs_node = glade_xml_node_new (context, GLADE_TAG_ATTRIBUTES); for (l = glade_widget_get_properties (widget); l; l = l->next) { property = l->data; pclass = glade_property_get_class (property); if (strncmp (glade_property_class_id (pclass), "attr-", attr_len) == 0) { GladeXmlNode *attr_node; gchar *column_str, *use_attr_str; gboolean use_attr = FALSE; use_attr_str = g_strdup_printf ("use-%s", glade_property_class_id (pclass)); glade_widget_property_get (widget, use_attr_str, &use_attr); if (use_attr && g_value_get_int (glade_property_inline_value (property)) >= 0) { column_str = g_strdup_printf ("%d", g_value_get_int (glade_property_inline_value (property))); attr_name = (gchar *)&glade_property_class_id (pclass)[attr_len]; attr_node = glade_xml_node_new (context, GLADE_TAG_ATTRIBUTE); glade_xml_node_append_child (attrs_node, attr_node); glade_xml_node_set_property_string (attr_node, GLADE_TAG_NAME, attr_name); glade_xml_set_content (attr_node, column_str); g_free (column_str); } g_free (use_attr_str); } } if (!glade_xml_node_get_children (attrs_node)) glade_xml_node_delete (attrs_node); else glade_xml_node_append_child (node, attrs_node); } void glade_gtk_cell_layout_write_child (GladeWidgetAdaptor *adaptor, GladeWidget *widget, GladeXmlContext *context, GladeXmlNode *node) { GladeXmlNode *child_node; child_node = glade_xml_node_new (context, GLADE_XML_TAG_CHILD); glade_xml_node_append_child (node, child_node); /* ComboBox can have an internal entry */ if (glade_widget_get_internal (widget)) glade_xml_node_set_property_string (child_node, GLADE_XML_TAG_INTERNAL_CHILD, glade_widget_get_internal (widget)); /* Write out the widget */ glade_widget_write (widget, context, child_node); glade_gtk_cell_renderer_write_attributes (widget, context, child_node); } gchar * glade_gtk_cell_layout_get_display_name (GladeBaseEditor *editor, GladeWidget *gchild, gpointer user_data) { GObject *child = glade_widget_get_object (gchild); gchar *name; if (GTK_IS_TREE_VIEW_COLUMN (child)) glade_widget_property_get (gchild, "title", &name); else name = (gchar *)glade_widget_get_name (gchild); return g_strdup (name); } void glade_gtk_cell_layout_child_selected (GladeBaseEditor *editor, GladeWidget *gchild, gpointer data) { GObject *child = glade_widget_get_object (gchild); glade_base_editor_add_label (editor, GTK_IS_TREE_VIEW_COLUMN (child) ? _("Tree View Column") : _("Cell Renderer")); glade_base_editor_add_default_properties (editor, gchild); glade_base_editor_add_label (editor, GTK_IS_TREE_VIEW_COLUMN (child) ? _("Properties") : _("Properties and Attributes")); glade_base_editor_add_editable (editor, gchild, GLADE_PAGE_GENERAL); if (GTK_IS_CELL_RENDERER (child)) { glade_base_editor_add_label (editor, _("Common Properties and Attributes")); glade_base_editor_add_editable (editor, gchild, GLADE_PAGE_COMMON); } } gboolean glade_gtk_cell_layout_move_child (GladeBaseEditor *editor, GladeWidget *gparent, GladeWidget *gchild, gpointer data) { GObject *parent = glade_widget_get_object (gparent); GObject *child = glade_widget_get_object (gchild); GList list = { 0, }; if (GTK_IS_TREE_VIEW (parent) && !GTK_IS_TREE_VIEW_COLUMN (child)) return FALSE; if (GTK_IS_CELL_LAYOUT (parent) && !GTK_IS_CELL_RENDERER (child)) return FALSE; if (GTK_IS_CELL_RENDERER (parent)) return FALSE; if (gparent != glade_widget_get_parent (gchild)) { list.data = gchild; glade_command_dnd (&list, gparent, NULL); } return TRUE; } static void glade_gtk_cell_layout_launch_editor (GObject *layout, gchar *window_name) { GladeBaseEditor *editor; GtkWidget *window; /* Editor */ editor = glade_base_editor_new (layout, NULL, _("Text"), GTK_TYPE_CELL_RENDERER_TEXT, _("Accelerator"), GTK_TYPE_CELL_RENDERER_ACCEL, _("Combo"), GTK_TYPE_CELL_RENDERER_COMBO, _("Spin"), GTK_TYPE_CELL_RENDERER_SPIN, _("Pixbuf"), GTK_TYPE_CELL_RENDERER_PIXBUF, _("Progress"), GTK_TYPE_CELL_RENDERER_PROGRESS, _("Toggle"), GTK_TYPE_CELL_RENDERER_TOGGLE, _("Spinner"), GTK_TYPE_CELL_RENDERER_SPINNER, NULL); g_signal_connect (editor, "get-display-name", G_CALLBACK (glade_gtk_cell_layout_get_display_name), NULL); g_signal_connect (editor, "child-selected", G_CALLBACK (glade_gtk_cell_layout_child_selected), NULL); g_signal_connect (editor, "move-child", G_CALLBACK (glade_gtk_cell_layout_move_child), NULL); gtk_widget_show (GTK_WIDGET (editor)); window = glade_base_editor_pack_new_window (editor, window_name, NULL); gtk_widget_show (window); } static void glade_gtk_cell_layout_launch_editor_action (GObject *object) { GladeWidget *w = glade_widget_get_from_gobject (object); do { GObject *obj = glade_widget_get_object (w); if (GTK_IS_TREE_VIEW (obj)) { glade_gtk_treeview_launch_editor (obj); break; } else if (GTK_IS_ICON_VIEW (obj)) { glade_gtk_cell_layout_launch_editor (obj, _("Icon View Editor")); break; } else if (GTK_IS_COMBO_BOX (obj)) { glade_gtk_cell_layout_launch_editor (obj, _("Combo Editor")); break; } else if (GTK_IS_ENTRY_COMPLETION (obj)) { glade_gtk_cell_layout_launch_editor (obj, _("Entry Completion Editor")); break; } } while ((w = glade_widget_get_parent (w))); } void glade_gtk_cell_layout_action_activate (GladeWidgetAdaptor *adaptor, GObject *object, const gchar *action_path) { if (strcmp (action_path, "launch_editor") == 0) glade_gtk_cell_layout_launch_editor_action (object); else GWA_GET_CLASS (G_TYPE_OBJECT)->action_activate (adaptor, object, action_path); } void glade_gtk_cell_layout_action_activate_as_widget (GladeWidgetAdaptor *adaptor, GObject *object, const gchar *action_path) { if (strcmp (action_path, "launch_editor") == 0) glade_gtk_cell_layout_launch_editor_action (object); else GWA_GET_CLASS (GTK_TYPE_WIDGET)->action_activate (adaptor, object, action_path); } gboolean glade_gtk_cell_layout_sync_attributes (GObject *layout) { GladeWidget *gwidget = glade_widget_get_from_gobject (layout); GObject *cell; GList *children, *l; children = glade_widget_get_children (gwidget); for (l = children; l; l = l->next) { cell = l->data; if (!GTK_IS_CELL_RENDERER (cell)) continue; glade_gtk_cell_renderer_sync_attributes (cell); } g_list_free (children); return FALSE; }