summaryrefslogtreecommitdiff
path: root/tools/glade/glade/glade_atk.c
diff options
context:
space:
mode:
Diffstat (limited to 'tools/glade/glade/glade_atk.c')
-rw-r--r--tools/glade/glade/glade_atk.c1662
1 files changed, 1662 insertions, 0 deletions
diff --git a/tools/glade/glade/glade_atk.c b/tools/glade/glade/glade_atk.c
new file mode 100644
index 00000000..3a2330cb
--- /dev/null
+++ b/tools/glade/glade/glade_atk.c
@@ -0,0 +1,1662 @@
+/* Gtk+ User Interface Builder
+ * Copyright (C) 1998-2002 Damon Chaplin
+ * Copyright (C) 2002 Sun Microsystems, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+/*
+ * This file contains most of the ATK-related code in Glade.
+ * It handles the properties, actions and relations in the property editor.
+ */
+
+#include <config.h>
+#include <gladeconfig.h>
+
+#include <string.h>
+
+#include <atk/atk.h>
+#include <gtk/gtkcellrenderertoggle.h>
+#include <gtk/gtkcellrenderertext.h>
+#include <gtk/gtkdialog.h>
+#include <gtk/gtkentry.h>
+#include <gtk/gtkimage.h>
+#include <gtk/gtkliststore.h>
+#include <gtk/gtkmain.h>
+#include <gtk/gtknotebook.h>
+#include <gtk/gtkscrolledwindow.h>
+#include <gtk/gtkstock.h>
+#include <gtk/gtktable.h>
+#include <gtk/gtktreeview.h>
+#include <gtk/gtkvbox.h>
+
+#include "property.h"
+#include "save.h"
+#include "source.h"
+#include "utils.h"
+#include "glade_atk.h"
+
+#include "graphics/glade-atk.xpm"
+
+const gchar *GladeATKName = "AtkObject::accessible_name";
+const gchar *GladeATKDescription = "AtkObject::accessible_description";
+/* There is a problem with this as AtkObject says it is a string property
+ but it really is an AtkObject. I've taken it out for now. */
+#if 0
+const gchar *GladeATKTableCaption = "AtkObject::accessible_table_caption";
+#endif
+
+/* These are keys we use to store data in the property value widget - the
+ entry in the property editor that shows relations. */
+const gchar *GladeATKPropertyName = "GladeATKPropertyName";
+const gchar *GladeATKRelationType = "GladeATKRelationType";
+const gchar *GladeATKRelationsDialog = "GladeATKRelationsDialog";
+
+/* These are keys we use to store data in the relations dialog. */
+const gchar *GladeATKValueWidget = "GladeATKValueWidget";
+const gchar *GladeATKRelationsListStore = "GladeATKRelationsListStore";
+const gchar *GladeATKRelationsWidgets = "GladeATKRelationsWidgets";
+
+
+/* These are the GtkTables used in the property editor to contain the action
+ properties and the relation properties. */
+static GtkWidget *actions_table = NULL;
+static GtkWidget *relations_table = NULL;
+
+/* This is a list of the relation property value widgets, i.e. the GtkEntry
+ widgets in the property editor for each relation. */
+static GList *relations_properties = NULL;
+
+/* A hash of action property widgets. The keys are the Glade property names
+ ('AtkAction:<action-name>') and the values are the widgets in the property
+ editor. */
+static GHashTable *action_properties = NULL;
+static gint n_action_properties = 0;
+
+enum
+{
+ COLUMN_SELECTED,
+ COLUMN_WIDGET_NAME
+};
+
+
+/***************************************************************************
+ * Utility functions.
+ ***************************************************************************/
+
+/* Returns the property name to use in the property editor given a relation
+ type name. We need to add a prefix to make sure we don't clash with other
+ types of properties. The returned string must be freed. */
+static gchar *
+glade_atk_get_relation_property_name (const char *name)
+{
+ return g_strdup_printf ("AtkRelation:%s", name);
+}
+
+
+typedef struct _GladePropertyLabel GladePropertyLabel;
+struct _GladePropertyLabel
+{
+ const char *name;
+ const char *label;
+};
+
+
+/* This table lets us translate relation names to show in the property editor.
+ These are the standard relations from from atkrelation.h. */
+GladePropertyLabel relation_names_table[] = {
+ { "controlled-by", N_("Controlled By") },
+ { "controller-for", N_("Controller For") },
+ { "label-for", N_("Label For") },
+ { "labelled-by", N_("Labelled By") },
+ { "member-of", N_("Member Of") },
+ { "node-child-of", N_("Node Child Of") },
+ { "flows-to", N_("Flows To") },
+ { "flows-from", N_("Flows From") },
+ { "subwindow-of", N_("Subwindow Of") },
+ { "embeds", N_("Embeds") },
+ { "embedded-by", N_("Embedded By") },
+ { "popup-for", N_("Popup For") },
+ { "parent-window-of", N_("Parent Window Of") }
+};
+
+/* This returns the translated relation name. We hardcode some strings here so
+ we can translate them. The returned string should not be freed. */
+static const gchar*
+glade_atk_get_relation_name_for_display (const gchar *name)
+{
+ const char *label = name;
+ gint i;
+
+ for (i = 0; i < G_N_ELEMENTS (relation_names_table); i++)
+ {
+ if (!strcmp (name, relation_names_table[i].name))
+ label = _(relation_names_table[i].label);
+ }
+
+ return label;
+}
+
+/* This returns the label to use for the given relation name. We hardcode some
+ strings here so we can translate the action names. The returned string
+ should be freed. */
+static gchar*
+glade_atk_get_relation_property_label (const gchar *name)
+{
+ const char *label;
+
+ label = glade_atk_get_relation_name_for_display (name);
+ return g_strdup_printf ("%s:", label);
+}
+
+
+/***************************************************************************
+ * The Relations Dialog.
+ ***************************************************************************/
+
+typedef struct _GladeRelationsApplyData GladeRelationsApplyData;
+struct _GladeRelationsApplyData
+{
+ gint row;
+ GList *widget_pointers;
+
+ GList *targets;
+ GString *buffer;
+};
+
+static gboolean
+relations_dialog_apply_cb (GtkTreeModel *model,
+ GtkTreePath *path,
+ GtkTreeIter *iter,
+ gpointer user_data)
+{
+ GladeRelationsApplyData *data = user_data;
+ gboolean selected;
+
+ gtk_tree_model_get (model, iter, COLUMN_SELECTED, &selected, -1);
+
+ if (selected)
+ {
+ GtkWidget *widget = data->widget_pointers->data;
+
+ if (widget)
+ {
+ data->targets = g_list_prepend (data->targets, widget);
+
+ /* We add a weak pointer to the widget, so the element data will be
+ set to NULL if the widget is destroyed. */
+#if 0
+ g_print ("Adding weak pointer Object:%p Pointer:%p\n",
+ widget, &data->targets->data);
+#endif
+ g_object_add_weak_pointer (G_OBJECT (widget),
+ &data->targets->data);
+
+ /* Add a comma if the string isn't empty. */
+ if (data->buffer->len > 0)
+ g_string_append_c (data->buffer, ',');
+ g_string_append (data->buffer, gtk_widget_get_name (widget));
+ }
+ }
+
+ if (data->widget_pointers)
+ data->widget_pointers = data->widget_pointers->next;
+ data->row++;
+ return FALSE;
+}
+
+
+static void
+relations_dialog_apply (GtkWidget *relations_dialog)
+{
+ GtkWidget *widget, *value_widget;
+ GladeWidgetData *wdata;
+ GtkTreeModel *model;
+ AtkRelationType relationship;
+ GList *widget_pointers;
+ GladeRelationsApplyData data;
+
+ widget = property_get_widget ();
+ if (!widget)
+ return;
+
+ wdata = gtk_object_get_data (GTK_OBJECT (widget), GB_WIDGET_DATA_KEY);
+ g_return_if_fail (wdata != NULL);
+
+ value_widget = gtk_object_get_data (GTK_OBJECT (relations_dialog),
+ GladeATKValueWidget);
+ g_return_if_fail (value_widget != NULL);
+
+ model = gtk_object_get_data (GTK_OBJECT (relations_dialog),
+ GladeATKRelationsListStore);
+ g_return_if_fail (model != NULL);
+
+ widget_pointers = gtk_object_get_data (GTK_OBJECT (relations_dialog),
+ GladeATKRelationsWidgets);
+
+ relationship = GPOINTER_TO_INT (gtk_object_get_data (GTK_OBJECT (value_widget), GladeATKRelationType));
+
+ /* Step through the list of widgets in the dialog, adding selected widgets
+ to a list of targets. */
+ data.row = 0;
+ data.widget_pointers = widget_pointers;
+ data.buffer = g_string_sized_new (256);
+ data.targets = NULL;
+ gtk_tree_model_foreach (model, relations_dialog_apply_cb, &data);
+
+ /* Update the field in the property editor. */
+ gtk_entry_set_text (GTK_ENTRY (value_widget), data.buffer->str);
+ g_string_free (data.buffer, TRUE);
+
+ /* Now set the relation in the GladeWidgetData. */
+ glade_widget_data_set_relation (wdata, relationship, data.targets);
+}
+
+
+static void
+relations_dialog_response_cb (GtkWidget *dialog, gint response_id)
+{
+
+ if (response_id == GTK_RESPONSE_APPLY || response_id == GTK_RESPONSE_OK)
+ relations_dialog_apply (dialog);
+
+ if (response_id == GTK_RESPONSE_APPLY)
+ gtk_dialog_set_response_sensitive (GTK_DIALOG (dialog),
+ GTK_RESPONSE_APPLY, FALSE);
+
+ if (response_id != GTK_RESPONSE_APPLY)
+ gtk_widget_hide (dialog);
+}
+
+
+static void
+relations_widget_toggled_cb (GtkWidget *widget, gchar *path_str,
+ GtkWidget *relations_dialog)
+{
+ GtkTreeModel *model;
+ GtkTreePath *path;
+ GtkTreeIter iter;
+ gboolean selected;
+
+ model = gtk_object_get_data (GTK_OBJECT (relations_dialog),
+ GladeATKRelationsListStore);
+
+ /* Toggle the selected flag. */
+ path = gtk_tree_path_new_from_string (path_str);
+ gtk_tree_model_get_iter (model, &iter, path);
+ gtk_tree_path_free (path);
+
+ gtk_tree_model_get (model, &iter, COLUMN_SELECTED, &selected, -1);
+ selected = selected ? FALSE : TRUE;
+ gtk_list_store_set (GTK_LIST_STORE (model), &iter, COLUMN_SELECTED,
+ selected, -1);
+
+ gtk_dialog_set_response_sensitive (GTK_DIALOG (relations_dialog),
+ GTK_RESPONSE_APPLY, TRUE);
+}
+
+
+static GtkWidget*
+create_relations_dialog (GtkWidget *value_widget)
+{
+ GtkWindow *property_editor;
+ GtkWidget *relations_dialog, *scrolledwin, *treeview;
+ GtkListStore *list_store;
+ GtkTreeViewColumn *col;
+ GtkCellRenderer *rend;
+ AtkRelationType relationship;
+ const gchar *relation_name, *name;
+ gchar *title;
+
+ property_editor = GTK_WINDOW (gtk_widget_get_toplevel (value_widget));
+
+ relationship = GPOINTER_TO_INT (gtk_object_get_data (GTK_OBJECT (value_widget), GladeATKRelationType));
+ relation_name = atk_relation_type_get_name (relationship);
+ name = glade_atk_get_relation_name_for_display (relation_name);
+
+ /* I don't think we should set the transient parent as the dialog could be
+ left open if desired. */
+ title = g_strdup_printf (_("Relationship: %s"), name);
+ relations_dialog = gtk_dialog_new_with_buttons (title,
+ NULL /*property_editor*/,
+ GTK_DIALOG_NO_SEPARATOR,
+ GTK_STOCK_CLOSE,
+ GTK_RESPONSE_CLOSE,
+ GTK_STOCK_APPLY,
+ GTK_RESPONSE_APPLY,
+ GTK_STOCK_OK,
+ GTK_RESPONSE_OK,
+ NULL);
+ g_free (title);
+ gtk_window_set_default_size (GTK_WINDOW (relations_dialog), 250, 300);
+ /* We say it is a normal window as it may be left open if desired. */
+ gtk_window_set_type_hint (GTK_WINDOW (relations_dialog),
+ GDK_WINDOW_TYPE_HINT_NORMAL);
+
+ scrolledwin = gtk_scrolled_window_new (NULL, NULL);
+ gtk_widget_show (scrolledwin);
+ gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolledwin),
+ GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
+ gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scrolledwin),
+ GTK_SHADOW_IN);
+ gtk_box_pack_start (GTK_BOX (GTK_DIALOG (relations_dialog)->vbox),
+ scrolledwin, TRUE, TRUE, 0);
+
+ list_store = gtk_list_store_new (2, G_TYPE_BOOLEAN, G_TYPE_STRING);
+
+ treeview = gtk_tree_view_new_with_model (GTK_TREE_MODEL (list_store));
+ g_object_unref (G_OBJECT (list_store));
+ gtk_widget_show (treeview);
+ gtk_container_add (GTK_CONTAINER (scrolledwin), treeview);
+
+ rend = gtk_cell_renderer_toggle_new ();
+ col = gtk_tree_view_column_new_with_attributes ("", rend,
+ "active", COLUMN_SELECTED,
+ NULL);
+ gtk_tree_view_column_set_resizable (col, FALSE);
+ gtk_tree_view_append_column (GTK_TREE_VIEW (treeview), col);
+ gtk_signal_connect (GTK_OBJECT (rend), "toggled",
+ GTK_SIGNAL_FUNC (relations_widget_toggled_cb),
+ relations_dialog);
+
+ rend = gtk_cell_renderer_text_new ();
+ col = gtk_tree_view_column_new_with_attributes (_("Widget"), rend,
+ "text", COLUMN_WIDGET_NAME,
+ NULL);
+ gtk_tree_view_column_set_resizable (col, TRUE);
+ gtk_tree_view_append_column (GTK_TREE_VIEW (treeview), col);
+
+ gtk_signal_connect (GTK_OBJECT (relations_dialog), "response",
+ GTK_SIGNAL_FUNC (relations_dialog_response_cb),
+ value_widget);
+ gtk_signal_connect (GTK_OBJECT (relations_dialog), "delete-event",
+ GTK_SIGNAL_FUNC (gtk_true), NULL);
+
+ /* Save a pointer to the dialog in the value widget and vice versa, and save
+ a pointer to the list store in the dialog. */
+ gtk_object_set_data (GTK_OBJECT (value_widget),
+ GladeATKRelationsDialog, relations_dialog);
+ gtk_object_set_data (GTK_OBJECT (relations_dialog),
+ GladeATKValueWidget, value_widget);
+ gtk_object_set_data (GTK_OBJECT (relations_dialog),
+ GladeATKRelationsListStore, list_store);
+
+ return relations_dialog;
+}
+
+
+/* This is a recursive function to traverse the widget hierarchy and add all
+ the GbWidgets to the list. */
+void
+scan_widgets (GtkWidget *widget, GList **widget_list)
+{
+ /* First add this widget, if it is a GbWidget. */
+ if (GB_IS_GB_WIDGET (widget))
+ {
+ /* GbWidget names shouldn't be empty, but check just in case. */
+ const gchar *name = gtk_widget_get_name (widget);
+ if (name && *name)
+ *widget_list = g_list_prepend (*widget_list, widget);
+ }
+
+ /* Now add child widgets recursively. */
+ gb_widget_children_foreach (widget, (GtkCallback) scan_widgets,
+ widget_list);
+}
+
+
+gint
+compare_widget_names (GtkWidget *a, GtkWidget *b)
+{
+ const char *namea = gtk_widget_get_name (a);
+ const char *nameb = gtk_widget_get_name (b);
+ return g_utf8_collate (namea, nameb);
+}
+
+
+/* Remove all the weak pointers to the widgets. */
+static void
+clear_relations_dialog_weak_pointers (GList *widget_pointers)
+{
+ GList *elem;
+
+ for (elem = widget_pointers; elem; elem = elem->next)
+ {
+ GtkWidget *widget = elem->data;
+ if (widget)
+ {
+#if 0
+ g_print ("Removing weak pointer Object:%p Pointer:%p\n",
+ widget, &elem->data);
+#endif
+ g_object_remove_weak_pointer (G_OBJECT (widget), &elem->data);
+ }
+ }
+
+ g_list_free (widget_pointers);
+}
+
+
+/* This refreshes the contents of a relations dialog. It clears the list,
+ then adds all widgets in the same component as the widget shown in the
+ property editor, selecting those that are in this relation. */
+/* FIXME: Note that we could share the list of widgets in the component among
+ all the relations dialogs. That would be more efficient, though it should
+ only make a difference when several relations dialogs are left open. */
+static void
+glade_atk_refresh_relations_dialog (GtkWidget *relations_dialog)
+{
+ GtkWidget *widget, *value_widget, *toplevel;
+ GladeWidgetData *wdata;
+ GList *widget_list = NULL, *elem, *targets = NULL;
+ GtkListStore *list_store;
+ GList *widget_pointers;
+ AtkRelationType relationship;
+
+ widget = property_get_widget ();
+ g_return_if_fail (widget != NULL);
+
+ wdata = gtk_object_get_data (GTK_OBJECT (widget), GB_WIDGET_DATA_KEY);
+ g_return_if_fail (wdata != NULL);
+
+ value_widget = gtk_object_get_data (GTK_OBJECT (relations_dialog),
+ GladeATKValueWidget);
+ g_return_if_fail (value_widget != NULL);
+
+ /* Get a pointer to the list store that we set when creating the dialog. */
+ list_store = gtk_object_get_data (GTK_OBJECT (relations_dialog),
+ GladeATKRelationsListStore);
+ g_return_if_fail (list_store != NULL);
+
+ /* Clear the list. */
+ gtk_list_store_clear (list_store);
+
+ /* Remove all the weak pointers to the widgets. */
+ widget_pointers = gtk_object_get_data (GTK_OBJECT (relations_dialog),
+ GladeATKRelationsWidgets);
+ clear_relations_dialog_weak_pointers (widget_pointers);
+ widget_pointers = NULL;
+
+ /* Traverse the widget hierarchy of the window the widget is in, adding
+ all GbWidgets to a list, and sort it by their names. */
+ toplevel = glade_util_get_toplevel (widget);
+ scan_widgets (toplevel, &widget_list);
+ widget_list = g_list_sort (widget_list, (GCompareFunc) compare_widget_names);
+
+ /* Get the current relations, so we can check them in the list. */
+ relationship = GPOINTER_TO_INT (gtk_object_get_data (GTK_OBJECT (value_widget), GladeATKRelationType));
+ for (elem = wdata->relations; elem; elem = elem->next)
+ {
+ GladeRelation *relation = elem->data;
+ if (relation->relationship == relationship)
+ {
+ targets = relation->targets;
+ break;
+ }
+ }
+
+ /* Now add the widgets to the list store. If the widget is already
+ in the relation, check the checkbox. */
+ for (elem = widget_list; elem; elem = elem->next)
+ {
+ GtkWidget *widget_to_add = elem->data;
+ GtkTreeIter iter;
+ gboolean selected = FALSE;
+
+ if (g_list_find (targets, widget_to_add))
+ selected = TRUE;
+
+ gtk_list_store_append (list_store, &iter);
+ gtk_list_store_set (list_store, &iter,
+ 0, selected,
+ 1, gtk_widget_get_name (widget_to_add),
+ -1);
+
+ widget_pointers = g_list_prepend (widget_pointers, widget_to_add);
+ /* Add a weak pointer, so it gets set to NULL if the widget is
+ destroyed. */
+#if 0
+ g_print ("Adding weak pointer Object:%p Pointer:%p\n",
+ widget_to_add, &widget_pointers->data);
+#endif
+ g_object_add_weak_pointer (G_OBJECT (widget_to_add),
+ &widget_pointers->data);
+ }
+
+ widget_pointers = g_list_reverse (widget_pointers);
+ gtk_object_set_data (GTK_OBJECT (relations_dialog),
+ GladeATKRelationsWidgets, widget_pointers);
+
+ gtk_dialog_set_response_sensitive (GTK_DIALOG (relations_dialog),
+ GTK_RESPONSE_APPLY, FALSE);
+}
+
+
+/* This is the callback that is called when the little button on the right
+ of each relation property is clicked. value_button is the little button
+ that was clicked. value_widget is the entry to the left of it. */
+static void
+show_relations_dialog (GtkWidget *value_button,
+ gpointer value_widget)
+{
+ GtkWidget *relations_dialog;
+
+ /* Create the dialog if it we don't already have one for this relation. */
+ relations_dialog = gtk_object_get_data (GTK_OBJECT (value_widget),
+ GladeATKRelationsDialog);
+ if (!relations_dialog)
+ relations_dialog = create_relations_dialog (value_widget);
+
+ glade_atk_refresh_relations_dialog (relations_dialog);
+
+ /* Show the dialog, or raise it if it is already shown. */
+ gtk_widget_show (relations_dialog);
+ gdk_window_show (GTK_WIDGET (relations_dialog)->window);
+ gdk_window_raise (GTK_WIDGET (relations_dialog)->window);
+}
+
+
+/* This updates any relations dialogs which are currently visible, when the
+ widget being shown in the property editor changes (maybe to NULL). */
+void
+glade_atk_update_relation_dialogs (void)
+{
+ GList *elem;
+
+ /* Iterate over the list of relations value widgets (the entry fields in
+ the property editor). Get the associated dialog, if it has been created,
+ and check if it is visible. If it is, refresh it. */
+ for (elem = relations_properties; elem; elem = elem->next)
+ {
+ GtkWidget *value_widget = elem->data;
+ GtkWidget *relations_dialog;
+
+ relations_dialog = gtk_object_get_data (GTK_OBJECT (value_widget),
+ GladeATKRelationsDialog);
+ if (relations_dialog && GTK_WIDGET_DRAWABLE (relations_dialog))
+ {
+ glade_atk_refresh_relations_dialog (relations_dialog);
+ }
+ }
+}
+
+
+/***************************************************************************
+ * Creating the initial properties in the property editor.
+ ***************************************************************************/
+
+/* This creates the ATK properties page of the property editor.
+ We add the standard atk properties and relations here. Actions and other
+ relations may get added as needed. */
+void
+glade_atk_create_property_page (GtkNotebook *notebook)
+{
+ GtkWidget *page, *icon, *vbox, *table;
+ GdkPixbuf *pixbuf;
+ /* Don't use AtkRelationType here since new values can be registered
+ dynamically, which can cause problems with optimizing compilers. */
+ int relationship;
+
+ page = gtk_scrolled_window_new (NULL, NULL);
+ gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (page),
+ GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
+ gtk_widget_show (page);
+
+ /* We use an icon for the notebook tab, as there isn't much room for text. */
+ pixbuf = gdk_pixbuf_new_from_xpm_data ((const char**) glade_atk_xpm);
+ icon = gtk_image_new_from_pixbuf (pixbuf);
+ gdk_pixbuf_unref (pixbuf);
+ gtk_widget_show (icon);
+
+ gtk_notebook_append_page (notebook, page, icon);
+
+ vbox = gtk_vbox_new (FALSE, 0);
+ gtk_scrolled_window_add_with_viewport (GTK_SCROLLED_WINDOW (page), vbox);
+ gtk_viewport_set_shadow_type (GTK_VIEWPORT (GTK_BIN (page)->child),
+ GTK_SHADOW_NONE);
+ gtk_widget_show (vbox);
+
+ table = gtk_table_new (1, 3, FALSE);
+ gtk_table_set_row_spacings (GTK_TABLE (table), 1);
+ gtk_widget_show (table);
+ gtk_box_pack_start (GTK_BOX (vbox), table, FALSE, TRUE, 0);
+
+ property_set_table_position (table, 0);
+
+ property_add_string (GladeATKName, _("Name:"),
+ _("The name of the widget to pass to assistive technologies"));
+ property_add_text (GladeATKDescription, _("Description:"),
+ _("The description of the widget to pass to assistive technologies"), 4);
+#if 0
+ property_add_text (GladeATKTableCaption, _("Table Caption:"),
+ _("The table caption to pass to assistive technologies"), 2);
+#endif
+
+ /* We create separate tables for the actions and relations as we need to be
+ able to add properties to them as they are needed. */
+ actions_table = gtk_table_new (1, 3, FALSE);
+ gtk_table_set_row_spacings (GTK_TABLE (actions_table), 1);
+ gtk_widget_show (actions_table);
+ gtk_box_pack_start (GTK_BOX (vbox), actions_table, FALSE, TRUE, 0);
+
+ action_properties = g_hash_table_new (g_str_hash, g_str_equal);
+
+ relations_table = gtk_table_new (1, 3, FALSE);
+ gtk_table_set_row_spacings (GTK_TABLE (relations_table), 1);
+ gtk_widget_show (relations_table);
+ gtk_box_pack_start (GTK_BOX (vbox), relations_table, FALSE, TRUE, 0);
+
+ /* We assume that all relation types will have already been registered by
+ now. I hope that is correct. */
+ property_set_table_position (relations_table, 0);
+ for (relationship = 0; ; relationship++)
+ {
+ /* Skip these 2 as they aren't real relations. */
+ if (relationship != ATK_RELATION_NULL
+ && relationship != ATK_RELATION_LAST_DEFINED)
+ {
+ const gchar *name = atk_relation_type_get_name (relationship);
+ char *property_name, *property_label;
+ GtkWidget *value_widget;
+
+ if (!name)
+ break;
+
+ property_name = glade_atk_get_relation_property_name (name);
+ property_label = glade_atk_get_relation_property_label (name);
+
+ property_add_dialog (property_name, property_label,
+ _("Select the widgets with this relationship"),
+ FALSE, show_relations_dialog);
+
+ /* Store the property name and the relation type in the value widget,
+ so we can find them later. */
+ value_widget = property_get_value_widget (property_name);
+ relations_properties = g_list_prepend (relations_properties,
+ value_widget);
+ gtk_object_set_data_full (GTK_OBJECT (value_widget),
+ GladeATKPropertyName, property_name,
+ g_free);
+ gtk_object_set_data (GTK_OBJECT (value_widget),
+ GladeATKRelationType,
+ GINT_TO_POINTER (relationship));
+
+ g_free (property_label);
+ }
+ }
+}
+
+
+/***************************************************************************
+ * Showing properties in the property editor.
+ ***************************************************************************/
+
+static void
+glade_atk_get_atk_properties (GtkWidget * widget,
+ AtkObject * atko,
+ GbWidgetGetArgData * data)
+{
+ const char *name, *description;
+#if 0
+ const char *table_caption;
+ gboolean show_table_caption = FALSE;
+#endif
+
+ name = atk_object_get_name (atko);
+ gb_widget_output_translatable_string (data, GladeATKName, name);
+
+ description = atk_object_get_description (atko);
+ gb_widget_output_translatable_text (data, GladeATKDescription, description);
+
+#if 0
+ if (GTK_IS_TREE_VIEW (widget))
+ {
+ show_table_caption = TRUE;
+
+ g_object_get (G_OBJECT (atko),
+ "AtkObject::accessible-table-caption", &table_caption,
+ NULL);
+ gb_widget_output_translatable_text (data, GladeATKTableCaption,
+ table_caption);
+ }
+
+ if (data->action == GB_SHOWING)
+ property_set_visible (GladeATKTableCaption, show_table_caption);
+#endif
+}
+
+
+/* Returns the property name to use in the property editor given an action
+ name. We need to add a prefix to make sure we don't clash with other
+ types of properties. The returned string must be freed. */
+static gchar *
+glade_atk_get_action_property_name (const char *name)
+{
+ return g_strdup_printf ("AtkAction:%s", name);
+}
+
+
+static void
+hide_action_properties (const gchar * key, gpointer data, gpointer user_data)
+{
+ property_set_visible (key, FALSE);
+}
+
+
+/* This table lets us translate action names to show in the property editor.
+ These are the only 3 actions I can find at present. */
+GladePropertyLabel action_names_table[] = {
+ { "click", N_("Click") },
+ { "press", N_("Press") },
+ { "release", N_("Release") }
+};
+
+/* This returns the label to use for the given action name. We hardcode some
+ strings here so we can translate the action names. The returned string
+ should be freed. */
+static gchar*
+get_action_property_label (const gchar *name)
+{
+ const char *label = name;
+ gint i;
+
+ for (i = 0; i < G_N_ELEMENTS (action_names_table); i++)
+ {
+ if (!strcmp (name, action_names_table[i].name))
+ label = _(action_names_table[i].label);
+ }
+
+ return g_strdup_printf ("%s:", label);
+}
+
+
+static void
+glade_atk_get_actions (GtkWidget * widget,
+ AtkAction * action,
+ GbWidgetGetArgData * data)
+{
+ gint n_actions, i;
+
+ /* Hide all the action properties. We'll show the ones the widget supports
+ after. */
+ g_hash_table_foreach (action_properties, (GHFunc) hide_action_properties,
+ NULL);
+
+ n_actions = atk_action_get_n_actions (action);
+ for (i = 0; i < n_actions; i++)
+ {
+ const char *name, *description;
+ char *property_name, *property_label;
+ GtkWidget *value;
+ gboolean free_property_name;
+
+ name = atk_action_get_name (action, i);
+ description = atk_action_get_description (action, i);
+ property_name = glade_atk_get_action_property_name (name);
+ free_property_name = TRUE;
+
+ /* If we already have a property widget for this action, then show it,
+ else create a new property widget to edit the description. */
+ value = property_get_value_widget (property_name);
+ if (value)
+ {
+ property_set_visible (property_name, TRUE);
+ }
+ else
+ {
+ property_set_table_position (actions_table, n_action_properties);
+ property_label = get_action_property_label (name);
+ property_add_text (property_name, property_label,
+ _("Enter the description of the action to pass to assistive technologies"), 2);
+ g_free (property_label);
+ n_action_properties++;
+
+ /* Add to our hash. */
+ value = property_get_value_widget (property_name);
+ g_hash_table_insert (action_properties, property_name, value);
+ free_property_name = FALSE;
+ }
+
+ /* Now set the current value. */
+ property_set_text (property_name, description);
+
+ if (free_property_name)
+ g_free (property_name);
+ }
+}
+
+
+static void
+glade_atk_get_relations (GtkWidget * widget,
+ AtkObject * atko,
+ GbWidgetGetArgData * data)
+{
+ GladeWidgetData *wdata;
+ GList *elem;
+ GString *buffer;
+
+ wdata = gtk_object_get_data (GTK_OBJECT (widget), GB_WIDGET_DATA_KEY);
+ g_return_if_fail (wdata != NULL);
+
+ buffer = g_string_sized_new (256);
+
+ /* Clear all the relations properties. */
+ for (elem = relations_properties; elem; elem = elem->next)
+ {
+ GtkWidget *value_widget = elem->data;
+ gtk_entry_set_text (GTK_ENTRY (value_widget), "");
+ }
+
+ /* Step through each of the relations in the GladeWidgetData. */
+ for (elem = wdata->relations; elem; elem = elem->next)
+ {
+ GladeRelation *relation = elem->data;
+ const gchar *relation_name;
+ char *property_name;
+ GtkWidget *value_widget;
+
+ /* Find the property for the relationship. */
+ relation_name = atk_relation_type_get_name (relation->relationship);
+ property_name = glade_atk_get_relation_property_name (relation_name);
+
+ value_widget = property_get_value_widget (property_name);
+ if (value_widget)
+ {
+ GList *target;
+
+ /* Convert the list of target widgets to a comma-separated string. */
+ for (target = relation->targets; target; target = target->next)
+ {
+ GtkWidget *target_widget = target->data;
+
+ /* Remember this is a weak pointer so may be NULL. */
+ if (target_widget)
+ {
+ const char *target_name = gtk_widget_get_name (target_widget);
+ if (target_name && *target_name)
+ {
+ /* Add a comma if the string isn't empty. */
+ if (buffer->len > 0)
+ g_string_append_c (buffer, ',');
+ g_string_append (buffer, target_name);
+ }
+ }
+ }
+
+ gtk_entry_set_text (GTK_ENTRY (value_widget), buffer->str);
+ g_string_truncate (buffer, 0);
+ }
+
+ g_free (property_name);
+ }
+
+ g_string_free (buffer, TRUE);
+}
+
+
+/* This shows the widget's ATK properties in the property editor. */
+void
+glade_atk_get_properties (GtkWidget * widget,
+ GbWidgetGetArgData * data)
+{
+ AtkObject *atko;
+
+ atko = gtk_widget_get_accessible (widget);
+
+ glade_atk_get_atk_properties (widget, atko, data);
+
+ if (ATK_IS_ACTION (atko))
+ {
+ glade_atk_get_actions (widget, ATK_ACTION (atko), data);
+ gtk_widget_show (actions_table);
+ }
+ else
+ {
+ gtk_widget_hide (actions_table);
+ }
+
+ glade_atk_get_relations (widget, atko, data);
+}
+
+
+/***************************************************************************
+ * Applying properties from the property editor.
+ ***************************************************************************/
+
+static void
+glade_atk_set_atk_properties (GtkWidget * widget,
+ AtkObject * atko,
+ GbWidgetSetArgData * data)
+{
+ char *name, *description;
+
+ name = gb_widget_input_string (data, GladeATKName);
+ if (data->apply)
+ {
+ /* Set a flag to indicate the name has been set explicitly. */
+ g_object_set_data (G_OBJECT (atko), GladeATKName, "T");
+ atk_object_set_name (atko, name);
+ }
+
+ description = gb_widget_input_text (data, GladeATKDescription);
+ if (data->apply)
+ {
+ g_object_set_data (G_OBJECT (atko), GladeATKDescription, "T");
+ atk_object_set_description (atko, description);
+ }
+ g_free (description);
+
+#if 0
+ if (GTK_IS_TREE_VIEW (widget))
+ {
+ char *table_caption;
+
+ table_caption = gb_widget_input_text (data, GladeATKTableCaption);
+ if (data->apply)
+ {
+ g_object_set_data (G_OBJECT (atko), GladeATKTableCaption, "T");
+ g_object_set (G_OBJECT (atko),
+ "AtkObject::accessible-table-caption", table_caption,
+ NULL);
+ }
+ g_free (table_caption);
+ }
+#endif
+}
+
+
+static void
+glade_atk_set_actions (GtkWidget * widget,
+ AtkAction * action,
+ GbWidgetSetArgData * data)
+{
+ gint n_actions, i;
+
+ n_actions = atk_action_get_n_actions (action);
+ for (i = 0; i < n_actions; i++)
+ {
+ const char *name;
+ char *property_name, *description;
+
+ name = atk_action_get_name (action, i);
+ property_name = glade_atk_get_action_property_name (name);
+
+ description = gb_widget_input_text (data, property_name);
+ if (data->apply)
+ atk_action_set_description (action, i, description);
+ g_free (description);
+
+ g_free (property_name);
+ }
+}
+
+
+/* This applies the ATK properties from the property editor. */
+void
+glade_atk_set_properties (GtkWidget * widget,
+ GbWidgetSetArgData * data)
+{
+ AtkObject *atko;
+
+ atko = gtk_widget_get_accessible (widget);
+
+ glade_atk_set_atk_properties (widget, atko, data);
+
+ if (ATK_IS_ACTION (atko))
+ glade_atk_set_actions (widget, ATK_ACTION (atko), data);
+
+ /* Note that we don't have to set the relations here, since that is done
+ when the relations dialog is closed. */
+}
+
+
+/***************************************************************************
+ * Saving properties in the XML.
+ ***************************************************************************/
+
+static void
+save_atk_property (GbWidgetGetArgData * data, GString *buffer, gint indent,
+ const gchar * tag_name, const gchar * tag_value)
+{
+ gboolean translatable, context;
+ gchar *comments;
+
+ if (tag_value == NULL)
+ return;
+
+ glade_util_get_translation_properties (data->widget, tag_name, &translatable,
+ &comments, &context);
+
+ save_buffer_add_indent (buffer, indent);
+ g_string_append (buffer, "<atkproperty name=\"");
+ save_buffer_add_string (buffer, tag_name);
+ g_string_append_c (buffer, '"');
+
+ if (translatable)
+ {
+ g_string_append (buffer, " translatable=\"yes\"");
+
+ if (context)
+ g_string_append (buffer, " context=\"yes\"");
+
+ if (comments && *comments)
+ {
+ g_string_append (buffer, " comments=\"");
+ save_buffer_add_string (buffer, comments);
+ g_string_append_c (buffer, '"');
+ }
+ }
+
+ g_string_append_c (buffer, '>');
+
+ save_buffer_add_string (buffer, tag_value);
+ g_string_append (buffer, "</atkproperty>\n");
+
+ if (data->save_translatable_strings)
+ save_add_translatable_string (data, tag_value);
+}
+
+
+static void
+glade_atk_save_atk_properties (GtkWidget * widget,
+ AtkObject * atko,
+ GbWidgetGetArgData * data,
+ GString * buffer,
+ gint indent)
+{
+ const char *name, *description;
+
+ /* We only save the name, description and caption if they are set explicitly
+ by the user, and are not empty. There may be default settings. */
+ name = atk_object_get_name (atko);
+ if (name && *name && g_object_get_data (G_OBJECT (atko), GladeATKName))
+ save_atk_property (data, buffer, indent, GladeATKName, name);
+
+ description = atk_object_get_description (atko);
+ if (description && *description
+ && g_object_get_data (G_OBJECT (atko), GladeATKDescription))
+ save_atk_property (data, buffer, indent, GladeATKDescription, description);
+
+#if 0
+ if (GTK_IS_TREE_VIEW (widget))
+ {
+ const char *table_caption;
+
+ g_object_get (G_OBJECT (atko),
+ "AtkObject::accessible-table-caption", &table_caption,
+ NULL);
+ if (table_caption && *table_caption
+ && g_object_get_data (G_OBJECT (atko), GladeATKTableCaption))
+ save_atk_property (data, buffer, indent, GladeATKTableCaption,
+ table_caption);
+ }
+#endif
+}
+
+
+static void
+glade_atk_save_actions (GtkWidget * widget,
+ AtkAction * action,
+ GbWidgetGetArgData * data,
+ GString * buffer,
+ gint indent)
+{
+ gint n_actions, i;
+
+ n_actions = atk_action_get_n_actions (action);
+ for (i = 0; i < n_actions; i++)
+ {
+ const char *name, *description;
+
+ name = atk_action_get_name (action, i);
+ description = atk_action_get_description (action, i);
+
+ if (description && *description)
+ {
+ save_buffer_add_indent (buffer, indent);
+ g_string_append (buffer, "<atkaction action_name=\"");
+ save_buffer_add_string (buffer, name);
+ g_string_append (buffer, "\" description=\"");
+ save_buffer_add_string (buffer, description);
+ g_string_append (buffer, "\"/>\n");
+
+ if (data->save_translatable_strings)
+ save_add_translatable_string (data, description);
+ }
+ }
+}
+
+
+static void
+glade_atk_save_relations (GtkWidget * widget,
+ AtkObject * atko,
+ GbWidgetGetArgData * data,
+ GString * buffer,
+ gint indent)
+{
+ GladeWidgetData *wdata;
+ GList *elem;
+
+ wdata = gtk_object_get_data (GTK_OBJECT (widget), GB_WIDGET_DATA_KEY);
+ g_return_if_fail (wdata != NULL);
+
+ for (elem = wdata->relations; elem; elem = elem->next)
+ {
+ GladeRelation *relation = elem->data;
+ const gchar *relation_name;
+ GList *target;
+
+ relation_name = atk_relation_type_get_name (relation->relationship);
+
+ /* We output a separate <atkrelation> element for each target. */
+ for (target = relation->targets; target; target = target->next)
+ {
+ GtkWidget *widget = target->data;
+ if (widget)
+ {
+ const gchar *target_name = gtk_widget_get_name (widget);
+ if (target_name && *target_name)
+ {
+ save_buffer_add_indent (buffer, indent);
+ g_string_append (buffer, "<atkrelation target=\"");
+ save_buffer_add_string (buffer, target_name);
+ g_string_append (buffer, "\" type=\"");
+ save_buffer_add_string (buffer, relation_name);
+ g_string_append (buffer, "\"/>\n");
+ }
+ }
+ }
+ }
+}
+
+
+/* This saves the ATK properties in the XML file. */
+void
+glade_atk_save_properties (GtkWidget * widget,
+ GbWidgetGetArgData * data)
+{
+ AtkObject *atko;
+ GString *buffer;
+ gint indent;
+
+ atko = gtk_widget_get_accessible (widget);
+
+ /* We output all the ATK properties into a buffer. Then if it isn't empty
+ we output an <accessibility> element with the buffer contents. */
+ buffer = g_string_sized_new (1024);
+ indent = data->indent + 1;
+
+ glade_atk_save_atk_properties (widget, atko, data, buffer, indent);
+
+ if (ATK_IS_ACTION (atko))
+ glade_atk_save_actions (widget, ATK_ACTION (atko), data, buffer, indent);
+
+ glade_atk_save_relations (widget, atko, data, buffer, indent);
+
+ if (buffer->len > 0)
+ {
+ save_start_tag (data, "accessibility");
+ g_string_append (data->buffer, buffer->str);
+ save_end_tag (data, "accessibility");
+ }
+
+ g_string_free (buffer, TRUE);
+}
+
+
+/***************************************************************************
+ * Loading properties from the XML.
+ ***************************************************************************/
+
+static void
+glade_atk_load_atk_properties (GtkWidget * widget,
+ AtkObject * atko,
+ GladeWidgetInfo * info)
+{
+ gint i;
+
+ for (i = 0; i < info->n_atk_props; i++)
+ {
+ GladeProperty *prop = &info->atk_props[i];
+
+ if (!strcmp (prop->name, GladeATKName))
+ {
+ /* Set a flag to indicate the name has been set explicitly. */
+ g_object_set_data (G_OBJECT (atko), GladeATKName, "T");
+ atk_object_set_name (atko, prop->value);
+
+ glade_util_set_translation_properties (widget, GladeATKName,
+ prop->translatable,
+ prop->translator_comments,
+ prop->context_prefix);
+ }
+ else if (!strcmp (prop->name, GladeATKDescription))
+ {
+ g_object_set_data (G_OBJECT (atko), GladeATKDescription, "T");
+ atk_object_set_description (atko, prop->value);
+
+ glade_util_set_translation_properties (widget, GladeATKDescription,
+ prop->translatable,
+ prop->translator_comments,
+ prop->context_prefix);
+ }
+#if 0
+ else if (GTK_IS_TREE_VIEW (widget)
+ && !strcmp (prop->name, GladeATKTableCaption))
+ {
+ g_object_set_data (G_OBJECT (atko), GladeATKTableCaption, "T");
+ g_object_set (G_OBJECT (atko),
+ "AtkObject::accessible-table-caption", prop->value,
+ NULL);
+
+ glade_util_set_translation_properties (widget, GladeATKTableCaption,
+ prop->translatable,
+ prop->translator_comments,
+ prop->context_prefix);
+ }
+#endif
+ }
+}
+
+
+static void
+glade_atk_load_actions (GtkWidget * widget,
+ AtkAction * action,
+ GladeWidgetInfo * info)
+{
+ gint n_actions, i, j;
+
+ n_actions = atk_action_get_n_actions (action);
+
+ for (j = 0; j < info->n_atk_actions; j++)
+ {
+ GladeAtkActionInfo *action_info = &info->atk_actions[j];
+
+ for (i = 0; i < n_actions; i++)
+ {
+ const char *name;
+
+ name = atk_action_get_name (action, i);
+ if (!strcmp (name, action_info->action_name))
+ {
+ atk_action_set_description (action, i, action_info->description);
+ break;
+ }
+ }
+ }
+}
+
+
+static void
+glade_atk_load_relations (GtkWidget * widget,
+ AtkObject * atko,
+ GladeWidgetInfo *info,
+ GHashTable *all_widgets)
+{
+ GladeWidgetData *wdata;
+ gint i;
+
+ wdata = gtk_object_get_data (GTK_OBJECT (widget), GB_WIDGET_DATA_KEY);
+ g_return_if_fail (wdata != NULL);
+
+ for (i = 0; i < info->n_relations; i++)
+ {
+ GladeAtkRelationInfo *relation = &info->relations[i];
+ AtkRelationType relationship = ATK_RELATION_NULL;
+ GtkWidget *target = NULL;
+
+ /* Convert the type string to an integer. */
+ if (relation->type && relation->type[0])
+ {
+ relationship = atk_relation_type_for_name (relation->type);
+ if (relationship == ATK_RELATION_NULL)
+ g_warning ("Couldn't find relation type: %s", relation->type);
+ }
+ else
+ g_warning ("<atkrelation> element has no type");
+
+ /* Try to find the target widget. */
+ if (relation->target && relation->target[0])
+ {
+ target = g_hash_table_lookup (all_widgets, relation->target);
+ if (!target)
+ g_warning ("Couldn't find relation target: %s", relation->target);
+ }
+ else
+ g_warning ("<atkrelation> element has no target");
+
+ /* Add the target to the widget's GladeWidgetData. */
+ if (relationship != ATK_RELATION_NULL && target)
+ {
+ glade_widget_data_add_relation (wdata, relationship, target);
+ }
+ }
+}
+
+
+/* This loads the ATK properties from the XML file. It is called after the
+ entire XML file is loaded and all the widgets are created, so that it
+ can resolve relation targets properly. */
+void
+glade_atk_load_properties (GtkWidget * widget,
+ GladeWidgetInfo * info,
+ GHashTable *all_widgets)
+{
+ AtkObject *atko;
+
+ atko = gtk_widget_get_accessible (widget);
+
+ glade_atk_load_atk_properties (widget, atko, info);
+
+ if (ATK_IS_ACTION (atko))
+ glade_atk_load_actions (widget, ATK_ACTION (atko), info);
+
+ glade_atk_load_relations (widget, atko, info, all_widgets);
+}
+
+
+
+
+
+/***************************************************************************
+ * Generating source code.
+ ***************************************************************************/
+
+static void
+glade_gtk_source_add_v (GString *buffer,
+ const gchar *format,
+ va_list args)
+{
+ gchar *buf;
+
+ buf = g_strdup_vprintf (format, args);
+ g_string_append (buffer, buf);
+ g_free (buf);
+}
+
+
+static void
+glade_atk_source_add (GString *buffer,
+ const gchar *format,
+ ...)
+{
+ va_list args;
+
+ va_start (args, format);
+ glade_gtk_source_add_v (buffer, format, args);
+ va_end (args);
+}
+
+
+void
+glade_atk_source_add_translator_comments (GString *buffer,
+ gboolean translatable,
+ const gchar *comments)
+{
+ /* If the property isn't being translated we don't bother outputting the
+ translator comments. */
+ if (!translatable || !comments || comments[0] == '\0')
+ return;
+
+ /* We simply output it in a C comment.
+ FIXME: If the comments contain an end of comment marker it won't
+ compile. */
+ g_string_append (buffer, " /* ");
+ g_string_append (buffer, comments);
+ g_string_append (buffer, " */\n");
+}
+
+
+static void
+glade_atk_write_atk_properties_source (GtkWidget * widget,
+ AtkObject * atko,
+ GbWidgetWriteSourceData * data,
+ GString * buffer)
+{
+ const char *name, *description;
+ gboolean translatable, context;
+ gchar *comments;
+
+ /* We only generate code for setting the name, description and caption if
+ they are set explicitly by the user, and are not empty. There may be
+ default settings. */
+ name = atk_object_get_name (atko);
+ if (name && *name && g_object_get_data (G_OBJECT (atko), GladeATKName))
+ {
+ glade_util_get_translation_properties (widget, GladeATKName,
+ &translatable,
+ &comments, &context);
+ glade_atk_source_add_translator_comments (buffer, translatable,
+ comments);
+
+ glade_atk_source_add (buffer,
+ " atk_object_set_name (atko, %s);\n",
+ source_make_string_full (name, data->use_gettext && translatable, context));
+ }
+
+ description = atk_object_get_description (atko);
+ if (description && *description
+ && g_object_get_data (G_OBJECT (atko), GladeATKDescription))
+ {
+ glade_util_get_translation_properties (widget, GladeATKDescription,
+ &translatable,
+ &comments, &context);
+ glade_atk_source_add_translator_comments (buffer, translatable,
+ comments);
+
+ glade_atk_source_add (buffer,
+ " atk_object_set_description (atko, %s);\n",
+ source_make_string_full (description, data->use_gettext && translatable, context));
+ }
+
+#if 0
+ if (GTK_IS_TREE_VIEW (widget))
+ {
+ const char *table_caption;
+
+ g_object_get (G_OBJECT (atko),
+ "AtkObject::accessible-table-caption", &table_caption,
+ NULL);
+ if (table_caption && *table_caption
+ && g_object_get_data (G_OBJECT (atko), GladeATKTableCaption))
+ {
+ glade_util_get_translation_properties (widget, GladeATKTableCaption,
+ &translatable,
+ &comments, &context);
+ glade_atk_source_add_translator_comments (buffer, translatable,
+ comments);
+
+ glade_atk_source_add (buffer,
+ " g_object_set (G_OBJECT (atko), \"AtkObject::accessible-table-caption\", %s,\n"
+ " NULL);\n",
+ source_make_string_full (table_caption, data->use_gettext && translatable, context));
+
+ }
+ }
+#endif
+}
+
+
+static void
+glade_atk_write_actions_source (GtkWidget * widget,
+ AtkAction * action,
+ GbWidgetWriteSourceData * data,
+ GString * buffer)
+{
+ gint n_actions, i;
+
+ n_actions = atk_action_get_n_actions (action);
+ for (i = 0; i < n_actions; i++)
+ {
+ const char *name, *description;
+
+ name = atk_action_get_name (action, i);
+ description = atk_action_get_description (action, i);
+
+ if (description && *description)
+ {
+ /* We use a support function to set the action description. */
+ glade_atk_source_add (buffer,
+ " glade_set_atk_action_description (ATK_ACTION (atko), %s,\n",
+ source_make_string (name, FALSE));
+
+ glade_atk_source_add (buffer,
+ " %s);\n",
+ source_make_string (description,
+ data->use_gettext));
+ }
+ }
+}
+
+
+static void
+glade_atk_write_relations_source (GtkWidget * widget,
+ AtkObject * atko,
+ GbWidgetWriteSourceData * data,
+ GString * buffer)
+{
+ GladeWidgetData *wdata;
+ gint max_targets = 0;
+ GList *elem;
+ gchar *decl;
+
+ wdata = gtk_object_get_data (GTK_OBJECT (widget), GB_WIDGET_DATA_KEY);
+ g_return_if_fail (wdata != NULL);
+
+ if (!wdata->relations)
+ return;
+
+ /* Find out the maximum number of targets in the relations. We'll use one
+ temporary targets array for all of them. */
+ for (elem = wdata->relations; elem; elem = elem->next)
+ {
+ GladeRelation *relation = elem->data;
+ gint n_targets = 0;
+ GList *target;
+
+ for (target = relation->targets; target; target = target->next)
+ {
+ if (target->data)
+ n_targets++;
+ }
+
+ max_targets = MAX (max_targets, n_targets);
+ }
+
+ if (max_targets == 0)
+ return;
+
+ source_ensure_decl (data, " AtkRelationSet *tmp_relation_set;\n");
+ source_ensure_decl (data, " AtkRelationType tmp_relationship;\n");
+ source_ensure_decl (data, " AtkRelation *tmp_relation;\n");
+ glade_atk_source_add (buffer,
+ " tmp_relation_set = atk_object_ref_relation_set (atko);\n");
+
+ /* Output the declaration of the temporary targets array. */
+ decl = g_strdup_printf (" AtkObject *%s_relation_targets[%i];\n",
+ data->wname, max_targets);
+ source_ensure_decl (data, decl);
+ g_free (decl);
+
+ for (elem = wdata->relations; elem; elem = elem->next)
+ {
+ GladeRelation *relation = elem->data;
+ gint n_targets = 0, target_num = 0;
+ GList *target;
+ const gchar *relation_name;
+
+ /* Remember that target widgets may be NULL if the target widget is
+ destroyed, so we count how many non-NULL targets there are. */
+ for (target = relation->targets; target; target = target->next)
+ {
+ if (target->data)
+ n_targets++;
+ }
+
+ if (n_targets == 0)
+ continue;
+
+ /* We have to get a reference to all the AtkObjects and add them to the
+ targets array. */
+ for (target = relation->targets; target; target = target->next)
+ {
+ GtkWidget *target_widget = target->data;
+ gchar *target_name;
+
+ target_name = source_create_valid_identifier (gtk_widget_get_name (target_widget));
+ glade_atk_source_add (buffer,
+ " %s_relation_targets[%i] = gtk_widget_get_accessible (%s);\n",
+ data->wname, target_num, target_name);
+ g_free (target_name);
+ target_num++;
+ }
+
+ /* We have to output code to lookup the relationship code from the
+ string name, as it may be an externally-defined relationship so the
+ code may change. */
+ relation_name = atk_relation_type_get_name (relation->relationship);
+
+ glade_atk_source_add (buffer,
+ " tmp_relationship = atk_relation_type_for_name (%s);\n",
+ source_make_string (relation_name, FALSE));
+ glade_atk_source_add (buffer,
+ " tmp_relation = atk_relation_new (%s_relation_targets, %i, tmp_relationship);\n",
+ data->wname, target_num);
+
+
+ glade_atk_source_add (buffer,
+ " atk_relation_set_add (tmp_relation_set, tmp_relation);\n"
+ " g_object_unref (G_OBJECT (tmp_relation));\n");
+ }
+
+ glade_atk_source_add (buffer, " g_object_unref (G_OBJECT (tmp_relation_set));\n");
+}
+
+
+/* This generates the source code to set the ATK properties, event descriptions
+ and relations. */
+void
+glade_atk_write_source (GtkWidget * widget,
+ GbWidgetWriteSourceData * data)
+{
+ AtkObject *atko;
+ GString *buffer;
+
+ atko = gtk_widget_get_accessible (widget);
+
+ /* We output all the ATK code into a buffer. Then if it isn't empty
+ we output the declaration for the AtkObject and the get_accessible()
+ call. */
+ buffer = g_string_sized_new (1024);
+
+ glade_atk_write_atk_properties_source (widget, atko, data, buffer);
+
+ if (ATK_IS_ACTION (atko))
+ glade_atk_write_actions_source (widget, ATK_ACTION (atko), data, buffer);
+
+ glade_atk_write_relations_source (widget, atko, data, buffer);
+
+ if (buffer->len > 0)
+ {
+ source_ensure_decl (data, " AtkObject *atko;\n");
+
+ source_add_to_buffer (data, GLADE_ATK_SOURCE,
+ " atko = gtk_widget_get_accessible (%s);\n%s\n",
+ data->wname, buffer->str);
+ }
+
+ g_string_free (buffer, TRUE);
+}
+