Index: backend/pdf/ev-poppler.cc =================================================================== --- backend/pdf/ev-poppler.cc (revision 2339) +++ backend/pdf/ev-poppler.cc (working copy) @@ -104,7 +104,52 @@ static void pdf_document_search_free (PdfDocumentSearch *search); static void pdf_print_context_free (PdfPrintContext *ctx); +/* Forms */ +static void pdf_document_get_crop_box (EvDocument *document, + int page, + EvRectangle *rect); +static GList *pdf_document_get_form_field_mapping (EvDocument *document, + int page); +static gchar* pdf_document_get_text_field_content (EvDocument *document, + unsigned field_id, + int *length); +static void pdf_document_set_text_field_content (EvDocument *document, + unsigned field_id, + gchar* content, + int length); +static void pdf_document_set_form_field_button_state (EvDocument *document, + unsigned field_id, + gboolean state); +static gboolean pdf_document_get_form_field_button_state (EvDocument *document, + unsigned field_id); +static gchar* pdf_document_get_form_field_choice_content (EvDocument *document, + unsigned field_id, + int index, + int *length); +static int pdf_document_get_form_field_choice_count (EvDocument *document, + unsigned field_id); +static gboolean pdf_document_form_field_choice_is_selected (EvDocument* document, + unsigned field_id, + int index); +static void pdf_document_form_field_choice_select (EvDocument* document, + unsigned field_id, + int index); +static void pdf_document_form_field_choice_toggle (EvDocument* document, + unsigned field_id, + int index); +static void pdf_document_form_field_choice_deselect_all (EvDocument* document, + unsigned field_id); +static void pdf_document_set_form_field_choice_edit (EvDocument *document, + unsigned field_id, + char* content, + int length); +static gchar * pdf_document_get_form_field_choice_edit (EvDocument *document, + unsigned field_id, + int *length); + + + G_DEFINE_TYPE_WITH_CODE (PdfDocument, pdf_document, G_TYPE_OBJECT, { G_IMPLEMENT_INTERFACE (EV_TYPE_DOCUMENT, @@ -673,6 +718,21 @@ iface->get_text = pdf_document_get_text; iface->can_get_text = pdf_document_can_get_text; iface->get_info = pdf_document_get_info; + /* Forms */ + iface->get_form_field_mapping = pdf_document_get_form_field_mapping; + iface->get_crop_box = pdf_document_get_crop_box; + iface->set_text_field_content = pdf_document_set_text_field_content; + iface->get_text_field_content = pdf_document_get_text_field_content; + iface->set_button_state = pdf_document_set_form_field_button_state; + iface->get_button_state = pdf_document_get_form_field_button_state; + iface->get_choice_field_content = pdf_document_get_form_field_choice_content; + iface->get_choice_field_count = pdf_document_get_form_field_choice_count; + iface->choice_field_is_selected = pdf_document_form_field_choice_is_selected; + iface->choice_field_select = pdf_document_form_field_choice_select; + iface->choice_field_toggle = pdf_document_form_field_choice_toggle; + iface->choice_field_deselect_all = pdf_document_form_field_choice_deselect_all; + iface->set_choice_field_edit = pdf_document_set_form_field_choice_edit; + iface->get_choice_field_edit = pdf_document_get_form_field_choice_edit; }; static void @@ -1713,3 +1773,191 @@ { return PDF_DOCUMENT (g_object_new (PDF_TYPE_DOCUMENT, NULL)); } + +/* Forms */ + +static void pdf_document_get_crop_box (EvDocument *document, + int page, + EvRectangle *rect) +{ + PdfDocument *pdf_document; + PopplerPage *poppler_page; + PopplerRectangle poppler_rect; + + pdf_document = PDF_DOCUMENT (document); + poppler_page = poppler_document_get_page (pdf_document->document, page); + poppler_page_get_crop_box (poppler_page, &poppler_rect); + rect->x1 = poppler_rect.x1; + rect->x2 = poppler_rect.x2; + rect->y1 = poppler_rect.y1; + rect->y2 = poppler_rect.y2; +} + +static void copy_form_poppler_evince (PopplerFormField *source, + EvFormField *dest, + double height, + EvRectangle crop_box) +{ + dest->x1 = source->area.x1 - crop_box.x1; + dest->x2 = source->area.x2 - crop_box.x1; + dest->y1 = height - source->area.y2 + crop_box.y1; + dest->y2 = height - source->area.y1 + crop_box.y1; + + dest->type = (EvFormFieldType)source->type; + dest->font_size = source->font_size; + dest->id = source->id; + + if (dest->type == EV_FORM_FIELD_TYPE_TEXT) { + dest->text.multiline = source->text.multiline; + dest->text.password = source->text.password; + dest->text.fileselect = source->text.fileselect; + dest->text.do_not_spell_check = source->text.do_not_spell_check; + dest->text.do_not_scroll = source->text.do_not_scroll; + dest->text.comb = source->text.comb; + dest->text.rich_text = source->text.rich_text; + } else if (dest->type == EV_FORM_FIELD_TYPE_BUTTON) { + + } else if (dest->type == EV_FORM_FIELD_TYPE_CHOICE) { + dest->choice.combo = source->choice.combo; + dest->choice.edit = source->choice.edit; + dest->choice.multi_select = source->choice.multi_select; + dest->choice.do_not_spell_check = source->choice.do_not_spell_check; + dest->choice.commit_on_sel_change = source->choice.commit_on_sel_change; + } +} + +static GList *pdf_document_get_form_field_mapping (EvDocument *document, + int page) +{ + PdfDocument *pdf_document; + PopplerPage *poppler_page; + GList *retval = NULL; + GList *fields; + GList *list; + double height; + EvRectangle crop_box; + + pdf_document = PDF_DOCUMENT (document); + poppler_page = poppler_document_get_page (pdf_document->document, + page); + fields = poppler_page_get_form_fields (poppler_page); + poppler_page_get_size (poppler_page, NULL, &height); + + pdf_document_get_crop_box(document, page, &crop_box); + + for (list = fields; list; list = list->next) { + PopplerFormField *field; + EvFormField *field_mapping; + double rect[4]; + + field = (PopplerFormField *)list->data; + + field_mapping = g_new (EvFormField, 1); + + copy_form_poppler_evince(field, field_mapping, height, crop_box); + + retval = g_list_prepend(retval, field_mapping); + } + poppler_page_free_form_fields(fields); + g_object_unref (poppler_page); + + return g_list_reverse(retval); + +} + +static gchar* pdf_document_get_text_field_content (EvDocument *document, + unsigned field_id, + int *length) +{ + PdfDocument *pdf_document = PDF_DOCUMENT(document); + return poppler_document_get_form_field_text_content(pdf_document->document, field_id, length); +} + +static void pdf_document_set_text_field_content (EvDocument *document, + unsigned field_id, + gchar* content, + int length) +{ + PdfDocument *pdf_document = PDF_DOCUMENT(document); + poppler_document_set_form_field_text_content(pdf_document->document, field_id, content, length); +} + +static void pdf_document_set_form_field_button_state (EvDocument *document, + unsigned field_id, + gboolean state) +{ + PdfDocument *pdf_document = PDF_DOCUMENT(document); + poppler_document_set_form_field_button_state(pdf_document->document, field_id, state); +} + +static gboolean pdf_document_get_form_field_button_state (EvDocument *document, + unsigned field_id) +{ + PdfDocument *pdf_document = PDF_DOCUMENT(document); + return poppler_document_get_form_field_button_state(pdf_document->document, field_id); +} + +static gchar* pdf_document_get_form_field_choice_content (EvDocument *document, + unsigned field_id, + int index, + int *length) +{ + PdfDocument *pdf_document = PDF_DOCUMENT(document); + return poppler_document_get_form_field_choice_content(pdf_document->document, field_id, index, length); +} + +static int pdf_document_get_form_field_choice_count (EvDocument *document, + unsigned field_id) +{ + PdfDocument *pdf_document = PDF_DOCUMENT(document); + return poppler_document_get_form_field_choice_num_choices(pdf_document->document, field_id); +} + +static gboolean pdf_document_form_field_choice_is_selected (EvDocument* document, + unsigned field_id, + int index) +{ + PdfDocument *pdf_document = PDF_DOCUMENT(document); + return poppler_document_form_field_choice_is_selected (pdf_document->document, field_id, index); +} + +static void pdf_document_form_field_choice_select (EvDocument* document, + unsigned field_id, + int index) +{ + PdfDocument *pdf_document = PDF_DOCUMENT(document); + return poppler_document_form_field_choice_select (pdf_document->document, field_id, index); +} + +static void pdf_document_form_field_choice_toggle (EvDocument* document, + unsigned field_id, + int index) +{ + PdfDocument *pdf_document = PDF_DOCUMENT(document); + return poppler_document_form_field_choice_toggle (pdf_document->document, field_id, index); +} + +static void pdf_document_form_field_choice_deselect_all (EvDocument* document, + unsigned field_id) +{ + PdfDocument *pdf_document = PDF_DOCUMENT(document); + return poppler_document_form_field_choice_deselect_all (pdf_document->document, field_id); +} + +static void pdf_document_set_form_field_choice_edit (EvDocument *document, + unsigned field_id, + char* content, + int length) +{ + PdfDocument *pdf_document = PDF_DOCUMENT(document); + return poppler_document_set_form_field_choice_edit(pdf_document->document, field_id, content, length); +} + +static gchar * pdf_document_get_form_field_choice_edit (EvDocument *document, + unsigned field_id, + int *length) +{ + PdfDocument *pdf_document = PDF_DOCUMENT(document); + return poppler_document_get_form_field_choice_edit(pdf_document->document, field_id, length); +} + Index: configure.ac =================================================================== --- configure.ac (revision 2339) +++ configure.ac (working copy) @@ -59,6 +59,9 @@ PKG_CHECK_MODULES(FRONTEND_CORE, gtk+-2.0 >= $GTK_REQUIRED libgnomeui-2.0 >= $LIBGNOMEUI_REQUIRED gnome-icon-theme >= $GNOME_ICON_THEME_REQUIRED libglade-2.0) PKG_CHECK_MODULES(SHELL_CORE, gtk+-2.0 >= $GTK_REQUIRED libgnomeui-2.0 >= $LIBGNOMEUI_REQUIRED gnome-vfs-2.0 libglade-2.0 gconf-2.0 gnome-keyring-1 >= $KEYRING_REQUIRED) +SHELL_CORE_CFLAGS="$SHELL_CORE_CFLAGS" +SHELL_CORE_LIBS="$SHELL_CORE_LIBS" + BACKEND_CFLAGS="$BACKEND_CFLAGS -DGDK_MULTIHEAD_SAFE -DGTK_MULTIHEAD_SAFE" AC_SUBST(BACKEND_CFLAGS) Index: libdocument/ev-form-field.h =================================================================== --- libdocument/ev-form-field.h (revision 0) +++ libdocument/ev-form-field.h (revision 0) @@ -0,0 +1,91 @@ +/* -*- 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) 2006 Julien Rebetez + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef EV_FORM_FIELD_H +#define EV_FORM_FIELD_H + +#include + +/*MUST be in the same order as poppler/glib/poppler.h PopplerFormFieldType !*/ +typedef enum +{ + EV_FORM_FIELD_TYPE_BUTTON, + EV_FORM_FIELD_TYPE_TEXT, + EV_FORM_FIELD_TYPE_CHOICE, + EV_FORM_FIELD_TYPE_SIGNATURE, + + EV_FORM_FIELD_TYPE_BUTTON_CHECK, + EV_FORM_FIELD_TYPE_BUTTON_PUSH, + EV_FORM_FIELD_TYPE_BUTTON_RADIO +} EvFormFieldType; + + +struct _EvFormTextField +{ + //flags + char multiline:1; + char password:1; + char fileselect:1; + char do_not_spell_check:1; + char do_not_scroll:1; + char comb:1; + char rich_text:1; +}; + +struct _EvFormButtonField +{ +}; + +struct _EvFormChoiceField +{ + char combo:1; + char edit:1; + char multi_select:1; + char do_not_spell_check:1; + char commit_on_sel_change:1; +}; + +typedef struct _EvFormField EvFormField; +struct _EvFormField +{ + EvFormFieldType type; + int id; + gdouble x1; + gdouble y1; + gdouble x2; + gdouble y2; + double font_size; + union { + struct _EvFormTextField text; + struct _EvFormButtonField button; + struct _EvFormChoiceField choice; + }; +}; + +EvFormField *ev_form_field_new (); +void ev_form_field_mapping_free (GList *form_field_mapping); +EvFormField *ev_form_field_mapping_find (GList *form_field_mapping, + gdouble x, + gdouble y); +EvFormField *ev_form_field_mapping_find_by_id (GList *form_field_mapping, + int id); + +#endif /* !EV_FORM_H */ + Index: libdocument/ev-document.c =================================================================== --- libdocument/ev-document.c (revision 2339) +++ libdocument/ev-document.c (working copy) @@ -279,3 +279,161 @@ (ABS (a->x2 - b->x2) < EPSILON) && (ABS (a->y2 - b->y2) < EPSILON)); } + +/* Forms */ + +GList* +ev_document_get_form_field_mapping (EvDocument *document, + int page) +{ + EvDocumentIface *iface = EV_DOCUMENT_GET_IFACE (document); + GList *retval; + + LOG ("ev_document_get_form_fields"); + if (iface->get_form_field_mapping == NULL) + return NULL; + + retval = iface->get_form_field_mapping (document, page); + return retval; +} + +gboolean +ev_document_get_crop_box (EvDocument *document, + int page, + EvRectangle *rect) +{ + EvDocumentIface *iface = EV_DOCUMENT_GET_IFACE (document); + LOG("ev_document_get_crop_box"); + if (iface->get_crop_box == NULL) + return FALSE; + iface->get_crop_box(document, page, rect); + return TRUE; +} + +gchar * +ev_document_get_form_field_text_content (EvDocument *document, int field_id, int *length) +{ + EvDocumentIface *iface = EV_DOCUMENT_GET_IFACE(document); + gchar* retval; + LOG("ev_document_get_form_field_text_content"); + if (iface->get_text_field_content == NULL) + return NULL; + retval = iface->get_text_field_content(document, field_id, length); + return retval; +} + +void +ev_document_set_form_field_text_content (EvDocument *document, int field_id, gchar* content, int length) +{ + EvDocumentIface *iface = EV_DOCUMENT_GET_IFACE(document); + LOG("ev_document_set_form_field_text_content"); + if (iface->set_text_field_content == NULL) + return; + iface->set_text_field_content(document, field_id, content, length); +} + +gchar * +ev_document_get_form_field_choice_content (EvDocument *document, int field_id, int index, int *length) +{ + EvDocumentIface *iface = EV_DOCUMENT_GET_IFACE(document); + LOG("ev_document_get_form_field_choice_content"); + if (iface->get_choice_field_content == NULL) + return NULL; + return iface->get_choice_field_content(document, field_id, index, length); +} + +gboolean +ev_document_form_field_choice_is_selected (EvDocument* document, unsigned field_id, int index) +{ + EvDocumentIface *iface = EV_DOCUMENT_GET_IFACE(document); + LOG("ev_document_form_field_choice_is_selected"); + if (iface->choice_field_is_selected == NULL) + return FALSE; + return iface->choice_field_is_selected(document, field_id, index); +} + +void +ev_document_form_field_choice_select (EvDocument* document, unsigned field_id, int index) +{ + EvDocumentIface *iface = EV_DOCUMENT_GET_IFACE(document); + LOG("ev_document_form_field_choice_select"); + if (iface->choice_field_select == NULL) + return; + return iface->choice_field_select(document, field_id, index); +} + +void +ev_document_form_field_choice_toggle (EvDocument* document, unsigned field_id, int index) +{ + EvDocumentIface *iface = EV_DOCUMENT_GET_IFACE(document); + LOG("ev_document_form_field_choice_toggle"); + if (iface->choice_field_toggle == NULL) + return; + return iface->choice_field_toggle(document, field_id, index); +} + +void +ev_document_form_field_choice_deselect_all (EvDocument* document, unsigned field_id) +{ + EvDocumentIface *iface = EV_DOCUMENT_GET_IFACE(document); + LOG("ev_document_form_field_choice_deselect_all"); + if (iface->choice_field_is_selected == NULL) + return; + return iface->choice_field_deselect_all(document, field_id); +} + +int ev_document_get_form_field_choice_count (EvDocument *document, int field_id) +{ + EvDocumentIface *iface = EV_DOCUMENT_GET_IFACE(document); + LOG("ev_document_get_form_field_button_state"); + if (iface->get_choice_field_count == NULL) + return 0; + return iface->get_choice_field_count(document, field_id); +} + +void +ev_document_set_form_field_button_state (EvDocument *document, int field_id, gboolean state) +{ + EvDocumentIface *iface = EV_DOCUMENT_GET_IFACE(document); + LOG("ev_document_set_form_field_button_state"); + if (iface->set_button_state == NULL) + return; + iface->set_button_state(document, field_id, state); +} + +gboolean +ev_document_get_form_field_button_state (EvDocument *document, int field_id) +{ + EvDocumentIface *iface = EV_DOCUMENT_GET_IFACE(document); + LOG("ev_document_get_form_field_button_state"); + if (iface->get_button_state == NULL) + return FALSE; + iface->get_button_state(document, field_id); +} + +void +ev_document_set_form_field_choice_edit (EvDocument *document, + unsigned field_id, + char* content, + int length) +{ + EvDocumentIface *iface = EV_DOCUMENT_GET_IFACE(document); + LOG("ev_document_set_form_field_choice_field_edit"); + if (iface->set_choice_field_edit == NULL) + return; + iface->set_choice_field_edit(document, field_id, content, length); +} + +gchar * +ev_document_get_form_field_choice_edit (EvDocument *document, + unsigned field_id, + int *length) +{ + EvDocumentIface *iface = EV_DOCUMENT_GET_IFACE(document); + LOG("ev_document_get_form_field_choice_field_edit"); + if (iface->get_choice_field_edit == NULL) + return; + return iface->get_choice_field_edit(document, field_id, length); +} + + Index: libdocument/Makefile.am =================================================================== --- libdocument/Makefile.am (revision 2339) +++ libdocument/Makefile.am (working copy) @@ -48,6 +48,8 @@ ev-document-info.h \ ev-document-transition.h \ ev-document-transition.c \ + ev-form-field.h \ + ev-form-field.c \ ev-file-exporter.c \ ev-file-exporter.h \ ev-file-helpers.c \ Index: libdocument/ev-document.h =================================================================== --- libdocument/ev-document.h (revision 2339) +++ libdocument/ev-document.h (working copy) @@ -27,6 +27,7 @@ #include #include "ev-link.h" +#include "ev-form-field.h" #include "ev-document-info.h" #include "ev-render-context.h" @@ -93,6 +94,48 @@ GdkPixbuf * (* render_pixbuf) (EvDocument *document, EvRenderContext *rc); EvDocumentInfo * (* get_info) (EvDocument *document); + /* Forms */ + void (* get_crop_box) (EvDocument *document, + int page, + EvRectangle *rect); + GList * (* get_form_field_mapping) (EvDocument *document, + int page); + gchar * (* get_text_field_content) (EvDocument *document, + unsigned field_id, + int *length); + void (* set_text_field_content) (EvDocument *document, + unsigned field_id, + gchar* content, + int length); + gchar * (* get_choice_field_content) (EvDocument *document, + unsigned field_id, + int index, + int *length); + int (* get_choice_field_count) (EvDocument *document, + unsigned field_id); + gboolean (* choice_field_is_selected) (EvDocument* document, + unsigned field_id, + int index); + void (* choice_field_select) (EvDocument* document, + unsigned field_id, + int index); + void (* choice_field_toggle) (EvDocument* document, + unsigned field_id, + int index); + void (* choice_field_deselect_all) (EvDocument* document, + unsigned field_id); + void (* set_button_state) (EvDocument *document, + unsigned field_id, + gboolean state); + gboolean (* get_button_state) (EvDocument *document, + unsigned field_id); + void (* set_choice_field_edit) (EvDocument *document, + unsigned field_id, + char* content, + int length); + gchar * (* get_choice_field_edit) (EvDocument *document, + unsigned field_id, + int *length); }; GType ev_document_get_type (void); @@ -133,8 +176,53 @@ gint ev_rect_cmp (EvRectangle *a, EvRectangle *b); +/* Forms */ +GList *ev_document_get_form_field_mapping (EvDocument *document, + int page); +gchar *ev_document_get_form_field_text_content (EvDocument *document, + int field_id, + int *length); +void ev_document_set_form_field_text_content (EvDocument *document, + int field_id, + gchar* content, + int length); +void ev_document_set_form_field_button_state (EvDocument *document, + int field_id, + gboolean state); +gboolean ev_document_get_form_field_button_state (EvDocument *document, + int field_id); + +gboolean ev_document_get_crop_box (EvDocument *document, + int page, + EvRectangle *rect); + +gchar * ev_document_get_form_field_choice_content (EvDocument *document, + int field_id, + int index, + int *length); +int ev_document_get_form_field_choice_count (EvDocument *document, + int field_id); +gboolean ev_document_form_field_choice_is_selected (EvDocument* document, + unsigned field_id, + int index); +void ev_document_form_field_choice_select (EvDocument* document, + unsigned field_id, + int index); +void ev_document_form_field_choice_toggle (EvDocument* document, + unsigned field_id, + int index); +void ev_document_form_field_choice_deselect_all (EvDocument* document, + unsigned field_id); +void ev_document_set_form_field_choice_edit (EvDocument *document, + unsigned field_id, + char* content, + int length); +gchar * ev_document_get_form_field_choice_edit (EvDocument *document, + unsigned field_id, + int *length); + G_END_DECLS #endif Index: libdocument/ev-form-field.c =================================================================== --- libdocument/ev-form-field.c (revision 0) +++ libdocument/ev-form-field.c (revision 0) @@ -0,0 +1,79 @@ +/* -*- 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) 2006 Julien Rebetez + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "ev-form-field.h" + +EvFormField * +ev_form_field_new () +{ + EvFormField *field = g_new (EvFormField, 1); + field->id = -1; +} + +void +ev_form_field_mapping_free (GList *form_field_mapping) +{ + if (form_field_mapping == NULL) + return; + + g_list_foreach (form_field_mapping, (GFunc) (g_free), NULL); + g_list_free (form_field_mapping); +} + + +EvFormField * +ev_form_field_mapping_find (GList *form_field_mapping, + gdouble x, + gdouble y) +{ + GList *list; + + for (list = form_field_mapping; list; list = list->next) { + EvFormField *field = list->data; + + if ((x >= field->x1) && + (y >= field->y1) && + (x <= field->x2) && + (y <= field->y2)) { + return field; + } + } + return NULL; +} + +EvFormField * +ev_form_field_mapping_find_by_id (GList *form_field_mapping, + int id) +{ + GList *list; + for (list = form_field_mapping; list; list = list->next) { + EvFormField *field = list->data; + + if (id == field->id) + return field; + } + return NULL; +} + + Index: shell/ev-pixbuf-cache.c =================================================================== --- shell/ev-pixbuf-cache.c (revision 2339) +++ shell/ev-pixbuf-cache.c (working copy) @@ -15,6 +15,7 @@ GList *link_mapping; GList *image_mapping; GdkRegion *text_mapping; + GList *form_field_mapping; /* Selection data. * Selection_points are the coordinates encapsulated in selection. @@ -151,6 +152,10 @@ g_object_unref (G_OBJECT (job_info->pixbuf)); job_info->pixbuf = NULL; } + if (job_info->form_field_mapping) { + ev_form_field_mapping_free(job_info->form_field_mapping); + job_info->form_field_mapping = NULL; + } if (job_info->link_mapping) { ev_link_mapping_free (job_info->link_mapping); job_info->link_mapping = NULL; @@ -316,6 +321,7 @@ } *target_page = *job_info; + job_info->form_field_mapping = NULL; job_info->job = NULL; job_info->pixbuf = NULL; job_info->link_mapping = NULL; @@ -417,6 +423,11 @@ } job_info->rc = g_object_ref (job_render->rc); + if (job_render->include_form) { + if (job_info->form_field_mapping) + ev_form_field_mapping_free (job_info->form_field_mapping); + job_info->form_field_mapping = job_render->form_field_mapping; + } if (job_render->include_links) { if (job_info->link_mapping) ev_link_mapping_free (job_info->link_mapping); @@ -536,6 +547,7 @@ gfloat scale, EvJobPriority priority) { + gboolean include_form = FALSE; gboolean include_links = FALSE; gboolean include_text = FALSE; gboolean include_selection = FALSE; @@ -564,6 +576,10 @@ } /* Figure out what else we need for this job */ + /* FIXME: if we don't set include_form to TRUE, sometimes the render job's form_field_mapping is NULL + although the page has some fields + if (job_info->form_field_mapping == NULL) */ + include_form = TRUE; if (job_info->link_mapping == NULL) include_links = TRUE; if (job_info->image_mapping == NULL) @@ -583,6 +599,7 @@ width, height, &(job_info->target_points), text, base, + include_form, include_links, include_images, include_text, @@ -1088,3 +1105,103 @@ return retval; } +static void add_job (EvPixbufCache *pixbuf_cache, + CacheJobInfo *job_info, + EvPageCache *page_cache, + gint page, + gint rotation, + gfloat scale, + EvJobPriority priority, + int width, + int height) +{ + gboolean include_form = FALSE; + gboolean include_links = FALSE; + gboolean include_text = FALSE; + gboolean include_selection = FALSE; + gboolean include_images = TRUE; + GdkColor *text, *base; + + + if (job_info->rc == NULL) { + job_info->rc = ev_render_context_new (rotation, page, scale); + } else { + ev_render_context_set_rotation (job_info->rc, rotation); + ev_render_context_set_page (job_info->rc, page); + ev_render_context_set_scale (job_info->rc, scale); + } + + /* Figure out what else we need for this job */ + /* FIXME: if we don't set include_form to TRUE, sometimes the render job's form_field_mapping is NULL + although the page has some fields + if (job_info->form_field_mappings == NULL)*/ + include_form = TRUE; + if (job_info->link_mapping == NULL) + include_links = TRUE; + if (job_info->image_mapping == NULL) + include_images = TRUE; + if (job_info->text_mapping == NULL) + include_text = TRUE; + if (new_selection_pixbuf_needed (pixbuf_cache, job_info, page, scale)) { + include_selection = TRUE; + } + + gtk_widget_ensure_style (pixbuf_cache->view); + + get_selection_colors (pixbuf_cache->view, &text, &base); + + job_info->job = ev_job_render_new (pixbuf_cache->document, + job_info->rc, + width, height, + &(job_info->target_points), + text, base, + include_form, + include_links, + include_images, + include_text, + include_selection); + ev_job_queue_add_job (job_info->job, priority); + g_signal_connect (job_info->job, "finished", G_CALLBACK (job_finished_cb), pixbuf_cache); + +} + +void +ev_pixbuf_cache_reload_page (EvPixbufCache *pixbuf_cache, + gint page, + gint rotation, + gfloat scale) +{ + CacheJobInfo *job_info; + EvPageCache *page_cache; + int width, height; + + if(page < pixbuf_cache->start_page || page > pixbuf_cache->end_page) + return; + page_cache = ev_page_cache_get (pixbuf_cache->document); + ev_page_cache_get_size (page_cache, page, rotation, scale, &width, &height); + job_info = pixbuf_cache->job_list + (page - pixbuf_cache->start_page); + + //dispose_cache_job_info (job_info, pixbuf_cache); + + add_job(pixbuf_cache, job_info, page_cache, page, rotation, scale, EV_JOB_PRIORITY_HIGH, width, height); + + +} + +GList * +ev_pixbuf_cache_get_form_field_mapping (EvPixbufCache *pixbuf_cache, + gint page) +{ + CacheJobInfo *job_info; + + job_info = find_job_cache (pixbuf_cache, page); + if(job_info == NULL) + return NULL; + + if(job_info->job && + EV_JOB(job_info->job)->finished) { + copy_job_to_job_info (EV_JOB_RENDER(job_info->job), job_info, pixbuf_cache); + } + return job_info->form_field_mapping; +} + Index: shell/ev-pixbuf-cache.h =================================================================== --- shell/ev-pixbuf-cache.h (revision 2339) +++ shell/ev-pixbuf-cache.h (working copy) @@ -65,9 +65,14 @@ gint page); GdkRegion *ev_pixbuf_cache_get_text_mapping (EvPixbufCache *pixbuf_cache, gint page); +GList *ev_pixbuf_cache_get_form_field_mapping (EvPixbufCache *pixbuf_cache, + gint page); void ev_pixbuf_cache_clear (EvPixbufCache *pixbuf_cache); void ev_pixbuf_cache_style_changed (EvPixbufCache *pixbuf_cache); - +void ev_pixbuf_cache_reload_page (EvPixbufCache *pixbuf_cache, + gint page, + gint rotation, + gfloat scale); /* Selection */ GdkPixbuf *ev_pixbuf_cache_get_selection_pixbuf (EvPixbufCache *pixbuf_cache, gint page, Index: shell/ev-view-private.h =================================================================== --- shell/ev-view-private.h (revision 2339) +++ shell/ev-view-private.h (working copy) @@ -42,6 +42,49 @@ GList *selections; } SelectionInfo; +/* Information for form fields/container */ +typedef enum { + VIEW_CHILD_LIST, + VIEW_CHILD_SINGLE, + VIEW_CHILD_EDIT_COMBO +} EvViewChildType; + +typedef struct { + // EvViewChild::widget is a scrolled_window containing the treeview + GtkWidget *tree; //the treeview + GtkListStore *store; + GtkTreeViewColumn *column; + GtkCellRenderer *renderer; +} EvViewChildList; + +typedef struct { + GtkListStore *store; +} EvViewChildEditCombo; + +typedef struct { + // empty +} EvViewChildSingle; + +typedef struct { + EvViewChildType type; + union { + EvViewChildList list; + EvViewChildSingle single; + EvViewChildEditCombo edit; + }; +} EvViewChildInfo; + +typedef struct { + GtkWidget *widget; + EvViewChildInfo *info; + gint x; + gint y; + EvPoint p[2]; + gint page; + int field_id; //id of the field represented by this child + gboolean committed; +} EvViewChild; + /* Information for handling images DND */ typedef struct { gboolean in_drag; @@ -73,7 +116,7 @@ } EvPresentationState; struct _EvView { - GtkWidget parent_instance; + GtkContainer parent_instance; EvDocument *document; @@ -149,10 +192,15 @@ /* Goto Popup */ GtkWidget *goto_window; GtkWidget *goto_entry; + + /* Container */ + gint current_width; + gint current_height; + GList *childs; }; struct _EvViewClass { - GtkWidgetClass parent_class; + GtkContainerClass parent_class; void (*set_scroll_adjustments) (EvView *view, GtkAdjustment *hadjustment, Index: shell/ev-jobs.c =================================================================== --- shell/ev-jobs.c (revision 2339) +++ shell/ev-jobs.c (working copy) @@ -264,6 +264,7 @@ EvRectangle *selection_points, GdkColor *text, GdkColor *base, + gboolean include_form, gboolean include_links, gboolean include_images, gboolean include_text, @@ -283,6 +284,7 @@ job->target_height = height; job->text = *text; job->base = *base; + job->include_form = include_form; job->include_links = include_links; job->include_images = include_images; job->include_text = include_text; @@ -326,6 +328,8 @@ ev_document_fc_mutex_lock (); job->pixbuf = ev_document_render_pixbuf (EV_JOB (job)->document, job->rc); + if (job->include_form) + job->form_field_mapping = ev_document_get_form_field_mapping(EV_JOB(job)->document, job->rc->page); if (job->include_links && EV_IS_DOCUMENT_LINKS (EV_JOB (job)->document)) job->link_mapping = ev_document_links_get_links (EV_DOCUMENT_LINKS (EV_JOB (job)->document), Index: shell/ev-jobs.h =================================================================== --- shell/ev-jobs.h (revision 2339) +++ shell/ev-jobs.h (working copy) @@ -126,6 +126,7 @@ GList *link_mapping; GdkRegion *text_mapping; GList *image_mapping; + GList *form_field_mapping; GdkPixbuf *selection; GdkRegion *selection_region; @@ -133,6 +134,7 @@ GdkColor base; GdkColor text; + gint include_form : 1; gint include_links : 1; gint include_text : 1; gint include_selection : 1; @@ -223,6 +225,7 @@ EvRectangle *selection_points, GdkColor *text, GdkColor *base, + gboolean include_form, gboolean include_links, gboolean include_images, gboolean include_text, Index: shell/ev-view.c =================================================================== --- shell/ev-view.c (revision 2339) +++ shell/ev-view.c (working copy) @@ -64,6 +64,12 @@ }; enum { + CHILD_PROP_0, + CHILD_PROP_X, + CHILD_PROP_Y +}; + +enum { SIGNAL_BINDING_ACTIVATED, SIGNAL_ZOOM_INVALID, SIGNAL_HANDLE_LINK, @@ -325,9 +331,62 @@ static void ev_view_presentation_transition_start (EvView *ev_view); static void ev_view_presentation_transition_stop (EvView *ev_view); +/*** Forms ***/ +static EvFormField* ev_view_get_form_field_at_location (EvView *view, + gdouble x, + gdouble y); +static void handle_form_field_over_xy (EvView *view, + gint x, + gint y); +static void form_field_widgets_resize (EvView *view); +static void handle_click_at_location (EvView *view, + gdouble x, + gdouble y); +static void render_form_field_content_for_page (EvView *view, gint page); -G_DEFINE_TYPE (EvView, ev_view, GTK_TYPE_WIDGET) +/*** Container ***/ +static void ev_view_map (GtkWidget *widget); +static void ev_view_add (GtkContainer *cont, + GtkWidget *widget); +static void ev_view_remove (GtkContainer *cont, + GtkWidget *widget); +static void ev_view_remove_all (GtkContainer *cont); +static void ev_view_put (EvView *view, + GtkWidget *widget, + EvViewChildInfo *info, + gint x, + gint y, + double x1, + double y1, + double x2, + double y2, + gint page, + gint id); +static void ev_view_forall (GtkContainer *cont, + gboolean include_internals, + GtkCallback callback, + gpointer callback_data); +static void ev_view_allocate_child (EvView *view, + EvViewChild *child); +static void ev_view_move_internal (EvView *view, + GtkWidget *widget, + gboolean change_x, + gint x, + gboolean change_y, + gint y); +static void ev_view_set_child_property (GtkContainer *cont, + GtkWidget *child, + guint property_id, + const GValue *value, + GParamSpec *pspec); +static void ev_view_get_child_property (GtkContainer *cont, + GtkWidget *child, + guint property_id, + GValue *value, + GParamSpec *pspec); +G_DEFINE_TYPE (EvView, ev_view, GTK_TYPE_CONTAINER) + static void scroll_to_current_page (EvView *view, GtkOrientation orientation) { @@ -1694,6 +1753,21 @@ return; } + if (view->childs) { + GList* elem; + for (elem = view->childs; elem != NULL; elem = g_list_next(elem)) { + GtkRequisition child_requisition; + gtk_widget_size_request (((EvViewChild*)elem->data)->widget, &child_requisition); + } + } + + if(!(requisition->width == view->current_width && requisition->height == view->current_height)) { + form_field_widgets_resize (view); + } + view->current_width = requisition->width; + view->current_height = requisition->height; + + if (view->continuous && view->dual_page) ev_view_size_request_continuous_dual_page (view, requisition); else if (view->continuous) @@ -1712,6 +1786,14 @@ GTK_WIDGET_CLASS (ev_view_parent_class)->size_allocate (widget, allocation); + if (view->childs) { + GList* elem; + for (elem = view->childs; elem != NULL; elem = g_list_next(elem)) { + ev_view_allocate_child(view, (EvViewChild*)elem->data); + } + + } + if (view->sizing_mode == EV_SIZING_FIT_WIDTH || view->sizing_mode == EV_SIZING_BEST_FIT) { @@ -1769,6 +1851,15 @@ gdk_window_set_background (widget->window, &widget->style->black); else gdk_window_set_background (widget->window, &widget->style->mid [GTK_STATE_NORMAL]); + + if (view->childs) { + GList* elem; + for (elem = view->childs; elem != NULL; elem = g_list_next(elem)) { + gtk_widget_set_parent_window(((EvViewChild*)elem->data)->widget, GTK_WIDGET(view)->window); + ev_view_allocate_child(view, (EvViewChild*)elem->data); + } + + } } static gboolean @@ -1939,6 +2030,7 @@ if (page_ready && EV_IS_DOCUMENT_FIND (view->document)) highlight_find_results (view, i); } + (* GTK_WIDGET_CLASS (ev_view_parent_class)->expose_event) (widget, event); return FALSE; } @@ -2020,6 +2112,7 @@ view->selection_info.start.x = event->x + view->scroll_x; view->selection_info.start.y = event->y + view->scroll_y; + handle_click_at_location (view, event->x, event->y); } return TRUE; case 2: @@ -2305,6 +2398,7 @@ } } else if (view->pressed_button <= 0) { handle_link_over_xy (view, x, y); + handle_form_field_over_xy (view, x, y); return TRUE; } @@ -3162,6 +3256,7 @@ { GObjectClass *object_class = G_OBJECT_CLASS (class); GtkObjectClass *gtk_object_class = GTK_OBJECT_CLASS (class); + GtkContainerClass *container_class = GTK_CONTAINER_CLASS (class); GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (class); GtkBindingSet *binding_set; @@ -3169,6 +3264,7 @@ object_class->set_property = ev_view_set_property; object_class->get_property = ev_view_get_property; + widget_class->map = ev_view_map; widget_class->expose_event = ev_view_expose_event; widget_class->button_press_event = ev_view_button_press_event; widget_class->motion_notify_event = ev_view_motion_notify_event; @@ -3190,9 +3286,34 @@ widget_class->popup_menu = ev_view_popup_menu; gtk_object_class->destroy = ev_view_destroy; + container_class->add = ev_view_add; + container_class->remove = ev_view_remove; + container_class->forall = ev_view_forall; + container_class->set_child_property = ev_view_set_child_property; + container_class->get_child_property = ev_view_get_child_property; + class->set_scroll_adjustments = ev_view_set_scroll_adjustments; class->binding_activated = ev_view_scroll; + gtk_container_class_install_child_property(container_class, + CHILD_PROP_X, + g_param_spec_int ("x", + "X position", + "X position of the child widget", + G_MININT, + G_MAXINT, + 0, + G_PARAM_READWRITE)); + gtk_container_class_install_child_property(container_class, + CHILD_PROP_Y, + g_param_spec_int ("y", + "Y position", + "Y position of the child widget", + G_MININT, + G_MAXINT, + 0, + G_PARAM_READWRITE)); + widget_class->set_scroll_adjustments_signal = g_signal_new ("set-scroll-adjustments", G_OBJECT_CLASS_TYPE (object_class), @@ -3362,6 +3483,9 @@ view->sizing_mode = EV_SIZING_FIT_WIDTH; view->pending_scroll = SCROLL_TO_KEEP_POSITION; view->jump_to_find_result = TRUE; + view->current_width = 0; + view->current_height = 0; + view->childs = NULL; gtk_drag_dest_set (GTK_WIDGET (view), GTK_DEST_DEFAULT_ALL, @@ -3395,6 +3519,21 @@ job_finished_cb (EvPixbufCache *pixbuf_cache, EvView *view) { + //clean fields widgets + if (view->childs) { + GList* elem; + for (elem = view->childs; elem!=NULL; elem = g_list_next(elem)) { + EvViewChild* child = (EvViewChild*)elem->data; + if (!child->committed) //keep uncommitted ones + continue; + + if (GTK_WIDGET_HAS_FOCUS(GTK_WIDGET(child->widget))) //keep focused ones + continue; + + gtk_widget_unparent(child->widget); + elem = view->childs = g_slist_delete_link(view->childs, elem); + } + } gtk_widget_queue_draw (GTK_WIDGET (view)); } @@ -3441,6 +3580,14 @@ view->scroll_y = 0; } + /* move the childs widgets (form fields) in order they follow the window scrolling */ + if (view->childs) { + GList* elem; + for(elem = view->childs; elem != NULL; elem = g_list_next(elem)) { + EvViewChild* child = (EvViewChild*)elem->data; + ev_view_move_internal(view, child->widget, TRUE, child->x + dx, TRUE, child->y + dy); + } + } if (view->pending_resize) gtk_widget_queue_draw (GTK_WIDGET (view)); @@ -4966,3 +5113,582 @@ } return etype; } + +/*** Forms ***/ +static EvFormField * +ev_view_get_form_field_at_location (EvView *view, + gdouble x, + gdouble y) +{ + gint page = -1; + gint x_offset = 0, y_offset = 0; + GList *form_field_mapping; + x += view->scroll_x; + y += view->scroll_y; + + find_page_at_location (view, x, y, &page, &x_offset, &y_offset); + + if (page == -1) + return NULL; + + form_field_mapping = ev_pixbuf_cache_get_form_field_mapping (view->pixbuf_cache, page); + + if (form_field_mapping) + return ev_form_field_mapping_find (form_field_mapping, x_offset / view->scale, y_offset / view->scale); + else { + return NULL; + } +} + +static void +commit_field_changes (EvView *view, int page) +{ + printf("commit_field_changes\n"); + GList *elem; + if (!view->childs) + return; + for(elem = view->childs; elem != NULL; elem = g_list_next(elem)) { + EvViewChild *child = elem->data; + if (GTK_IS_ENTRY(child->widget)) { + const gchar *txt = gtk_entry_get_text(GTK_ENTRY(child->widget)); + if (txt) { + gsize length; + gchar *tmp = g_convert (txt, + -1, + "UTF16BE", + "UTF8", + NULL, + &length, + NULL); + ev_document_set_form_field_text_content(view->document, child->field_id, tmp, length); + } else { + ev_document_set_form_field_text_content(view->document, child->field_id, NULL, 0); + } + } else if (GTK_IS_TEXT_VIEW(child->widget)) { + GtkTextIter start, end; + gchar *txt; + gtk_text_buffer_get_bounds (gtk_text_view_get_buffer (GTK_TEXT_VIEW(child->widget)), &start, &end); + txt = gtk_text_buffer_get_text (gtk_text_view_get_buffer (GTK_TEXT_VIEW(child->widget)), &start, &end, FALSE); + if (txt) { + gsize length; + gchar *tmp = g_convert (txt, + -1, + "UTF16BE", + "UTF8", + NULL, + &length, + NULL); + ev_document_set_form_field_text_content(view->document, child->field_id, tmp, length); + } else { + ev_document_set_form_field_text_content(view->document, child->field_id, NULL, 0); + } + g_free(txt); + + } else if (GTK_IS_COMBO_BOX(child->widget)) { + //editable combo box with user-entered text + if (GTK_IS_COMBO_BOX_ENTRY(child->widget) && gtk_combo_box_get_active_text(GTK_COMBO_BOX(child->widget)) != NULL) { + const gchar *txt = gtk_combo_box_get_active_text(GTK_COMBO_BOX(child->widget)); + gsize length; + gchar *tmp = g_convert (txt, + -1, + "UTF16BE", + "UTF8", + NULL, + &length, + NULL); + ev_document_set_form_field_choice_edit(view->document, child->field_id, tmp, length); + } else { + gchar *txt = gtk_combo_box_get_active_text(GTK_COMBO_BOX(child->widget)); + printf("ev-view.c: handle_click_at_location: choice selected %s %i\n", txt, gtk_combo_box_get_active(GTK_COMBO_BOX(child->widget))); + ev_document_form_field_choice_select(view->document, child->field_id, gtk_combo_box_get_active(GTK_COMBO_BOX(child->widget))); + } + } else if (GTK_IS_SCROLLED_WINDOW(child->widget) && child->info->type == VIEW_CHILD_LIST) { //list + GtkTreeSelection *sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(child->info->list.tree)); + + ev_document_form_field_choice_deselect_all(view->document, child->field_id); + + if (gtk_tree_selection_get_mode(sel) == GTK_SELECTION_MULTIPLE) { + GList* selected_rows = gtk_tree_selection_get_selected_rows(sel, NULL); + GList* elem; + for (elem = selected_rows; elem != NULL; elem = elem->next) { + GtkTreeIter iter; + GtkTreePath* path = (GtkTreePath*)elem->data; + gtk_tree_model_get_iter(child->info->list.store, &iter, path); + gint int_data; + gtk_tree_model_get(child->info->list.store, &iter, 1, &int_data, -1); + printf("list : %i\n", int_data); + ev_document_form_field_choice_select(view->document, child->field_id, int_data); + } + + g_list_foreach (selected_rows, gtk_tree_path_free, NULL); + g_list_free (selected_rows); + } else { //simple select + GtkTreeIter iter; + if(gtk_tree_selection_get_selected(sel, NULL, &iter)) { + gchar *str_data; + gint int_data; + gtk_tree_model_get(child->info->list.store, &iter, 0, &str_data, 1, &int_data, -1); + printf("list : %i\n", int_data); + ev_document_form_field_choice_select(view->document, child->field_id, int_data); + } + } + } + child->committed = TRUE; + } + ev_pixbuf_cache_reload_page(view->pixbuf_cache, page, view->rotation, view->scale); +} + +static void +handle_click_at_location (EvView *view, + gdouble x, + gdouble y) +{ + gint page = -1; + gint x_offset = 0, y_offset = 0; + GList *form_field_mapping; + EvFormField *new_field; + EvViewChildInfo *info; + GtkWidget *wid = NULL; + EvPoint p[2]; + GdkPoint d[2]; + gint v[4]; + gchar *content; + gboolean current_state; + + + x += view->scroll_x; + y += view->scroll_y; + + find_page_at_location (view, x, y, &page, &x_offset, &y_offset); + + if (page == -1) + return; + + form_field_mapping = ev_pixbuf_cache_get_form_field_mapping (view->pixbuf_cache, page); + + if (!form_field_mapping) + return; + + commit_field_changes(view, page); + + new_field = ev_form_field_mapping_find (form_field_mapping, x_offset/view->scale, y_offset/view->scale); + + if (!new_field) { + return; + } + + info = g_new(EvViewChildInfo, 1); + info->type = VIEW_CHILD_SINGLE; + + p[0].x = new_field->x1; + p[0].y = new_field->y1; + p[1].x = new_field->x2; + p[1].y = new_field->y2; + + doc_point_to_view_point (view, page, &p[0], &d[0]); + doc_point_to_view_point (view, page, &p[1], &d[1]); + + v[0] = d[0].x - view->scroll_x; v[1] = d[0].y - view->scroll_y; + v[2] = d[1].x - view->scroll_x; v[3] = d[1].y - view->scroll_y; + + //TODO: delete old field + switch (new_field->type) { + case EV_FORM_FIELD_TYPE_BUTTON: + /*wid = gtk_button_new_with_label("Button");*/ + printf("button clicked\n"); + current_state = ev_document_get_form_field_button_state(view->document, new_field->id); + printf("old state: %i, new state: %i\n", current_state, !current_state); + ev_document_set_form_field_button_state(view->document, new_field->id, !current_state); + + //g_array_append_val(view->pendingFormFields,new_field->id); + //ev_pixbuf_cache_reload_page(view->pixbuf_cache, page, view->rotation, view->scale); + gtk_widget_queue_draw(GTK_WIDGET(view)); + return; + //break; + case EV_FORM_FIELD_TYPE_TEXT: + { + int txt_length; + gchar *txt = ev_document_get_form_field_text_content(view->document, new_field->id, &txt_length); + if (txt) { + content = g_convert(txt, + txt_length, + "UTF8", + "UTF16BE", + NULL, + NULL, + NULL); + } else { + content = NULL; + } + + if (new_field->text.multiline) { //multiline entry + GtkTextBuffer *buffer; + wid = gtk_text_view_new (); + buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(wid)); + if (content) + gtk_text_buffer_set_text(buffer, content, -1); + + } else { + wid = gtk_entry_new(); + if (content) + gtk_entry_set_text(GTK_ENTRY(wid), content); + gtk_entry_set_has_frame(GTK_ENTRY(wid), FALSE); + } + + break; + } + case EV_FORM_FIELD_TYPE_CHOICE: + { + if (!new_field->choice.combo) { //List + GtkTreeIter iter; + + int i; + int count = ev_document_get_form_field_choice_count(view->document, new_field->id); + + info->type = VIEW_CHILD_LIST; + info->list.store = gtk_list_store_new(2,G_TYPE_STRING, G_TYPE_INT); + + info->list.tree = gtk_tree_view_new_with_model (GTK_TREE_MODEL(info->list.store)); + + info->list.renderer = gtk_cell_renderer_text_new(); + info->list.column = gtk_tree_view_column_new_with_attributes("choix", info->list.renderer, "text", 0, NULL); + + gtk_tree_view_append_column(GTK_TREE_VIEW(info->list.tree), info->list.column); + gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(info->list.tree), FALSE); + + wid = gtk_scrolled_window_new(NULL, NULL); + gtk_container_add(GTK_CONTAINER(wid), info->list.tree); + gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(wid), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); + + for(i=0; idocument, new_field->id, i, &txt_length); + if (txt) { + content = g_convert(txt, + txt_length, + "UTF8", + "UTF16BE", + NULL, + NULL, + NULL); + } else { + content = NULL; + } + if (content) { + gtk_list_store_append(info->list.store, &iter); + gtk_list_store_set (info->list.store, &iter, 0, content, 1, i, -1); + } + } + + if (new_field->choice.multi_select) { //allows multiple selections + gtk_tree_selection_set_mode(gtk_tree_view_get_selection(GTK_TREE_VIEW(info->list.tree)), GTK_SELECTION_MULTIPLE); + } + } else { + if (new_field->choice.edit) { // ComboBoxEntry + GtkTreeIter iter; + int i; + int txt_length; + int count = ev_document_get_form_field_choice_count(view->document, new_field->id); + + info->type = VIEW_CHILD_EDIT_COMBO; + info->edit.store = gtk_list_store_new(2, G_TYPE_STRING, G_TYPE_INT); + + wid = gtk_combo_box_entry_new_with_model(GTK_TREE_MODEL(info->edit.store), 0); + for (i=0; idocument, new_field->id, i, &txt_length); + if (txt) { + content = g_convert(txt, + txt_length, + "UTF8", + "UTF16BE", + NULL, + NULL, + NULL); + } else { + content = NULL; + } + if (content) { + gtk_list_store_append(info->edit.store, &iter); + gtk_list_store_set (info->edit.store, &iter, 0, content, 1, i, -1); + } + + } + //this combo has user-entered text + if (ev_document_get_form_field_choice_edit(view->document, new_field->id, &txt_length) != NULL) { + int txt_length; + gchar *txt = ev_document_get_form_field_choice_edit(view->document, new_field->id, &txt_length); + if (txt) { + content = g_convert(txt, + txt_length, + "UTF8", + "UTF16BE", + NULL, + NULL, + NULL); + gtk_entry_set_text(GTK_ENTRY(gtk_bin_get_child(GTK_BIN(wid))), content); + } + + } + } else { //Standard ComboBox + int i; + int count = ev_document_get_form_field_choice_count(view->document, new_field->id); + wid = gtk_combo_box_new_text(); + for(i=0; idocument, new_field->id, i, &txt_length); + if (txt) { + content = g_convert(txt, + txt_length, + "UTF8", + "UTF16BE", + NULL, + NULL, + NULL); + } else { + content = NULL; + } + if (content) + gtk_combo_box_append_text(GTK_COMBO_BOX(wid), content); + if (ev_document_form_field_choice_is_selected(view->document, new_field->id, i)) { + gtk_combo_box_set_active(GTK_COMBO_BOX(wid), i); + } + } + //gtk_combo_box_set_active(GTK_COMBO_BOX(wid), ev_document_get_form_field_choice_selected(view->document, new_field->id)); + g_object_set(G_OBJECT(wid), "has-frame", FALSE, NULL); + //FIXME: doesn't work + //gtk_combo_box_popup(GTK_COMBO_BOX(wid)); + } + } + break; + } + case EV_FORM_FIELD_TYPE_SIGNATURE: + wid = gtk_label_new ("signature"); + break; + default: + g_warning("Unknow field type %i, please fill a bug report with a test case.", new_field->type); + break; + } + gtk_widget_set_size_request(wid, v[2]-v[0], v[3]-v[1]); + ev_view_put(view, wid, info, v[0],v[1],p[0].x,p[0].y,p[1].x,p[1].y,page, new_field->id); + gtk_widget_show_all(wid); + gtk_widget_grab_focus(wid); +} + +static void +handle_form_field_over_xy (EvView *view, gint x, gint y) +{ + EvFormField *field; + + field = ev_view_get_form_field_at_location (view, x, y); + if(field) { + ev_view_set_cursor (view, EV_VIEW_CURSOR_LINK); + } else { + ev_view_set_cursor(view, EV_VIEW_CURSOR_NORMAL); + } +} + +static void +form_field_widgets_resize (EvView *view) +{ + GdkPoint d[2]; + gint v[4]; + GList* elem; + if (!view->childs) + return; + + for(elem = view->childs; elem != NULL; elem = g_list_next(elem)) { + EvViewChild *child = elem->data; + + doc_point_to_view_point(view, child->page, &child->p[0], &d[0]); + doc_point_to_view_point(view, child->page, &child->p[1], &d[1]); + + v[0] = d[0].x - view->scroll_x; v[1] = d[0].y - view->scroll_y; + v[2] = d[1].x - view->scroll_x; v[3] = d[1].y - view->scroll_y; + + gtk_widget_set_size_request(child->widget, v[2]-v[0], v[3]-v[1]); + ev_view_move_internal(view, child->widget, TRUE, v[0], TRUE, v[1]); + } +} + +/*** Container ***/ + +static void +ev_view_map (GtkWidget *widget) +{ + EvView *view = EV_VIEW(widget); + + GTK_WIDGET_SET_FLAGS(widget, GTK_MAPPED); + + if (view->childs) { + GList* elem; + for(elem = view->childs; elem != NULL; elem = g_list_next(elem)) { + EvViewChild* child = (EvViewChild*)elem->data; + if (GTK_WIDGET_VISIBLE(child->widget)) { + if (!GTK_WIDGET_MAPPED(child->widget)) { + gtk_widget_map(child->widget); + } + } + } + } + gdk_window_show(GTK_WIDGET(view)->window); +} + +static void +ev_view_add (GtkContainer *cont, GtkWidget *widget) +{ + g_warning("Use ev_view_put instead of ev_view_add"); +} + +static void +ev_view_remove (GtkContainer *cont, GtkWidget *widget) +{ + EvView *view = EV_VIEW(cont); + if (view->childs) { + GList* elem; + for(elem = view->childs; elem != NULL; elem = g_list_next(elem)) { + if (((EvViewChild*)elem->data)->widget == widget) { + gtk_widget_unparent(widget); + elem = g_list_remove (elem, elem->data); + } + } + } +} + +static void +ev_view_remove_all (GtkContainer *cont) +{ + EvView *view = EV_VIEW(cont); + if (view->childs) { + GList* elem; + for(elem = view->childs; elem != NULL; elem = g_list_next(elem)) { + gtk_widget_unparent(((EvViewChild*)elem->data)->widget); + elem = g_list_remove (elem, elem->data); + } + } + +} + +static void +ev_view_put (EvView *view, GtkWidget *widget, EvViewChildInfo *info, gint x, gint y, double x1, double y1, double x2, double y2, gint page, int id) +{ + EvViewChild *child; + + g_assert(info != NULL); + + child = g_new(EvViewChild, 1); + child->widget = widget; + child->info = info; + child->x = x; + child->y = y; + child->p[0].x = x1; + child->p[0].y = y1; + child->p[1].x = x2; + child->p[1].y = y2; + child->page = page; + child->field_id = id; + child->committed = FALSE; + + view->childs = g_list_append(view->childs, child); + + if (GTK_WIDGET_REALIZED(view)) + gtk_widget_set_parent_window (widget, GTK_WIDGET(view)->window); + gtk_widget_set_parent(widget, GTK_WIDGET(view)); +} + +static void +ev_view_forall (GtkContainer *cont, gboolean include_internals, GtkCallback callback, gpointer callback_data) +{ + EvView *view = EV_VIEW(cont); + if(view->childs) { + GList* elem; + for (elem = view->childs; elem != NULL; elem = g_list_next(elem)) + (*callback)(((EvViewChild*)elem->data)->widget, callback_data); + } +} + +static EvViewChild* +get_child (EvView *view, GtkWidget *widget) +{ + if(view->childs) { + GList* elem; + for (elem = view->childs; elem != NULL; elem = g_list_next(elem)) { + if (((EvViewChild*)elem->data)->widget == widget) { + return elem->data; + } + } + } + return NULL; +} + +static void +ev_view_move_internal (EvView *view, GtkWidget *widget, gboolean change_x, gint x, gboolean change_y, gint y) +{ + EvViewChild *child; + child = get_child(view, widget); + + g_assert(child); + + gtk_widget_freeze_child_notify(widget); + + if(change_x) { + child->x = x; + gtk_widget_child_notify(widget, "x"); + } + if(change_y) { + child->y = y; + gtk_widget_child_notify(widget, "y"); + } + gtk_widget_thaw_child_notify(widget); + + if (GTK_WIDGET_VISIBLE(widget) && GTK_WIDGET_VISIBLE(view)) + gtk_widget_queue_resize (GTK_WIDGET(widget)); +} + +static void +ev_view_allocate_child (EvView *view, EvViewChild *child) +{ + GtkAllocation allocation; + GtkRequisition requisition; + allocation.x = child->x; + allocation.y = child->y; + gtk_widget_get_child_requisition (child->widget, &requisition); + allocation.width = requisition.width; + allocation.height = requisition.height; + + gtk_widget_size_allocate (child->widget, &allocation); +} + +static void +ev_view_set_child_property (GtkContainer *cont, GtkWidget *child, guint property_id, const GValue *value, GParamSpec *pspec) +{ + switch (property_id) { + case CHILD_PROP_X: + ev_view_move_internal(EV_VIEW(cont), child, TRUE, g_value_get_int(value), FALSE, 0); + break; + case CHILD_PROP_Y: + ev_view_move_internal(EV_VIEW(cont), child, FALSE, 0, TRUE, g_value_get_int(value)); + break; + default: + GTK_CONTAINER_WARN_INVALID_CHILD_PROPERTY_ID(cont, property_id, pspec); + break; + } +} + +static void +ev_view_get_child_property (GtkContainer *cont, GtkWidget *child, guint property_id, GValue *value, GParamSpec *pspec) +{ + EvViewChild *view_child; + view_child = get_child(EV_VIEW(cont), child); + + switch (property_id) { + case CHILD_PROP_X: + g_value_set_int (value, view_child->x); + break; + case CHILD_PROP_Y: + g_value_set_int (value, view_child->y); + break; + default: + GTK_CONTAINER_WARN_INVALID_CHILD_PROPERTY_ID(cont, property_id, pspec); + break; + } +} Index: shell/ev-view.h =================================================================== --- shell/ev-view.h (revision 2339) +++ shell/ev-view.h (working copy) @@ -21,6 +21,7 @@ #define __EV_VIEW_H__ #include +#include #include "ev-document.h" #include "ev-link.h"