? .externalToolBuilders ? .project ? .settings ? INSTALL Index: backend/Makefile.am =================================================================== RCS file: /cvs/gnome/evince/backend/Makefile.am,v retrieving revision 1.31 diff -u -8 -p -B -b -r1.31 Makefile.am --- backend/Makefile.am 3 Dec 2006 20:35:43 -0000 1.31 +++ backend/Makefile.am 29 Dec 2006 20:10:43 -0000 @@ -38,16 +38,18 @@ libevbackend_la_SOURCES= \ ev-document-fonts.h \ ev-document-links.c \ ev-document-links.h \ ev-document-security.c \ ev-document-security.h \ ev-document-find.c \ ev-document-find.h \ ev-document-info.h \ + ev-form-field.h \ + ev-form-field.c \ ev-file-exporter.c \ ev-file-exporter.h \ ev-render-context.h \ ev-render-context.c \ ev-selection.h \ ev-selection.c \ ev-document-misc.h \ ev-document-misc.c Index: backend/ev-document.c =================================================================== RCS file: /cvs/gnome/evince/backend/ev-document.c,v retrieving revision 1.36 diff -u -8 -p -B -b -r1.36 ev-document.c --- backend/ev-document.c 8 Oct 2006 12:35:39 -0000 1.36 +++ backend/ev-document.c 29 Dec 2006 20:10:48 -0000 @@ -254,8 +254,116 @@ ev_rect_cmp (EvRectangle *a, if (a == NULL || b == NULL) return 1; return ! ((ABS (a->x1 - b->x1) < EPSILON) && (ABS (a->y1 - b->y1) < EPSILON) && (ABS (a->x2 - b->x2) < EPSILON) && (ABS (a->y2 - b->y2) < EPSILON)); } + +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); +} + +int +ev_document_get_form_field_choice_selected (EvDocument *document, int field_id) +{ + EvDocumentIface *iface = EV_DOCUMENT_GET_IFACE(document); + LOG("ev_document_get_form_field_choice_selected"); + if (iface->get_choice_field_selected == NULL) + return 0; + return iface->get_choice_field_selected(document, field_id); +} + +void +ev_document_set_form_field_choice_content (EvDocument *document, int field_id, int index) +{ + EvDocumentIface *iface = EV_DOCUMENT_GET_IFACE(document); + LOG("ev_document_set_form_field_choice_content"); + if (iface->set_choice_field_content == NULL) + return 0; + return iface->set_choice_field_content(document, field_id, index); +} + +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); +} + Index: backend/ev-document.h =================================================================== RCS file: /cvs/gnome/evince/backend/ev-document.h,v retrieving revision 1.34 diff -u -8 -p -B -b -r1.34 ev-document.h --- backend/ev-document.h 2 May 2006 19:02:45 -0000 1.34 +++ backend/ev-document.h 29 Dec 2006 20:10:48 -0000 @@ -22,16 +22,17 @@ #ifndef EV_DOCUMENT_H #define EV_DOCUMENT_H #include #include #include #include "ev-link.h" +#include "ev-form-field.h" #include "ev-document-info.h" #include "ev-render-context.h" G_BEGIN_DECLS #define EV_TYPE_DOCUMENT (ev_document_get_type ()) #define EV_DOCUMENT(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), EV_TYPE_DOCUMENT, EvDocument)) #define EV_DOCUMENT_IFACE(k) (G_TYPE_CHECK_CLASS_CAST((k), EV_TYPE_DOCUMENT, EvDocumentIface)) @@ -83,21 +84,50 @@ struct _EvDocumentIface double *width, double *height); char * (* get_page_label) (EvDocument *document, int page); gboolean (* can_get_text) (EvDocument *document); char * (* get_text) (EvDocument *document, int page, EvRectangle *rect); + GList * (* get_form_field_mapping) (EvDocument *document, + int page); gboolean (* has_attachments) (EvDocument *document); GList * (* get_attachments) (EvDocument *document); GdkPixbuf * (* render_pixbuf) (EvDocument *document, EvRenderContext *rc); EvDocumentInfo * (* get_info) (EvDocument *document); + void (* get_crop_box) (EvDocument *document, + int page, + EvRectangle *rect); + gchar * (* get_text_field_content) (EvDocument *document, + int field_id, + int *length); + gboolean (* set_text_field_content) (EvDocument *document, + int field_id, + gchar* content, + int length); + gchar * (* get_choice_field_content) (EvDocument *document, + int field_id, + int index, + int *length); + int (* get_choice_field_count) (EvDocument *document, + int field_id); + void (* set_choice_field_content) (EvDocument *document, + int field_id, + int index); + int (* get_choice_field_selected) (EvDocument *document, + int field_id); + void (* set_button_state) (EvDocument *document, + int field_id, + gboolean state); + gboolean (* get_button_state) (EvDocument *document, + int field_id); + }; GType ev_document_get_type (void); GQuark ev_document_error_quark (void); GMutex *ev_document_get_doc_mutex (void); void ev_document_doc_mutex_lock (void); void ev_document_doc_mutex_unlock (void); @@ -121,13 +151,31 @@ char *ev_document_get_text EvRectangle *rect); gboolean ev_document_has_attachments (EvDocument *document); GList *ev_document_get_attachments (EvDocument *document); GdkPixbuf *ev_document_render_pixbuf (EvDocument *document, EvRenderContext *rc); gint ev_rect_cmp (EvRectangle *a, EvRectangle *b); + +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); +void ev_document_set_form_field_choice_content (EvDocument *document, int field_id, int index); +int ev_document_get_form_field_choice_count (EvDocument *document, int field_id); +int ev_document_get_form_field_choice_selected (EvDocument *document, int field_id); G_END_DECLS #endif Index: backend/ev-form-field.c =================================================================== RCS file: backend/ev-form-field.c diff -N backend/ev-form-field.c --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ backend/ev-form-field.c 29 Dec 2006 20:10:49 -0000 @@ -0,0 +1,81 @@ +/* -*- 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; + field->content = NULL; + +} + +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: backend/ev-form-field.h =================================================================== RCS file: backend/ev-form-field.h diff -N backend/ev-form-field.h --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ backend/ev-form-field.h 29 Dec 2006 20:10:49 -0000 @@ -0,0 +1,66 @@ +/* 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; + + +typedef struct _EvFormField EvFormField; +struct _EvFormField +{ + EvFormFieldType type; + int id; + gdouble x1; + gdouble y1; + gdouble x2; + gdouble y2; + //text field specific + gchar *content; + int length; + //button specific + gboolean state; + //choice specific + int selected; +}; + +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: djvu/djvu-document.c =================================================================== RCS file: /cvs/gnome/evince/djvu/djvu-document.c,v retrieving revision 1.16 diff -u -8 -p -B -b -r1.16 djvu-document.c --- djvu/djvu-document.c 3 Dec 2006 15:54:22 -0000 1.16 +++ djvu/djvu-document.c 29 Dec 2006 20:11:21 -0000 @@ -270,16 +270,19 @@ djvu_document_document_iface_init (EvDoc iface->load = djvu_document_load; iface->save = djvu_document_save; iface->can_get_text = djvu_document_can_get_text; iface->get_text = djvu_document_get_text; iface->get_n_pages = djvu_document_get_n_pages; iface->get_page_size = djvu_document_get_page_size; iface->render_pixbuf = djvu_document_render_pixbuf; iface->get_info = djvu_document_get_info; + iface->get_form_field_mapping = NULL; + iface->get_field_content = NULL; + iface->set_field_content = NULL; } static void djvu_document_thumbnails_get_dimensions (EvDocumentThumbnails *document, gint page, gint suggested_width, gint *width, gint *height) Index: pdf/ev-poppler.cc =================================================================== RCS file: /cvs/gnome/evince/pdf/ev-poppler.cc,v retrieving revision 1.75 diff -u -8 -p -B -b -r1.75 ev-poppler.cc --- pdf/ev-poppler.cc 13 Dec 2006 12:14:56 -0000 1.75 +++ pdf/ev-poppler.cc 29 Dec 2006 20:12:50 -0000 @@ -91,16 +91,26 @@ static int pdf_document_get_n_pages ( static EvLinkDest *ev_link_dest_from_dest (PdfDocument *pdf_document, PopplerDest *dest); static EvLink *ev_link_from_action (PdfDocument *pdf_document, PopplerAction *action); static void pdf_document_search_free (PdfDocumentSearch *search); static void pdf_print_context_free (PdfPrintContext *ctx); +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, int field_id, int *length); +static gboolean pdf_document_set_text_field_content (EvDocument *document, int field_id, gchar* content, int length); +static void pdf_document_set_form_field_button_state (EvDocument *document, int field_id, gboolean state); +static gboolean pdf_document_get_form_field_button_state (EvDocument *document, int field_id); +static gchar* pdf_document_get_form_field_choice_content (EvDocument *document, int field_id, int index, int *length); +static int pdf_document_get_form_field_choice_count (EvDocument *document, int field_id); +static void pdf_document_set_form_field_choice_content (EvDocument *document, int field_id, int index); +static int pdf_document_get_form_field_choice_selected (EvDocument *document, int field_id); G_DEFINE_TYPE_WITH_CODE (PdfDocument, pdf_document, G_TYPE_OBJECT, { G_IMPLEMENT_INTERFACE (EV_TYPE_DOCUMENT, pdf_document_document_iface_init); G_IMPLEMENT_INTERFACE (EV_TYPE_DOCUMENT_SECURITY, pdf_document_security_iface_init); G_IMPLEMENT_INTERFACE (EV_TYPE_DOCUMENT_THUMBNAILS, @@ -654,18 +664,28 @@ pdf_document_document_iface_init (EvDocu iface->load = pdf_document_load; iface->get_n_pages = pdf_document_get_n_pages; iface->get_page_size = pdf_document_get_page_size; iface->get_page_label = pdf_document_get_page_label; iface->has_attachments = pdf_document_has_attachments; iface->get_attachments = pdf_document_get_attachments; iface->render_pixbuf = pdf_document_render_pixbuf; iface->get_text = pdf_document_get_text; + iface->get_form_field_mapping = pdf_document_get_form_field_mapping; + iface->get_crop_box = pdf_document_get_crop_box; iface->can_get_text = pdf_document_can_get_text; iface->get_info = pdf_document_get_info; + 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->set_choice_field_content = pdf_document_set_form_field_choice_content; + iface->get_choice_field_selected = pdf_document_get_form_field_choice_selected; }; static void pdf_document_security_iface_init (EvDocumentSecurityIface *iface) { iface->has_document_security = pdf_document_has_document_security; iface->set_password = pdf_document_set_password; } @@ -1624,9 +1644,161 @@ pdf_selection_iface_init (EvSelectionIfa iface->get_selection_region = pdf_selection_get_selection_region; iface->get_selection_map = pdf_selection_get_selection_map; } PdfDocument * pdf_document_new (void) { return PDF_DOCUMENT (g_object_new (PDF_TYPE_DOCUMENT, NULL)); +} + + +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; +} + +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); + field_mapping->content = NULL; + field_mapping->type = (EvFormFieldType)field->type; + field_mapping->id = field->id; + + copy_form_poppler_evince(field, field_mapping, height, crop_box); + + if(field_mapping->type == EV_FORM_FIELD_TYPE_TEXT) + field_mapping->content = poppler_document_get_form_field_text_content(pdf_document->document, field->id, &field_mapping->length); + if(field_mapping->type == EV_FORM_FIELD_TYPE_BUTTON) { + field_mapping->state = poppler_document_get_form_field_button_state(pdf_document->document, field->id); + /*field_mapping->num_kids = field->button.num_kids; + printf("num_kids: %i\n", field_mapping->num_kids); + field_mapping->kids = g_new(EvFormField, field_mapping->num_kids); + for (int i=0; inum_kids; i++) { + PopplerFormField *poppler_kid; + EvFormField *kid = &field_mapping->kids[i]; + poppler_kid = poppler_document_get_form_field_button_kid(pdf_document->document, field->id, i); + if (!poppler_kid) { + g_warning("pdf_document_get_form_field_mapping : unable to get kid for field with id %i\n", field->id); + break; + } + kid->id = poppler_kid->id; + kid->type = (EvFormFieldType)poppler_kid->type; + copy_form_poppler_evince(poppler_kid, kid, height, crop_box); + g_free(poppler_kid); + }*/ + + } + if(field_mapping->type == EV_FORM_FIELD_TYPE_CHOICE) + field_mapping->selected = poppler_document_get_form_field_choice_selected(pdf_document->document, field->id); + + + retval = g_list_prepend(retval, field_mapping); + } + poppler_page_free_form_fields(fields); + g_object_unref (poppler_page); + + return g_list_reverse(retval); +} + +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 gchar * +pdf_document_get_text_field_content (EvDocument *document, int 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 gboolean pdf_document_set_text_field_content (EvDocument *document, int 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); + return true; +} + +static void +pdf_document_set_form_field_button_state (EvDocument *document, int 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, int 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, int 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 void +pdf_document_set_form_field_choice_content (EvDocument *document, int field_id, int index) +{ + PdfDocument *pdf_document = PDF_DOCUMENT(document); + return poppler_document_set_form_field_choice_content(pdf_document->document, field_id, index); +} + +static int +pdf_document_get_form_field_choice_count (EvDocument *document, int field_id) +{ + PdfDocument *pdf_document = PDF_DOCUMENT(document); + return poppler_document_get_form_field_choice_num_choices(pdf_document->document, field_id); +} + +static int +pdf_document_get_form_field_choice_selected (EvDocument *document, int field_id) +{ + PdfDocument *pdf_document = PDF_DOCUMENT(document); + return poppler_document_get_form_field_choice_selected(pdf_document->document, field_id); } Index: pixbuf/pixbuf-document.c =================================================================== RCS file: /cvs/gnome/evince/pixbuf/pixbuf-document.c,v retrieving revision 1.23 diff -u -8 -p -B -b -r1.23 pixbuf-document.c --- pixbuf/pixbuf-document.c 19 Jan 2006 15:12:55 -0000 1.23 +++ pixbuf/pixbuf-document.c 29 Dec 2006 20:12:51 -0000 @@ -160,16 +160,19 @@ pixbuf_document_document_iface_init (EvD { iface->load = pixbuf_document_load; iface->save = pixbuf_document_save; iface->can_get_text = pixbuf_document_can_get_text; iface->get_n_pages = pixbuf_document_get_n_pages; iface->get_page_size = pixbuf_document_get_page_size; iface->render_pixbuf = pixbuf_document_render_pixbuf; iface->get_info = pixbuf_document_get_info; + iface->get_form_field_mapping = NULL; + iface->get_text_field_content = NULL; + iface->set_text_field_content = NULL; } static GdkPixbuf * pixbuf_document_thumbnails_get_thumbnail (EvDocumentThumbnails *document, gint page, gint rotation, gint size, gboolean border) Index: shell/ev-jobs.c =================================================================== RCS file: /cvs/gnome/evince/shell/ev-jobs.c,v retrieving revision 1.25 diff -u -8 -p -B -b -r1.25 ev-jobs.c --- shell/ev-jobs.c 3 Dec 2006 20:35:45 -0000 1.25 +++ shell/ev-jobs.c 29 Dec 2006 20:15:52 -0000 @@ -254,16 +254,17 @@ ev_job_links_run (EvJobLinks *job) EvJob * ev_job_render_new (EvDocument *document, EvRenderContext *rc, gint width, gint height, EvRectangle *selection_points, GdkColor *text, GdkColor *base, + gboolean include_form, gboolean include_links, gboolean include_text, gboolean include_selection) { EvJobRender *job; g_return_val_if_fail (EV_IS_RENDER_CONTEXT (rc), NULL); if (include_selection) @@ -272,16 +273,17 @@ ev_job_render_new (EvDocument *docu job = g_object_new (EV_TYPE_JOB_RENDER, NULL); EV_JOB (job)->document = g_object_ref (document); job->rc = g_object_ref (rc); job->target_width = width; job->target_height = height; job->text = *text; job->base = *base; + job->include_form = include_form; job->include_links = include_links; job->include_text = include_text; job->include_selection = include_selection; if (include_selection) job->selection_points = *selection_points; if (EV_IS_ASYNC_RENDERER (document)) { @@ -312,16 +314,18 @@ ev_job_render_run (EvJobRender *job) if (EV_JOB (job)->async) { EvAsyncRenderer *renderer = EV_ASYNC_RENDERER (EV_JOB (job)->document); ev_async_renderer_render_pixbuf (renderer, job->rc->page, job->rc->scale, job->rc->rotation); g_signal_connect (EV_JOB (job)->document, "render_finished", G_CALLBACK (render_finished_cb), job); } else { 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), job->rc->page); if (job->include_text && EV_IS_SELECTION (EV_JOB (job)->document)) job->text_mapping = ev_selection_get_selection_map (EV_SELECTION (EV_JOB (job)->document), job->rc); Index: shell/ev-jobs.h =================================================================== RCS file: /cvs/gnome/evince/shell/ev-jobs.h,v retrieving revision 1.19 diff -u -8 -p -B -b -r1.19 ev-jobs.h --- shell/ev-jobs.h 13 Dec 2006 06:13:47 -0000 1.19 +++ shell/ev-jobs.h 29 Dec 2006 20:15:52 -0000 @@ -120,23 +120,25 @@ struct _EvJobRender EvRenderContext *rc; gint target_width; gint target_height; GdkPixbuf *pixbuf; GList *link_mapping; GdkRegion *text_mapping; + GList *form_field_mapping; GdkPixbuf *selection; GdkRegion *selection_region; EvRectangle selection_points; GdkColor base; GdkColor text; + gint include_form : 1; gint include_links : 1; gint include_text : 1; gint include_selection : 1; }; struct _EvJobRenderClass { EvJobClass parent_class; @@ -218,16 +220,17 @@ void ev_job_links_run GType ev_job_render_get_type (void) G_GNUC_CONST; EvJob *ev_job_render_new (EvDocument *document, EvRenderContext *rc, gint width, gint height, EvRectangle *selection_points, GdkColor *text, GdkColor *base, + gboolean include_form, gboolean include_links, gboolean include_text, gboolean include_selection); void ev_job_render_run (EvJobRender *thumbnail); /* EvJobThumbnail */ GType ev_job_thumbnail_get_type (void) G_GNUC_CONST; EvJob *ev_job_thumbnail_new (EvDocument *document, Index: shell/ev-pixbuf-cache.c =================================================================== RCS file: /cvs/gnome/evince/shell/ev-pixbuf-cache.c,v retrieving revision 1.23 diff -u -8 -p -B -b -r1.23 ev-pixbuf-cache.c --- shell/ev-pixbuf-cache.c 27 Aug 2006 20:06:18 -0000 1.23 +++ shell/ev-pixbuf-cache.c 29 Dec 2006 20:16:01 -0000 @@ -7,16 +7,17 @@ typedef struct _CacheJobInfo { EvJob *job; EvRenderContext *rc; /* Data we get from rendering */ GdkPixbuf *pixbuf; GList *link_mapping; GdkRegion *text_mapping; + GList *form_field_mapping; /* Selection data. * Selection_points are the coordinates encapsulated in selection. * target_points is the target selection size. */ EvRectangle selection_points; EvRectangle target_points; gboolean points_set; @@ -70,16 +71,26 @@ static CacheJobInfo *find_job_cache int page); static void copy_job_to_job_info (EvJobRender *job_render, CacheJobInfo *job_info, EvPixbufCache *pixbuf_cache); static gboolean new_selection_pixbuf_needed(EvPixbufCache *pixbuf_cache, CacheJobInfo *job_info, gint page, gfloat scale); +void add_job (EvPixbufCache *pixbuf_cache, + CacheJobInfo *job_info, + EvPageCache *page_cache, + gint page, + gint rotation, + gfloat scale, + EvJobPriority priority, + int width, + int height); + /* These are used for iterating through the prev and next arrays */ #define FIRST_VISABLE_PREV(pixbuf_cache) \ (MAX (0, pixbuf_cache->preload_cache_size + 1 - pixbuf_cache->start_page)) #define VISIBLE_NEXT_LEN(pixbuf_cache, page_cache) \ (MIN(pixbuf_cache->preload_cache_size, ev_page_cache_get_n_pages (page_cache) - (1 + pixbuf_cache->end_page))) #define PAGE_CACHE_LEN(pixbuf_cache) \ @@ -143,16 +154,20 @@ dispose_cache_job_info (CacheJobInfo *jo ev_job_queue_remove_job (job_info->job); g_object_unref (G_OBJECT (job_info->job)); job_info->job = NULL; } if (job_info->pixbuf) { 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; } if (job_info->text_mapping) { gdk_region_destroy (job_info->text_mapping); job_info->text_mapping = NULL; } @@ -304,16 +319,17 @@ move_one_job (CacheJobInfo *job_info, page_offset = page - start_page; g_assert (page_offset >= 0 && page_offset <= ((end_page - start_page) + 1)); new_priority = EV_JOB_PRIORITY_HIGH; target_page = new_job_list + page_offset; } *target_page = *job_info; + job_info->form_field_mapping = NULL; job_info->job = NULL; job_info->pixbuf = NULL; job_info->link_mapping = NULL; if (new_priority != priority && target_page->job) { ev_job_queue_update_job (target_page->job, new_priority); } } @@ -415,18 +431,21 @@ copy_job_to_job_info (EvJobRender *job job_info->link_mapping = job_render->link_mapping; } if (job_render->include_text) { if (job_info->text_mapping) gdk_region_destroy (job_info->text_mapping); job_info->text_mapping = job_render->text_mapping; } - - + if (job_render->form_field_mapping) { + 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_selection) { if (job_info->selection) { g_object_unref (G_OBJECT (job_info->selection)); job_info->selection = NULL; } if (job_info->selection_region) { gdk_region_destroy (job_info->selection_region); @@ -523,62 +542,71 @@ add_job_if_needed (EvPixbufCache *pixbuf gint page, gint rotation, gfloat scale, EvJobPriority priority) { gboolean include_links = FALSE; gboolean include_text = FALSE; gboolean include_selection = FALSE; + gboolean include_form = FALSE; int width, height; GdkColor *text, *base; if (job_info->job) return; ev_page_cache_get_size (page_cache, page, rotation, scale, &width, &height); if (job_info->pixbuf && gdk_pixbuf_get_width (job_info->pixbuf) == width && gdk_pixbuf_get_height (job_info->pixbuf) == height) return; /* make a new job now */ + /*FIXME: commented out to have PDF form working */ + #if 0 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 */ if (job_info->link_mapping == NULL) include_links = TRUE; if (job_info->text_mapping == NULL) include_text = TRUE; + if (job_info->form_field_mapping == NULL) + include_form = 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_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); + #endif + add_job(pixbuf_cache, job_info, page_cache, page, rotation, scale, priority, width, height); + } static void ev_pixbuf_cache_add_jobs_if_needed (EvPixbufCache *pixbuf_cache, gint rotation, gfloat scale) { @@ -1044,9 +1072,106 @@ ev_pixbuf_cache_get_selection_list (EvPi retval = g_list_append (retval, selection); } page ++; } return retval; } + +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; + 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->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_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 =================================================================== RCS file: /cvs/gnome/evince/shell/ev-pixbuf-cache.h,v retrieving revision 1.9 diff -u -8 -p -B -b -r1.9 ev-pixbuf-cache.h --- shell/ev-pixbuf-cache.h 6 Aug 2005 05:13:20 -0000 1.9 +++ shell/ev-pixbuf-cache.h 29 Dec 2006 20:16:01 -0000 @@ -58,18 +58,26 @@ void ev_pixbuf_cache_set_page_ gfloat scale, GList *selection_list); GdkPixbuf *ev_pixbuf_cache_get_pixbuf (EvPixbufCache *pixbuf_cache, gint page); GList *ev_pixbuf_cache_get_link_mapping (EvPixbufCache *pixbuf_cache, 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, gfloat scale, GdkRegion **region); void ev_pixbuf_cache_set_selection_list (EvPixbufCache *pixbuf_cache, GList *selection_list); Index: shell/ev-view-private.h =================================================================== RCS file: /cvs/gnome/evince/shell/ev-view-private.h,v retrieving revision 1.12 diff -u -8 -p -B -b -r1.12 ev-view-private.h --- shell/ev-view-private.h 10 Dec 2006 20:49:12 -0000 1.12 +++ shell/ev-view-private.h 29 Dec 2006 20:16:12 -0000 @@ -36,16 +36,27 @@ typedef struct { /* Information for handling selection */ typedef struct { gboolean in_drag; GdkPoint start; gboolean in_selection; GList *selections; } SelectionInfo; +/* Info for form fields/container */ +typedef struct { + GtkWidget *widget; + gint x; + gint y; + EvPoint p[2]; + gint page; + int field_id; //id of the field represented by this child +} EvViewChild; + + typedef enum { SCROLL_TO_KEEP_POSITION, SCROLL_TO_PAGE_POSITION, SCROLL_TO_CENTER, SCROLL_TO_FIND_LOCATION, } PendingScroll; typedef enum { @@ -60,17 +71,17 @@ typedef enum { typedef enum { EV_PRESENTATION_NORMAL, EV_PRESENTATION_BLACK, EV_PRESENTATION_WHITE, EV_PRESENTATION_END } EvPresentationState; struct _EvView { - GtkWidget parent_instance; + GtkContainer parent_instance; EvDocument *document; char *status; char *find_status; int find_result; gboolean jump_to_find_result; @@ -120,20 +131,28 @@ struct _EvView { guint selection_scroll_id; EvViewSelectionMode selection_mode; SelectionInfo selection_info; /* Links */ GtkWidget *link_tooltip; EvLink *hovered_link; + + /* Container */ + gint current_width; + gint current_height; + EvViewChild *child; + + /* Forms */ + GArray* pendingFormFields; }; struct _EvViewClass { - GtkWidgetClass parent_class; + GtkContainerClass parent_class; void (*set_scroll_adjustments) (EvView *view, GtkAdjustment *hadjustment, GtkAdjustment *vadjustment); void (*binding_activated) (EvView *view, EvScrollType scroll, gboolean horizontal); void (*zoom_invalid) (EvView *view); Index: shell/ev-view.c =================================================================== RCS file: /cvs/gnome/evince/shell/ev-view.c,v retrieving revision 1.218 diff -u -8 -p -B -b -r1.218 ev-view.c --- shell/ev-view.c 13 Dec 2006 21:51:06 -0000 1.218 +++ shell/ev-view.c 29 Dec 2006 20:16:22 -0000 @@ -57,16 +57,22 @@ enum { PROP_PRESENTATION, PROP_SIZING_MODE, PROP_ZOOM, PROP_ROTATION, PROP_HAS_SELECTION, }; enum { + CHILD_PROP_0, + CHILD_PROP_X, + CHILD_PROP_Y +}; + +enum { SIGNAL_BINDING_ACTIVATED, SIGNAL_ZOOM_INVALID, SIGNAL_EXTERNAL_LINK, SIGNAL_POPUP_MENU, N_SIGNALS, }; enum { @@ -306,18 +312,71 @@ static char* get_selected_text static void ev_view_primary_get_cb (GtkClipboard *clipboard, GtkSelectionData *selection_data, guint info, gpointer data); static void ev_view_primary_clear_cb (GtkClipboard *clipboard, gpointer data); static void ev_view_update_primary_selection (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); + +/*** 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, + 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_WIDGET) + +G_DEFINE_TYPE (EvView, ev_view, GTK_TYPE_CONTAINER) static void scroll_to_current_page (EvView *view, GtkOrientation orientation) { GdkPoint view_point; if (view->document == NULL) { return; @@ -1625,16 +1684,25 @@ ev_view_size_request (GtkWidget *wi return; } if (view->presentation) { requisition->width = 1; requisition->height = 1; return; } + if (view->child) { + GtkRequisition child_requisition; + gtk_widget_size_request (view->child->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) ev_view_size_request_continuous (view, requisition); else if (view->dual_page) ev_view_size_request_dual_page (view, requisition); else @@ -1642,16 +1710,20 @@ ev_view_size_request (GtkWidget *wi } static void ev_view_size_allocate (GtkWidget *widget, GtkAllocation *allocation) { EvView *view = EV_VIEW (widget); + if (view->child) { + ev_view_allocate_child(view, view->child); + } + if (view->sizing_mode == EV_SIZING_FIT_WIDTH || view->sizing_mode == EV_SIZING_BEST_FIT) { g_signal_emit (view, signals[SIGNAL_ZOOM_INVALID], 0); ev_view_size_request (widget, &widget->requisition); } @@ -1702,16 +1774,22 @@ ev_view_realize (GtkWidget *widget) GDK_WA_VISUAL); gdk_window_set_user_data (widget->window, widget); widget->style = gtk_style_attach (widget->style, widget->window); if (view->presentation) gdk_window_set_background (widget->window, &widget->style->black); else gdk_window_set_background (widget->window, &widget->style->mid [GTK_STATE_NORMAL]); + + if (view->child) { + gtk_widget_set_parent_window(view->child->widget, GTK_WIDGET(view)->window); + ev_view_allocate_child(view, view->child); + } + } static gboolean ev_view_scroll_event (GtkWidget *widget, GdkEventScroll *event) { EvView *view = EV_VIEW (widget); guint state; @@ -1874,16 +1952,17 @@ ev_view_expose_event (GtkWidget *wi page_area.x -= view->scroll_x; page_area.y -= view->scroll_y; draw_one_page (view, i, &page_area, &border, &(event->area), &page_ready); 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; } static gboolean ev_view_popup_menu (GtkWidget *widget) { gint x, y; @@ -1922,16 +2001,17 @@ ev_view_button_press_event (GtkWidget } gtk_widget_queue_draw (widget); } 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: /* use root coordinates as reference point because * scrolling changes window relative coordinates */ view->drag_info.start.x = event->x_root; view->drag_info.start.y = event->y_root; view->drag_info.hadj = gtk_adjustment_get_value (view->hadjustment); view->drag_info.vadj = gtk_adjustment_get_value (view->vadjustment); @@ -2111,16 +2191,17 @@ ev_view_motion_notify_event (GtkWidget MIN(view->drag_info.vadj - dvadj_value, view->vadjustment->upper - view->vadjustment->page_size)); return TRUE; } } else if (view->pressed_button <= 0) { handle_link_over_xy (view, x, y); + handle_form_field_over_xy (view, x, y); return TRUE; } return FALSE; } static gboolean ev_view_button_release_event (GtkWidget *widget, @@ -2526,16 +2607,17 @@ draw_one_page (EvView *view, overlap.y - real_page_area.y, overlap.x, overlap.y, overlap.width, overlap.height, GDK_RGB_DITHER_NORMAL, 0, 0); g_object_unref (scaled_selection); } } + render_form_field_content_for_page (view, page); } /*** GObject functions ***/ static void ev_view_finalize (GObject *object) { EvView *view = EV_VIEW (object); @@ -2696,23 +2778,25 @@ ev_view_get_property (GObject *object, } } static void ev_view_class_init (EvViewClass *class) { 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; object_class->finalize = ev_view_finalize; 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; widget_class->button_release_event = ev_view_button_release_event; widget_class->key_press_event = ev_view_key_press_event; widget_class->focus_in_event = ev_view_focus_in; widget_class->focus_out_event = ev_view_focus_out; widget_class->get_accessible = ev_view_get_accessible; @@ -2722,19 +2806,43 @@ ev_view_class_init (EvViewClass *class) widget_class->scroll_event = ev_view_scroll_event; widget_class->enter_notify_event = ev_view_enter_notify_event; widget_class->leave_notify_event = ev_view_leave_notify_event; widget_class->style_set = ev_view_style_set; widget_class->drag_data_get = ev_view_drag_data_get; 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), G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION, G_STRUCT_OFFSET (EvViewClass, set_scroll_adjustments), NULL, NULL, ev_marshal_VOID__OBJECT_OBJECT, G_TYPE_NONE, 2, @@ -2868,16 +2976,19 @@ ev_view_class_init (EvViewClass *class) add_scroll_binding_keypad (binding_set, GDK_Down, GDK_MOD1_MASK, EV_SCROLL_STEP_UP, FALSE); } static void ev_view_init (EvView *view) { GTK_WIDGET_SET_FLAGS (view, GTK_CAN_FOCUS); + view->current_width = 0; + view->current_height = 0; + view->child = NULL; view->spacing = 5; view->scale = 1.0; view->current_page = 0; view->pressed_button = -1; view->cursor = EV_VIEW_CURSOR_NORMAL; view->drag_info.in_drag = FALSE; view->selection_info.selections = NULL; view->selection_info.in_selection = FALSE; @@ -2914,16 +3025,19 @@ find_changed_cb (EvDocument *document, i gtk_widget_queue_draw (GTK_WIDGET (view)); } static void job_finished_cb (EvPixbufCache *pixbuf_cache, EvView *view) { gtk_widget_queue_draw (GTK_WIDGET (view)); + if(view->pendingFormFields) + g_array_free(view->pendingFormFields, TRUE); + view->pendingFormFields = g_array_new(FALSE, TRUE, sizeof(int)); } static void page_changed_cb (EvPageCache *page_cache, int new_page, EvView *view) { if (view->current_page != new_page) { @@ -2957,16 +3071,22 @@ static void on_adjustment_value_changed if (view->vadjustment) { dy = view->scroll_y - (int) view->vadjustment->value; view->scroll_y = (int) view->vadjustment->value; } else { view->scroll_y = 0; } + /* move the childs widgets (form fields) in order they follow the window scrolling */ + if (view->child) { + ev_view_move_internal(view, view->child->widget, TRUE, view->child->x + dx, TRUE, view->child->y + dy); + } + + if (view->pending_resize) gtk_widget_queue_draw (GTK_WIDGET (view)); else gdk_window_scroll (GTK_WIDGET (view)->window, dx, dy); if (view->document) @@ -4403,9 +4523,521 @@ ev_scroll_type_get_type (void) { EV_SCROLL_STEP_FORWARD, "EV_SCROLL_STEP_FORWARD", "scroll-step-forward" }, { EV_SCROLL_STEP_UP, "EV_SCROLL_STEP_UP", "scroll-step-up" }, { EV_SCROLL_STEP_DOWN, "EV_SCROLL_STEP_DOWN", "scroll-step-down" }, { 0, NULL, NULL } }; etype = g_enum_register_static ("EvScrollType", values); } 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 +render_form_field_content_for_page (EvView *view, gint page) +{ + + GList *form_field_mapping; + GList *tmp_list; + form_field_mapping = ev_pixbuf_cache_get_form_field_mapping (view->pixbuf_cache, page); + tmp_list = form_field_mapping; + + while (tmp_list) { + EvPoint p[2]; + GdkPoint d[2]; + gint v[4]; + int i; + EvFormField *field = tmp_list->data; + PangoLayout* playout; + PangoFontDescription* pfontdesc; + gchar* content = NULL; + gboolean pending = FALSE; + + tmp_list = tmp_list->next; + + if (view->pendingFormFields) { + for(i=0; ipendingFormFields->len; i++) { + if (g_array_index(view->pendingFormFields, int, i) == field->id) { + pending = TRUE; + break; + } + } + } + if (!pending) + continue; + printf("found pending\n"); + + if (field->type == EV_FORM_FIELD_TYPE_TEXT) { + int length; + gchar *txt = ev_document_get_form_field_text_content(view->document, field->id, &length); + if (txt) { + content = g_convert(txt, + length, + "UTF8", + "UTF16", + NULL, + NULL, + NULL); + } else { + content = NULL; + } + //content = ev_document_get_form_field_text_content(view->document, field->id); + if (!content) + continue; + } else if (field->type == EV_FORM_FIELD_TYPE_BUTTON) { + gboolean state = ev_document_get_form_field_button_state(view->document, field->id); + + if (!state) + continue; + content = "x"; + printf("ev-view.c:render_form_field_content_for_page content = x"); + } else if (field->type == EV_FORM_FIELD_TYPE_CHOICE) { + //FIXME:: + int length; + gchar *txt = ev_document_get_form_field_choice_content(view->document, field->id, + ev_document_get_form_field_choice_selected(view->document, field->id), &length); + if (txt) { + content = g_convert(txt, + length, + "UTF8", + "UTF16BE", + NULL, + NULL, + NULL); + + } else { + content = NULL; + } + if (!content) + continue; + } + + + p[0].x = field->x1; + p[0].y = field->y1; + p[1].x = field->x2; + p[1].y = 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; + + playout = gtk_widget_create_pango_layout(GTK_WIDGET(view), content); + pfontdesc = pango_font_description_from_string("Sans 10"); + pango_font_description_set_absolute_size(pfontdesc, 0.75*PANGO_SCALE*(v[3]-v[1])); + pango_layout_set_width(playout, PANGO_SCALE*(v[2]-v[1])); + pango_layout_set_font_description(playout, pfontdesc); + + //draw a rectangle to hide the not-up-to-date text from the last poppler rendering + //FIXME: the rect color is fixed to white.. perhaps it should be the same as the pdf background + gdk_draw_rectangle(GTK_WIDGET(view)->window, + GTK_WIDGET(view)->style->white_gc, + TRUE, + v[0], + v[1], + v[2]-v[0], + v[3]-v[1]); + gdk_draw_layout(GTK_WIDGET(view)->window, + GTK_WIDGET (view)->style->fg_gc[GTK_STATE_NORMAL], + v[0], + v[1], + playout); + } + + + +} + +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; + 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; + + new_field = ev_form_field_mapping_find (form_field_mapping, x_offset/view->scale, y_offset/view->scale); + + //store current entry text + if (view->child) { + if (GTK_IS_ENTRY(view->child->widget)) { + const gchar *txt = gtk_entry_get_text(GTK_ENTRY(view->child->widget)); + if (txt) { + int i; + gsize length; + gchar *tmp = g_convert (gtk_entry_get_text(GTK_ENTRY(view->child->widget)), + -1, + "UTF16", + "UTF8", + NULL, + &length, + NULL); + printf("ev-view.c: handle_click_at_location g_convert : wrote %i bytes, %s , strlen(tmp): %i\n", length, tmp, strlen(tmp)); + for(i=0; idocument, view->child->field_id, tmp, length); + } else { + ev_document_set_form_field_text_content(view->document, view->child->field_id, NULL, 0); + } + + if(view->pendingFormFields) + g_array_append_val(view->pendingFormFields,view->child->field_id); + ev_pixbuf_cache_reload_page(view->pixbuf_cache, page, view->rotation, view->scale); + } else if (GTK_IS_COMBO_BOX(view->child->widget)) { + gchar *txt = gtk_combo_box_get_active_text(GTK_COMBO_BOX(view->child->widget)); + printf("ev-view.c: handle_click_at_location: choice selected %s %i\n", txt, gtk_combo_box_get_active(GTK_COMBO_BOX(view->child->widget))); + ev_document_set_form_field_choice_content(view->document, view->child->field_id, gtk_combo_box_get_active(GTK_COMBO_BOX(view->child->widget))); + if(view->pendingFormFields) + g_array_append_val(view->pendingFormFields,view->child->field_id); + ev_pixbuf_cache_reload_page(view->pixbuf_cache, page, view->rotation, view->scale); + + } + } + + //clean current view widgets + ev_view_remove_all(GTK_CONTAINER(view)); + + if (!new_field) { + return; + } + + + 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; + + 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: + { + wid = gtk_entry_new(); + 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", + "UTF16", + NULL, + NULL, + NULL); + } else { + content = NULL; + } + + 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: + { + 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); + } + 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,v[0],v[1],p[0].x,p[0].y,p[1].x,p[1].y,page, new_field->id); + gtk_widget_show(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]; + EvViewChild *child = view->child; + + if(!child) + return; + + 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->child) { + if (GTK_WIDGET_VISIBLE(view->child->widget)) { + if (!GTK_WIDGET_MAPPED(view->child->widget)) { + gtk_widget_map(view->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->child) { + if (view->child->widget == widget) { + gtk_widget_unparent(widget); + g_free(view->child); + view->child = NULL; + } + } +} + +static void +ev_view_remove_all (GtkContainer *cont) +{ + EvView *view = EV_VIEW(cont); + if (view->child) { + gtk_widget_unparent(view->child->widget); + g_free(view->child); + view->child = NULL; + } + +} + +static void +ev_view_put (EvView *view, GtkWidget *widget, gint x, gint y, double x1, double y1, double x2, double y2, gint page, int id) +{ + EvViewChild *child; + + if (view->child != NULL) { + g_warning("ev_view_put, a child already exists"); + } + + child = g_new(EvViewChild, 1); + child->widget = widget; + 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; + + view->child = 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->child) { + (*callback)(view->child->widget, callback_data); + } +} + +static EvViewChild* +get_child (EvView *view, GtkWidget *widget) +{ + if(view->child) { + if(view->child->widget == widget) { + return view->child; + } + } + 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 =================================================================== RCS file: /cvs/gnome/evince/shell/ev-view.h,v retrieving revision 1.50 diff -u -8 -p -B -b -r1.50 ev-view.h --- shell/ev-view.h 2 May 2006 19:02:46 -0000 1.50 +++ shell/ev-view.h 29 Dec 2006 20:16:23 -0000 @@ -16,16 +16,17 @@ * 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_VIEW_H__ #define __EV_VIEW_H__ #include +#include #include "ev-document.h" #include "ev-link.h" #include "ev-view-accessible.h" G_BEGIN_DECLS #define EV_TYPE_VIEW (ev_view_get_type ()) Index: shell/ev-window.c =================================================================== RCS file: /cvs/gnome/evince/shell/ev-window.c,v retrieving revision 1.331 diff -u -8 -p -B -b -r1.331 ev-window.c --- shell/ev-window.c 14 Dec 2006 11:45:40 -0000 1.331 +++ shell/ev-window.c 29 Dec 2006 20:16:33 -0000 @@ -3697,17 +3697,21 @@ static const GtkActionEntry entries[] = { "FileProperties", GTK_STOCK_PROPERTIES, N_("P_roperties"), "Return", NULL, G_CALLBACK (ev_window_cmd_file_properties) }, { "FileCloseWindow", GTK_STOCK_CLOSE, NULL, "W", NULL, G_CALLBACK (ev_window_cmd_file_close_window) }, /* Edit menu */ { "EditCopy", GTK_STOCK_COPY, NULL, "C", NULL, G_CALLBACK (ev_window_cmd_edit_copy) }, +#ifdef HAVE_GTK_RECENT { "EditSelectAll", GTK_STOCK_SELECT_ALL, N_("Select _All"), "A", NULL, +#else + { "EditSelectAll", NULL, N_("Select _All"), "A", NULL, +#endif /* HAVE_GTK_RECENT */ G_CALLBACK (ev_window_cmd_edit_select_all) }, { "EditFind", GTK_STOCK_FIND, N_("_Find..."), "F", N_("Find a word or phrase in the document"), G_CALLBACK (ev_window_cmd_edit_find) }, { "EditFindNext", NULL, N_("Find Ne_xt"), "G", NULL, G_CALLBACK (ev_window_cmd_edit_find_next) }, { "EditFindPrevious", NULL, N_("Find Pre_vious"), "G", NULL, G_CALLBACK (ev_window_cmd_edit_find_previous) },