[evince] Expose form fields as AtkObject children of the page



commit d70748646a4d89a614a3774e3a74a2002209cc44
Author: Joanmarie Diggs <jdiggs igalia com>
Date:   Mon Jun 23 12:06:46 2014 -0400

    Expose form fields as AtkObject children of the page
    
    https://bugzilla.gnome.org/show_bug.cgi?id=728475

 libview/Makefile.am                |    2 +
 libview/ev-form-field-accessible.c |  241 ++++++++++++++++++++++++++++++++++++
 libview/ev-form-field-accessible.h |   55 ++++++++
 libview/ev-page-accessible.c       |    8 +-
 libview/ev-view-private.h          |    2 +
 libview/ev-view.c                  |    8 +-
 6 files changed, 311 insertions(+), 5 deletions(-)
---
diff --git a/libview/Makefile.am b/libview/Makefile.am
index 6d0ab7d..c45f09c 100644
--- a/libview/Makefile.am
+++ b/libview/Makefile.am
@@ -2,6 +2,7 @@ lib_LTLIBRARIES = libevview3.la
 
 NOINST_H_SRC_FILES =                   \
        ev-annotation-window.h          \
+       ev-form-field-accessible.h      \
        ev-image-accessible.h           \
        ev-link-accessible.h            \
        ev-page-accessible.h            \
@@ -35,6 +36,7 @@ nodist_header_DATA = $(INST_H_BUILT_FILES)
 libevview3_la_SOURCES =                        \
        ev-annotation-window.c          \
        ev-document-model.c             \
+       ev-form-field-accessible.c      \
        ev-image-accessible.c           \
        ev-jobs.c                       \
        ev-job-scheduler.c              \
