1 /* This file is part of the GtkHTML library.
2 *
3 * Copyright 2002 Ximian, Inc.
4 *
5 * Author: Radek Doulik
6 *
7 *
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Library General Public
10 * License as published by the Free Software Foundation; either
11 * version 2 of the License, or (at your option) any later version.
12 *
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Library General Public License for more details.
17 *
18 * You should have received a copy of the GNU Library General Public License
19 * along with this library; see the file COPYING.LIB. If not, write to
20 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
21 * Boston, MA 02110-1301, USA.
22 */
23
24 #include <config.h>
25 #include <atk/atktable.h>
26
27 #include "htmltable.h"
28 #include "htmltablecell.h"
29 #include "gtkhtml.h"
30 #include "htmlengine.h"
31
32 #include "html.h"
33 #include "object.h"
34 #include "table.h"
35 #include "utils.h"
36
37 static void html_a11y_table_class_init (HTMLA11YTableClass *klass);
38 static void html_a11y_table_init (HTMLA11YTable *a11y_table);
39 static void atk_table_interface_init (AtkTableIface *iface);
40
41 static AtkObject * html_a11y_table_ref_at (AtkTable *table, gint row, gint column);
42 static gint html_a11y_table_get_index_at (AtkTable *table, gint row, gint column);
43 static gint html_a11y_table_get_column_at_index (AtkTable *table, gint index);
44 static gint html_a11y_table_get_row_at_index (AtkTable *table, gint index);
45 static gint html_a11y_table_get_n_columns (AtkTable *table);
46 static gint html_a11y_table_get_n_rows (AtkTable *table);
47 static gint html_a11y_table_get_column_extent_at (AtkTable *table, gint row, gint column);
48 static gint html_a11y_table_get_row_extent_at (AtkTable *table, gint row, gint column);
49 static AtkObject * html_a11y_table_get_column_header (AtkTable *table, gint column);
50 static AtkObject * html_a11y_table_get_row_header (AtkTable *table, gint row);
51
52 static AtkObjectClass *parent_class = NULL;
53
54 GType
html_a11y_table_get_type(void)55 html_a11y_table_get_type (void)
56 {
57 static GType type = 0;
58
59 if (!type) {
60 static const GTypeInfo tinfo = {
61 sizeof (HTMLA11YTableClass),
62 NULL, /* base init */
63 NULL, /* base finalize */
64 (GClassInitFunc) html_a11y_table_class_init, /* class init */
65 NULL, /* class finalize */
66 NULL, /* class data */
67 sizeof (HTMLA11YTable), /* instance size */
68 0, /* nb preallocs */
69 (GInstanceInitFunc) html_a11y_table_init, /* instance init */
70 NULL /* value table */
71 };
72
73 static const GInterfaceInfo atk_table_info = {
74 (GInterfaceInitFunc) atk_table_interface_init,
75 (GInterfaceFinalizeFunc) NULL,
76 NULL
77 };
78
79 type = g_type_register_static (G_TYPE_HTML_A11Y, "HTMLA11YTable", &tinfo, 0);
80 g_type_add_interface_static (type, ATK_TYPE_TABLE, &atk_table_info);
81 }
82
83 return type;
84 }
85
86 static void
atk_table_interface_init(AtkTableIface * iface)87 atk_table_interface_init (AtkTableIface *iface)
88 {
89 g_return_if_fail (iface != NULL);
90
91 iface->ref_at = html_a11y_table_ref_at;
92 iface->get_index_at = html_a11y_table_get_index_at;
93 iface->get_column_at_index = html_a11y_table_get_column_at_index;
94 iface->get_row_at_index = html_a11y_table_get_row_at_index;
95 iface->get_n_columns = html_a11y_table_get_n_columns;
96 iface->get_n_rows = html_a11y_table_get_n_rows;
97 iface->get_column_extent_at = html_a11y_table_get_column_extent_at;
98 iface->get_row_extent_at = html_a11y_table_get_row_extent_at;
99 iface->get_column_header = html_a11y_table_get_column_header;
100 iface->get_row_header = html_a11y_table_get_row_header;
101 }
102
103 static void
html_a11y_table_finalize(GObject * obj)104 html_a11y_table_finalize (GObject *obj)
105 {
106 G_OBJECT_CLASS (parent_class)->finalize (obj);
107 }
108
109 static void
html_a11y_table_initialize(AtkObject * obj,gpointer data)110 html_a11y_table_initialize (AtkObject *obj,
111 gpointer data)
112 {
113 /* printf ("html_a11y_table_initialize\n"); */
114
115 if (ATK_OBJECT_CLASS (parent_class)->initialize)
116 ATK_OBJECT_CLASS (parent_class)->initialize (obj, data);
117 }
118
119 static void
html_a11y_table_class_init(HTMLA11YTableClass * klass)120 html_a11y_table_class_init (HTMLA11YTableClass *klass)
121 {
122 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
123 AtkObjectClass *atk_class = ATK_OBJECT_CLASS (klass);
124
125 parent_class = g_type_class_peek_parent (klass);
126
127 atk_class->initialize = html_a11y_table_initialize;
128 gobject_class->finalize = html_a11y_table_finalize;
129 }
130
131 static void
html_a11y_table_init(HTMLA11YTable * a11y_table)132 html_a11y_table_init (HTMLA11YTable *a11y_table)
133 {
134 }
135
136 AtkObject *
html_a11y_table_new(HTMLObject * html_obj)137 html_a11y_table_new (HTMLObject *html_obj)
138 {
139 GObject *object;
140 AtkObject *accessible;
141
142 g_return_val_if_fail (HTML_IS_TABLE (html_obj), NULL);
143
144 object = g_object_new (G_TYPE_HTML_A11Y_TABLE, NULL);
145
146 accessible = ATK_OBJECT (object);
147 atk_object_initialize (accessible, html_obj);
148
149 accessible->role = ATK_ROLE_TABLE;
150
151 /* printf ("created new html accessible table object\n"); */
152
153 return accessible;
154 }
155
156 static gboolean
is_valid(AtkObject * table)157 is_valid (AtkObject *table)
158 {
159 GtkHTMLA11Y * htmla11y = html_a11y_get_gtkhtml_parent (HTML_A11Y (table));
160 GtkHTML *html = GTK_HTML_A11Y_GTKHTML (htmla11y);
161 AtkStateSet *ss;
162
163 HTMLTable *to = HTML_TABLE (HTML_A11Y_HTML (table));
164 if (!htmla11y)
165 return FALSE;
166
167 if (!to)
168 return FALSE;
169
170 if (html->engine->parsing)
171 return FALSE;
172
173 ss = atk_object_ref_state_set (ATK_OBJECT (htmla11y));
174 if (atk_state_set_contains_state (ss, ATK_STATE_DEFUNCT)) {
175 g_object_unref (ss);
176 return FALSE;
177 }
178 g_object_unref (ss);
179
180 return TRUE;
181 }
182
183 /*
184 * AtkTable interface
185 */
186
187 static AtkObject *
html_a11y_table_ref_at(AtkTable * table,gint row,gint column)188 html_a11y_table_ref_at (AtkTable *table,
189 gint row,
190 gint column)
191 {
192 AtkObject *accessible = NULL;
193 HTMLTable *to = HTML_TABLE (HTML_A11Y_HTML (table));
194 HTMLTableCell *cell;
195
196 if (!is_valid (ATK_OBJECT (table)))
197 return NULL;
198
199 g_return_val_if_fail (row < to->totalRows, NULL);
200 g_return_val_if_fail (column < to->totalCols, NULL);
201
202 cell = to->cells[row][column];
203
204 if (cell) {
205 accessible = html_utils_get_accessible (HTML_OBJECT (cell), ATK_OBJECT (table));
206 if (accessible)
207 g_object_ref (accessible);
208 }
209
210 return accessible;
211 }
212
213 static gint
html_a11y_table_get_index_at(AtkTable * table,gint row,gint column)214 html_a11y_table_get_index_at (AtkTable *table,
215 gint row,
216 gint column)
217 {
218 HTMLTable *to = HTML_TABLE (HTML_A11Y_HTML (table));
219
220 if (!is_valid (ATK_OBJECT (table)))
221 return -1;
222
223 g_return_val_if_fail (row < to->totalRows, -1);
224 g_return_val_if_fail (column < to->totalCols, -1);
225 g_return_val_if_fail (to->cells[row][column], -1);
226
227 return html_object_get_child_index (HTML_OBJECT (to), HTML_OBJECT (to->cells[row][column]));
228 }
229
230 static gint
html_a11y_table_get_column_at_index(AtkTable * table,gint index)231 html_a11y_table_get_column_at_index (AtkTable *table,
232 gint index)
233 {
234 HTMLTable *to = HTML_TABLE (HTML_A11Y_HTML (table));
235 HTMLTableCell *cell;
236
237 if (!is_valid (ATK_OBJECT (table)))
238 return -1;
239
240 cell = HTML_TABLE_CELL (html_object_get_child (HTML_OBJECT (to), index));
241
242 return cell ? cell->col : -1;
243 }
244
245 static gint
html_a11y_table_get_row_at_index(AtkTable * table,gint index)246 html_a11y_table_get_row_at_index (AtkTable *table,
247 gint index)
248 {
249 HTMLTable *to = HTML_TABLE (HTML_A11Y_HTML (table));
250 HTMLTableCell *cell;
251
252 if (!is_valid (ATK_OBJECT (table)))
253 return -1;
254
255 cell = HTML_TABLE_CELL (html_object_get_child (HTML_OBJECT (to), index));
256
257 return cell ? cell->row : -1;
258 }
259
260 static gint
html_a11y_table_get_n_columns(AtkTable * table)261 html_a11y_table_get_n_columns (AtkTable *table)
262 {
263 HTMLTable *to = HTML_TABLE (HTML_A11Y_HTML (table));
264
265 if (!is_valid (ATK_OBJECT (table)))
266 return -1;
267
268 return to->totalCols;
269 }
270
271 static gint
html_a11y_table_get_n_rows(AtkTable * table)272 html_a11y_table_get_n_rows (AtkTable *table)
273 {
274 HTMLTable *to = HTML_TABLE (HTML_A11Y_HTML (table));
275
276 if (!is_valid (ATK_OBJECT (table)))
277 return -1;
278
279 return to->totalRows;
280 }
281
282 static gint
html_a11y_table_get_column_extent_at(AtkTable * table,gint row,gint column)283 html_a11y_table_get_column_extent_at (AtkTable *table,
284 gint row,
285 gint column)
286 {
287 HTMLTable *to = HTML_TABLE (HTML_A11Y_HTML (table));
288
289 if (!is_valid (ATK_OBJECT (table)))
290 return -1;
291
292 g_return_val_if_fail (row < to->totalRows, -1);
293 g_return_val_if_fail (column < to->totalCols, -1);
294 g_return_val_if_fail (to->cells[row][column], -1);
295
296 return to->cells[row][column]->cspan;
297 }
298
299 static gint
html_a11y_table_get_row_extent_at(AtkTable * table,gint row,gint column)300 html_a11y_table_get_row_extent_at (AtkTable *table,
301 gint row,
302 gint column)
303 {
304 HTMLTable *to = HTML_TABLE (HTML_A11Y_HTML (table));
305
306 if (!is_valid (ATK_OBJECT (table)))
307 return -1;
308
309 g_return_val_if_fail (row < to->totalRows, -1);
310 g_return_val_if_fail (column < to->totalCols, -1);
311 g_return_val_if_fail (to->cells[row][column], -1);
312
313 return to->cells[row][column]->rspan;
314 }
315
316 static AtkObject *
html_a11y_table_get_column_header(AtkTable * table,gint column)317 html_a11y_table_get_column_header (AtkTable *table,
318 gint column)
319 {
320 HTMLTable *to = HTML_TABLE (HTML_A11Y_HTML (table));
321
322 if (!is_valid (ATK_OBJECT (table)))
323 return NULL;
324
325 g_return_val_if_fail (column < to->totalCols, NULL);
326 g_return_val_if_fail (to->cells[0][column], NULL);
327
328 return to->cells[0][column]->heading
329 ? html_utils_get_accessible (HTML_OBJECT (to->cells[0][column]), ATK_OBJECT (table)) : NULL;
330 }
331
332 static AtkObject *
html_a11y_table_get_row_header(AtkTable * table,gint row)333 html_a11y_table_get_row_header (AtkTable *table,
334 gint row)
335 {
336 HTMLTable *to = HTML_TABLE (HTML_A11Y_HTML (table));
337
338 if (!is_valid (ATK_OBJECT (table)))
339 return NULL;
340
341 g_return_val_if_fail (row < to->totalRows, NULL);
342 g_return_val_if_fail (to->cells[row][0], NULL);
343
344 return to->cells[row][0]->heading
345 ? html_utils_get_accessible (HTML_OBJECT (to->cells[row][0]), ATK_OBJECT (table)) : NULL;
346 }
347
348 /* unsupported calls
349 *
350 * AtkObject*
351 * (* get_caption) (AtkTable *table);
352 * const gchar * (* get_column_description) (AtkTable *table,
353 * gint column);
354 * const gchar * (* get_row_description) (AtkTable *table,
355 * gint row);
356 * AtkObject* (* get_summary) (AtkTable *table);
357 * void (* set_caption) (AtkTable *table,
358 * AtkObject *caption);
359 * void (* set_column_description) (AtkTable *table,
360 * gint column,
361 * const gchar *description);
362 * void (* set_column_header) (AtkTable *table,
363 * gint column,
364 * AtkObject *header);
365 * void (* set_row_description) (AtkTable *table,
366 * gint row,
367 * const gchar *description);
368 * void (* set_row_header) (AtkTable *table,
369 * gint row,
370 * AtkObject *header);
371 * void (* set_summary) (AtkTable *table,
372 * AtkObject *accessible);
373 * gint (* get_selected_columns) (AtkTable *table,
374 * gint **selected);
375 * gint (* get_selected_rows) (AtkTable *table,
376 * gint **selected);
377 * gboolean (* is_column_selected) (AtkTable *table,
378 * gint column);
379 * gboolean (* is_row_selected) (AtkTable *table,
380 * gint row);
381 * gboolean (* is_selected) (AtkTable *table,
382 * gint row,
383 * gint column);
384 * gboolean (* add_row_selection) (AtkTable *table,
385 * gint row);
386 * gboolean (* remove_row_selection) (AtkTable *table,
387 * gint row);
388 * gboolean (* add_column_selection) (AtkTable *table,
389 * gint column);
390 * gboolean (* remove_column_selection) (AtkTable *table,
391 * gint column);
392 */
393