]> Pileus Git - ~andy/gtk/blob - tests/a11y/tree-relationships.c
Change FSF Address
[~andy/gtk] / tests / a11y / tree-relationships.c
1 /*
2  * Copyright (C) 2011 SUSE Linux Products GmbH, Nurenberg, Germany
3  *
4  * Author:
5  *      Mike Gorse <mgorse@suse.com>
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Library General Public
9  * License as published by the Free Software Foundation; either
10  * version 2 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Library General Public License for more details.
16  *
17  * You should have received a copy of the GNU Library General Public
18  * License along with this library. If not, see <http://www.gnu.org/licenses/>.
19  */
20
21 #include <gtk/gtk.h>
22
23 const gchar list_ui[] =
24   "<interface>"
25   "  <object class='GtkListStore' id='liststore1'>"
26   "    <columns>"
27   "      <column type='gchararray'/>"
28   "      <column type='gchararray'/>"
29   "      <column type='gchararray'/>"
30   "      <column type='gboolean'/>"
31   "      <column type='gint'/>"
32   "      <column type='gint'/>"
33   "    </columns>"
34   "    <data>"
35   "      <row><col id='0'>One</col><col id='1'>Two</col><col id='2'>Three</col><col id='3'>True</col><col id='4'>50</col><col id='5'>50</col></row>"
36   "    </data>"
37   "  </object>"
38   "  <object class='GtkWindow' id='window1'>"
39   "    <child>"
40   "      <object class='GtkTreeView' id='treeview1'>"
41   "        <property name='visible'>True</property>"
42   "        <property name='model'>liststore1</property>"
43   "        <child>"
44   "          <object class='GtkTreeViewColumn' id='column1'>"
45   "            <property name='title' translatable='yes'>First column</property>"
46   "            <child>"
47   "              <object class='GtkCellRendererText' id='renderer1'>"
48   "              </object>"
49   "              <attributes>"
50   "                <attribute name='text'>0</attribute>"
51   "              </attributes>"
52   "            </child>"
53   "            <child>"
54   "              <object class='GtkCellRendererToggle' id='renderer2'>"
55   "              </object>"
56   "              <attributes>"
57   "                <attribute name='active'>3</attribute>"
58   "              </attributes>"
59   "            </child>"
60   "          </object>"
61   "        </child>"
62   "        <child>"
63   "          <object class='GtkTreeViewColumn' id='column2'>"
64   "            <property name='title' translatable='yes'>Second column</property>"
65   "            <child>"
66   "              <object class='GtkCellRendererText' id='renderer3'>"
67   "              </object>"
68   "              <attributes>"
69   "                <attribute name='text'>1</attribute>"
70   "              </attributes>"
71   "            </child>"
72   "            <child>"
73   "              <object class='GtkCellRendererProgress' id='renderer4'>"
74   "              </object>"
75   "              <attributes>"
76   "                <attribute name='value'>4</attribute>"
77   "              </attributes>"
78   "            </child>"
79   "          </object>"
80   "        </child>"
81   "      </object>"
82   "    </child>"
83   "  </object>"
84   "</interface>";
85
86 static GtkWidget *
87 builder_get_toplevel (GtkBuilder *builder)
88 {
89   GSList *list, *walk;
90   GtkWidget *window = NULL;
91
92   list = gtk_builder_get_objects (builder);
93   for (walk = list; walk; walk = walk->next)
94     {
95       if (GTK_IS_WINDOW (walk->data) &&
96           gtk_widget_get_parent (walk->data) == NULL)
97         {
98           window = walk->data;
99           break;
100         }
101     }
102
103   g_slist_free (list);
104
105   return window;
106 }
107
108 const gchar tree_ui[] =
109   "<interface>"
110   "  <object class='GtkTreeStore' id='treestore1'>"
111   "    <columns>"
112   "      <column type='gchararray'/>"
113   "      <column type='gchararray'/>"
114   "      <column type='gchararray'/>"
115   "      <column type='gboolean'/>"
116   "      <column type='gint'/>"
117   "      <column type='gint'/>"
118   "    </columns>"
119   "  </object>"
120   "  <object class='GtkWindow' id='window1'>"
121   "    <child>"
122   "      <object class='GtkTreeView' id='treeview1'>"
123   "        <property name='visible'>True</property>"
124   "        <property name='model'>treestore1</property>"
125   "        <child>"
126   "          <object class='GtkTreeViewColumn' id='column1'>"
127   "            <property name='title' translatable='yes'>First column</property>"
128   "            <child>"
129   "              <object class='GtkCellRendererText' id='renderer1'>"
130   "              </object>"
131   "              <attributes>"
132   "                <attribute name='text'>0</attribute>"
133   "              </attributes>"
134   "            </child>"
135   "            <child>"
136   "              <object class='GtkCellRendererToggle' id='renderer2'>"
137   "              </object>"
138   "              <attributes>"
139   "                <attribute name='active'>3</attribute>"
140   "              </attributes>"
141   "            </child>"
142   "          </object>"
143   "        </child>"
144   "        <child>"
145   "          <object class='GtkTreeViewColumn' id='column2'>"
146   "            <property name='title' translatable='yes'>Second column</property>"
147   "            <child>"
148   "              <object class='GtkCellRendererText' id='renderer3'>"
149   "              </object>"
150   "              <attributes>"
151   "                <attribute name='text'>1</attribute>"
152   "              </attributes>"
153   "            </child>"
154   "            <child>"
155   "              <object class='GtkCellRendererProgress' id='renderer4'>"
156   "              </object>"
157   "              <attributes>"
158   "                <attribute name='value'>4</attribute>"
159   "              </attributes>"
160   "            </child>"
161   "          </object>"
162   "        </child>"
163   "      </object>"
164   "    </child>"
165   "  </object>"
166   "</interface>";
167
168 static void
169 populate_tree (GtkBuilder *builder)
170 {
171   GtkTreeView *tv;
172   GtkTreeStore *store;
173   GtkTreeIter iter;
174
175   tv = (GtkTreeView *)gtk_builder_get_object (builder, "treeview1");
176   store = (GtkTreeStore *)gtk_tree_view_get_model (tv);
177
178   /* append some rows */
179   gtk_tree_store_append (store, &iter, NULL);
180   gtk_tree_store_set (store, &iter, 0, "a(1)", 1, "a(2)", 2, "a(3)", 3, TRUE, 4, 0, 5, 0, -1);
181   gtk_tree_store_append (store, &iter, &iter);
182   gtk_tree_store_set (store, &iter, 0, "aa(1)", 1, "aa(2)", 2, "aa(3)", 3, TRUE, 4, 0, 5, 0, -1);
183       gtk_tree_store_append (store, &iter, &iter);
184   gtk_tree_store_set (store, &iter, 0, "aaa(1)", 1, "aaa(2)", 2, "aaa(3)", 3, TRUE, 4, 0, 5, 0, -1);
185
186   gtk_tree_store_append (store, &iter, NULL);
187   gtk_tree_store_set (store, &iter, 0, "b(1)", 1, "b(2)", 2, "b(3)", 3, TRUE, 4, 0, 5, 0, -1);
188   gtk_tree_store_append (store, &iter, &iter);
189   gtk_tree_store_set (store, &iter, 0, "bb(1)", 1, "bb(2)", 2, "bb(3)", 3, TRUE, 4, 0, 5, 0, -1);
190       gtk_tree_store_append (store, &iter, &iter);
191   gtk_tree_store_set (store, &iter, 0, "bbb(1)", 1, "bbb(2)", 2, "bbb(3)", 3, TRUE, 4, 0, 5, 0, -1);
192 }
193
194 typedef struct {
195   gint count;
196   AtkObject *descendant;
197 } SignalData;
198
199 static void
200 active_descendant_changed (AtkObject  *accessible,
201                   AtkObject *descendant,
202                   SignalData *data)
203 {
204   data->count++;
205   if (data->descendant)
206     g_object_unref (data->descendant);
207   data->descendant = g_object_ref (descendant);
208 }
209
210 static gboolean
211 quit_loop (gpointer data)
212 {
213   GMainLoop *loop = data;
214   g_main_loop_quit (loop);
215   return FALSE;
216 }
217
218 static void
219 process_pending_idles ()
220 {
221   GMainLoop *loop = g_main_loop_new (NULL, FALSE);
222   gdk_threads_add_idle (quit_loop, loop);
223   g_main_loop_run (loop);
224 }
225
226 static void
227 test_a11y_tree_focus (void)
228 {
229   GtkBuilder *builder;
230   GtkWidget *window;
231   GError *error = NULL;
232   GtkTreeView *tv;
233   GtkTreePath *path = NULL;
234   GtkTreeViewColumn *focus_column = NULL;
235   SignalData data;
236   AtkObject *accessible;
237   AtkObject *child;
238   gchar *text;
239
240   builder = gtk_builder_new ();
241   gtk_builder_add_from_string (builder, tree_ui, -1, &error);
242   g_assert_no_error (error);
243   window = builder_get_toplevel (builder);
244   g_assert (window);
245
246   populate_tree (builder);
247
248   tv = (GtkTreeView *)gtk_builder_get_object (builder, "treeview1");
249   gtk_tree_view_expand_all (tv);
250
251   gtk_widget_show (window);
252
253   gtk_tree_view_get_cursor (tv, &path, &focus_column);
254   gtk_tree_path_down (path);
255   data.count = 0;
256   data.descendant = NULL;
257   accessible = gtk_widget_get_accessible (GTK_WIDGET (tv));
258   g_signal_connect (accessible, "active_descendant_changed",
259                     G_CALLBACK (active_descendant_changed), &data);
260   gtk_tree_view_set_cursor (tv, path, focus_column, FALSE);
261   /* hack: active_descendant_change gets fired in an idle handler */
262   process_pending_idles ();
263   /* Getting only one signal might be ideal, although we get three or so */
264   g_assert_cmpint (data.count, >=, 1);
265   child = atk_object_ref_accessible_child (data.descendant, 0);
266   text = atk_text_get_text (ATK_TEXT (child), 0, -1);
267   g_assert_cmpstr (text, ==, "aa(1)");
268   g_free (text);
269
270   g_object_unref (child);
271
272   g_object_unref (data.descendant);
273   g_object_unref (builder);
274
275 }
276
277 static AtkObject *
278 find_root_accessible (GtkTreeView *tv, const char *name)
279 {
280   AtkObject *tvaccessible = gtk_widget_get_accessible (GTK_WIDGET (tv));
281   int i = 0;
282
283   for (i = 0;;i++)
284   {
285     AtkObject *child = atk_object_ref_accessible_child (tvaccessible, i);
286     AtkObject *item;
287     gchar *text;
288     if (!child)
289       return NULL;
290     item = atk_object_ref_accessible_child (child, 0);
291     if (!item)
292       continue;
293     text = atk_text_get_text (ATK_TEXT (item), 0, -1);
294     g_object_unref (item);
295     if (!g_strcmp0 (text, name))
296     {
297       g_free (text);
298       return child;
299     }
300     g_free (text);
301     g_object_unref (child);
302   }
303 }
304
305 static void
306 test_node_child_of (AtkObject *child, AtkObject *parent)
307 {
308   AtkRelationSet *set = atk_object_ref_relation_set (child);
309   AtkRelation *relation = atk_relation_set_get_relation_by_type (set, ATK_RELATION_NODE_CHILD_OF);
310
311   g_assert (relation != NULL);
312   g_assert_cmpint (relation->target->len, ==, 1);
313   g_assert (g_ptr_array_index (relation->target, 0) == parent);
314   g_object_unref (set);
315 }
316
317 static void
318 test_node_parent_of (AtkObject *parent, AtkObject *child)
319 {
320   AtkRelationSet *set = atk_object_ref_relation_set (parent);
321   AtkRelation *relation = atk_relation_set_get_relation_by_type (set, ATK_RELATION_NODE_PARENT_OF);
322
323   g_assert (relation != NULL);
324   g_assert_cmpint (relation->target->len, ==, 1);
325   g_assert (g_ptr_array_index (relation->target, 0) == child);
326   g_object_unref (set);
327 }
328
329 static void
330 test_relations (AtkObject *parent, AtkObject *child)
331 {
332   test_node_parent_of (parent, child);
333   test_node_child_of (child, parent);
334 }
335
336 static void
337 test_a11y_tree_relations (void)
338 {
339   GtkBuilder *builder;
340   GtkWidget *window;
341   GError *error = NULL;
342   GtkTreeView *tv;
343   AtkObject *parent, *child;
344
345   builder = gtk_builder_new ();
346   gtk_builder_add_from_string (builder, tree_ui, -1, &error);
347   g_assert_no_error (error);
348   window = builder_get_toplevel (builder);
349   g_assert (window);
350
351   populate_tree (builder);
352
353   tv = (GtkTreeView *)gtk_builder_get_object (builder, "treeview1");
354   gtk_tree_view_expand_all (tv);
355
356   gtk_widget_show (window);
357
358   parent = find_root_accessible (tv, "a(1)");
359 child = find_root_accessible (tv, "aa(1)");
360   test_relations (parent, child);
361   g_object_unref (parent);
362   parent = child;
363 child = find_root_accessible (tv, "aaa(1)");
364   test_relations (parent, child);
365   g_object_unref (parent);
366   g_object_unref (child);
367
368   g_object_unref (builder);
369
370 }
371
372 int
373 main (int argc, char *argv[])
374 {
375   gtk_test_init (&argc, &argv, NULL);
376
377   g_test_add_func ("/a11y/tree/focus", test_a11y_tree_focus);
378   g_test_add_func ("/a11y/tree/relations", test_a11y_tree_relations);
379
380   return g_test_run ();
381 }
382