diff --git a/libview/ev-form-field-accessible.c b/libview/ev-form-field-accessible.c
new file mode 100644
index 0000000..d6f4b42
--- /dev/null
+++ b/libview/ev-form-field-accessible.c
@@ -0,0 +1,241 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8; c-indent-level: 8 -*- */
+/* this file is part of evince, a gnome document viewer
+ *
+ * Copyright (C) 2014 Igalia
+ * Author: Joanmarie Diggs <jdiggs igalia com>
+ *
+ * Evince 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.
+ *
+ * Evince 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include <config.h>
+
+#include "ev-form-field-accessible.h"
+#include "ev-view-private.h"
+
+struct _EvFormFieldAccessiblePrivate {
+       EvPageAccessible *page;
+       EvFormField      *form_field;
+       EvRectangle       area;
+};
+
+static void ev_form_field_accessible_component_iface_init (AtkComponentIface *iface);
+
+G_DEFINE_TYPE_WITH_CODE (EvFormFieldAccessible, ev_form_field_accessible, ATK_TYPE_OBJECT,
+                        G_IMPLEMENT_INTERFACE (ATK_TYPE_COMPONENT, 
ev_form_field_accessible_component_iface_init))
+
+static void
+ev_form_field_accessible_get_extents (AtkComponent *atk_component,
+                                     gint         *x,
+                                     gint         *y,
+                                     gint         *width,
+                                     gint         *height,
+                                     AtkCoordType coord_type)
+{
+       EvFormFieldAccessible *self;
+       EvViewAccessible *view_accessible;
+       gint page;
+       EvRectangle atk_rect;
+
+       self = EV_FORM_FIELD_ACCESSIBLE (atk_component);
+       view_accessible = ev_page_accessible_get_view_accessible (self->priv->page);
+       page = ev_page_accessible_get_page (self->priv->page);
+       _transform_doc_rect_to_atk_rect (view_accessible, page, &self->priv->area, &atk_rect, coord_type);
+       *x = atk_rect.x1;
+       *y = atk_rect.y1;
+       *width = atk_rect.x2 - atk_rect.x1;
+       *height = atk_rect.y2 - atk_rect.y1;
+}
+
+static gboolean
+ev_form_field_accessible_grab_focus (AtkComponent *atk_component)
+{
+       EvFormFieldAccessible *self;
+       EvView *view;
+
+       self = EV_FORM_FIELD_ACCESSIBLE (atk_component);
+       view = ev_page_accessible_get_view (self->priv->page);
+       _ev_view_focus_form_field (view, self->priv->form_field);
+
+       return TRUE;
+}
+
+static void
+ev_form_field_accessible_component_iface_init (AtkComponentIface *iface)
+{
+       iface->get_extents = ev_form_field_accessible_get_extents;
+       iface->grab_focus = ev_form_field_accessible_grab_focus;
+}
+
+static AtkObject *
+ev_form_field_accessible_get_parent (AtkObject *atk_object)
+{
+       EvFormFieldAccessiblePrivate *priv = EV_FORM_FIELD_ACCESSIBLE (atk_object)->priv;
+
+       return ATK_OBJECT (priv->page);
+}
+
+static AtkRole
+ev_form_field_accessible_get_role (AtkObject *atk_object)
+{
+       EvFormField *ev_form_field;
+
+       ev_form_field = EV_FORM_FIELD_ACCESSIBLE (atk_object)->priv->form_field;
+       if (EV_IS_FORM_FIELD_BUTTON (ev_form_field)) {
+               EvFormFieldButton *field_button = EV_FORM_FIELD_BUTTON (ev_form_field);
+
+               switch (field_button->type) {
+               case EV_FORM_FIELD_BUTTON_CHECK:
+                       return ATK_ROLE_CHECK_BOX;
+               case EV_FORM_FIELD_BUTTON_RADIO:
+                       return ATK_ROLE_RADIO_BUTTON;
+               case EV_FORM_FIELD_BUTTON_PUSH:
+                       return ATK_ROLE_PUSH_BUTTON;
+               default:
+                       return ATK_ROLE_UNKNOWN;
+               }
+       }
+
+       if (EV_IS_FORM_FIELD_CHOICE (ev_form_field)) {
+               EvFormFieldChoice *field_choice = EV_FORM_FIELD_CHOICE (ev_form_field);
+
+               switch (field_choice->type) {
+               case EV_FORM_FIELD_CHOICE_COMBO:
+                       return ATK_ROLE_COMBO_BOX;
+               case EV_FORM_FIELD_CHOICE_LIST:
+                       return ATK_ROLE_LIST_BOX;
+               default:
+                       return ATK_ROLE_UNKNOWN;
+               }
+       }
+
+       if (EV_IS_FORM_FIELD_TEXT (ev_form_field)) {
+               EvFormFieldText *field_text = EV_FORM_FIELD_TEXT (ev_form_field);
+
+               if (field_text->is_password)
+                       return ATK_ROLE_PASSWORD_TEXT;
+               else if (field_text->type == EV_FORM_FIELD_TEXT_MULTILINE)
+                       return ATK_ROLE_TEXT;
+               else
+                       return ATK_ROLE_ENTRY;
+       }
+
+       return ATK_ROLE_UNKNOWN;
+}
+
+static AtkStateSet *
+ev_form_field_accessible_ref_state_set (AtkObject *atk_object)
+{
+       AtkStateSet *state_set;
+       AtkStateSet *copy_set;
+       AtkStateSet *page_accessible_state_set;
+       EvFormFieldAccessible *self;
+       EvFormField *ev_form_field;
+       EvViewAccessible *view_accessible;
+       gint page;
+
+       self = EV_FORM_FIELD_ACCESSIBLE (atk_object);
+       state_set = ATK_OBJECT_CLASS (ev_form_field_accessible_parent_class)->ref_state_set (atk_object);
+       atk_state_set_clear_states (state_set);
+
+       page_accessible_state_set = atk_object_ref_state_set (ATK_OBJECT (self->priv->page));
+       copy_set = atk_state_set_or_sets (state_set, page_accessible_state_set);
+
+       view_accessible = ev_page_accessible_get_view_accessible (self->priv->page);
+       page = ev_page_accessible_get_page (self->priv->page);
+       if (!ev_view_accessible_is_doc_rect_showing (view_accessible, page, &self->priv->area))
+               atk_state_set_remove_state (copy_set, ATK_STATE_SHOWING);
+
+       ev_form_field = EV_FORM_FIELD_ACCESSIBLE (atk_object)->priv->form_field;
+       if (EV_IS_FORM_FIELD_BUTTON (ev_form_field)) {
+               EvFormFieldButton *field_button = EV_FORM_FIELD_BUTTON (ev_form_field);
+
+               if (field_button->state) {
+                       if (field_button->type == EV_FORM_FIELD_BUTTON_PUSH)
+                               atk_state_set_add_state (copy_set, ATK_STATE_PRESSED);
+                       else
+                               atk_state_set_add_state (copy_set, ATK_STATE_CHECKED);
+               }
+       }
+
+       else if (EV_IS_FORM_FIELD_CHOICE (ev_form_field)) {
+               EvFormFieldChoice *field_choice = EV_FORM_FIELD_CHOICE (ev_form_field);
+
+               if (field_choice->is_editable && !ev_form_field->is_read_only)
+                       atk_state_set_add_state (copy_set, ATK_STATE_EDITABLE);
+               if (field_choice->multi_select)
+                       atk_state_set_add_state (copy_set, ATK_STATE_MULTISELECTABLE);
+       }
+
+       else if (EV_IS_FORM_FIELD_TEXT (ev_form_field)) {
+               EvFormFieldText *field_text = EV_FORM_FIELD_TEXT (ev_form_field);
+
+               if (!ev_form_field->is_read_only)
+                       atk_state_set_add_state (copy_set, ATK_STATE_EDITABLE);
+               if (field_text->type == EV_FORM_FIELD_TEXT_NORMAL)
+                       atk_state_set_add_state (copy_set, ATK_STATE_SINGLE_LINE);
+               else if (field_text->type == EV_FORM_FIELD_TEXT_MULTILINE)
+                       atk_state_set_add_state (copy_set, ATK_STATE_MULTI_LINE);
+       }
+
+       g_object_unref (state_set);
+       g_object_unref (page_accessible_state_set);
+
+       return copy_set;
+}
+
+static void
+ev_form_field_accessible_finalize (GObject *object)
+{
+       EvFormFieldAccessiblePrivate *priv = EV_FORM_FIELD_ACCESSIBLE (object)->priv;
+
+       g_object_unref (priv->form_field);
+
+       G_OBJECT_CLASS (ev_form_field_accessible_parent_class)->finalize (object);
+}
+
+static void
+ev_form_field_accessible_class_init (EvFormFieldAccessibleClass *klass)
+{
+       GObjectClass *object_class = G_OBJECT_CLASS (klass);
+       AtkObjectClass *atk_class = ATK_OBJECT_CLASS (klass);
+
+       object_class->finalize = ev_form_field_accessible_finalize;
+       atk_class->get_parent = ev_form_field_accessible_get_parent;
+       atk_class->get_role = ev_form_field_accessible_get_role;
+       atk_class->ref_state_set = ev_form_field_accessible_ref_state_set;
+
+       g_type_class_add_private (klass, sizeof (EvFormFieldAccessiblePrivate));
+}
+
+static void
+ev_form_field_accessible_init (EvFormFieldAccessible *accessible)
+{
+       accessible->priv = G_TYPE_INSTANCE_GET_PRIVATE (accessible, EV_TYPE_FORM_FIELD_ACCESSIBLE, 
EvFormFieldAccessiblePrivate);
+}
+
+EvFormFieldAccessible*
+ev_form_field_accessible_new (EvPageAccessible *page,
+                             EvFormField      *form_field,
+                             EvRectangle      *area)
+{
+       EvFormFieldAccessible *atk_form_field;
+
+       atk_form_field = g_object_new (EV_TYPE_FORM_FIELD_ACCESSIBLE, NULL);
+       atk_form_field->priv->page = page;
+       atk_form_field->priv->form_field = g_object_ref (form_field);
+       atk_form_field->priv->area = *area;
+
+       return EV_FORM_FIELD_ACCESSIBLE (atk_form_field);
+}
diff --git a/libview/ev-form-field-accessible.h b/libview/ev-form-field-accessible.h
new file mode 100644
index 0000000..0469e7e
--- /dev/null
+++ b/libview/ev-form-field-accessible.h
@@ -0,0 +1,55 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8; c-indent-level: 8 -*- */
+/* this file is part of evince, a gnome document viewer
+ *
+ * Copyright (C) 2014 Igalia
+ * Author: Joanmarie Diggs <jdiggs igalia com>
+ *
+ * Evince 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.
+ *
+ * Evince 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#if !defined (EVINCE_COMPILATION)
+#error "This is a private header."
+#endif
+
+#ifndef __EV_FORM_FIELD_ACCESSIBLE_H__
+#define __EV_FORM_FIELD_ACCESSIBLE_H__
+
+#include <gtk/gtk-a11y.h>
+#include "ev-page-accessible.h"
+#include "ev-form-field.h"
+
+#define EV_TYPE_FORM_FIELD_ACCESSIBLE      (ev_form_field_accessible_get_type ())
+#define EV_FORM_FIELD_ACCESSIBLE(obj)      (G_TYPE_CHECK_INSTANCE_CAST ((obj), 
EV_TYPE_FORM_FIELD_ACCESSIBLE, EvFormFieldAccessible))
+#define EV_IS_FORM_FIELD_ACCESSIBLE(obj)   (G_TYPE_CHECK_INSTANCE_TYPE ((obj), 
EV_TYPE_FORM_FIELD_ACCESSIBLE))
+
+typedef struct _EvFormFieldAccessible        EvFormFieldAccessible;
+typedef struct _EvFormFieldAccessibleClass   EvFormFieldAccessibleClass;
+typedef struct _EvFormFieldAccessiblePrivate EvFormFieldAccessiblePrivate;
+
+struct _EvFormFieldAccessible {
+        AtkObject parent;
+        EvFormFieldAccessiblePrivate *priv;
+};
+
+struct _EvFormFieldAccessibleClass {
+        AtkObjectClass parent_class;
+};
+
+GType ev_form_field_accessible_get_type (void);
+EvFormFieldAccessible *ev_form_field_accessible_new (EvPageAccessible *page,
+                                                    EvFormField      *form_field,
+                                                    EvRectangle      *area);
+
+#endif  /* __EV_FORM_FIELD_ACCESSIBLE_H__ */
diff --git a/libview/ev-page-accessible.c b/libview/ev-page-accessible.c
index 6ba0b32..454bae6 100644
--- a/libview/ev-page-accessible.c
+++ b/libview/ev-page-accessible.c
@@ -24,6 +24,7 @@
 
 #include <glib/gi18n-lib.h>
 #include "ev-page-accessible.h"
+#include "ev-form-field-accessible.h"
 #include "ev-image-accessible.h"
 #include "ev-link-accessible.h"
 #include "ev-view-private.h"
@@ -99,6 +100,7 @@ ev_page_accessible_initialize_children (EvPageAccessible *self)
        EvView *view;
        EvMappingList *images;
        EvMappingList *links;
+       EvMappingList *fields;
        GList *children = NULL;
        GList *list;
 
@@ -113,11 +115,13 @@ ev_page_accessible_initialize_children (EvPageAccessible *self)
 
        links = ev_page_cache_get_link_mapping (view->page_cache, self->priv->page);
        images = ev_page_cache_get_image_mapping (view->page_cache, self->priv->page);
-       if (!links && !images)
+       fields = ev_page_cache_get_form_field_mapping (view->page_cache, self->priv->page);
+       if (!links && !images && !fields)
                return;
 
        children = g_list_copy (ev_mapping_list_get_list (links));
        children = g_list_concat (children, g_list_copy (ev_mapping_list_get_list (images)));
+       children = g_list_concat (children, g_list_copy (ev_mapping_list_get_list (fields)));
 
        children = g_list_sort (children, (GCompareFunc) compare_mappings);
        self->priv->children = g_ptr_array_new_full (g_list_length (children), (GDestroyNotify) 
g_object_unref);
@@ -133,6 +137,8 @@ ev_page_accessible_initialize_children (EvPageAccessible *self)
                        child = atk_hyperlink_get_object (atk_link, 0);
                } else if (images && ev_mapping_list_find (images, mapping->data))
                        child = ATK_OBJECT (ev_image_accessible_new (self, EV_IMAGE (mapping->data), 
&mapping->area));
+               else if (fields && ev_mapping_list_find (fields, mapping->data))
+                       child = ATK_OBJECT (ev_form_field_accessible_new (self, EV_FORM_FIELD 
(mapping->data), &mapping->area));
 
                if (child)
                        g_ptr_array_add (self->priv->children, child);
diff --git a/libview/ev-view-private.h b/libview/ev-view-private.h
index e2d5640..0ff7412 100644
--- a/libview/ev-view-private.h
+++ b/libview/ev-view-private.h
@@ -289,6 +289,8 @@ void _ev_view_set_selection   (EvView   *view,
 void _ev_view_set_focused_element (EvView *view,
                                   EvMapping *element_mapping,
                                   gint page);
+void _ev_view_focus_form_field    (EvView      *view,
+                                  EvFormField *field);
 
 #endif  /* __EV_VIEW_PRIVATE_H__ */
 
diff --git a/libview/ev-view.c b/libview/ev-view.c
index 24f474b..d33c4a1 100644
--- a/libview/ev-view.c
+++ b/libview/ev-view.c
@@ -2624,8 +2624,8 @@ ev_view_form_field_choice_create_widget (EvView      *view,
        return choice;
 }
 
-static void
-ev_view_focus_form_field (EvView      *view,
+void
+_ev_view_focus_form_field (EvView      *view,
                          EvFormField *field)
 {
        GtkWidget     *field_widget = NULL;
@@ -2670,7 +2670,7 @@ ev_view_handle_form_field (EvView      *view,
        if (field->is_read_only)
                return;
 
-       ev_view_focus_form_field (view, field);
+       _ev_view_focus_form_field (view, field);
 
        if (field->activation_link)
                ev_view_handle_link (view, field->activation_link);
@@ -4304,7 +4304,7 @@ ev_view_set_focused_element_at_location (EvView *view,
 
        if ((field = ev_view_get_form_field_at_location (view, x, y))) {
                ev_view_remove_all (view);
-               ev_view_focus_form_field (view, field);
+               _ev_view_focus_form_field (view, field);
                return;
        }
 


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]