From: Carlos Garcia Campos Date: Sun, 8 Jul 2007 20:09:36 +0000 (+0000) Subject: Merge evince-forms branch. X-Git-Tag: EVINCE_0_9_2~8 X-Git-Url: https://www.fi.muni.cz/~kas/git//home/kas/public_html/git/?a=commitdiff_plain;h=6426ce3672bf190ab39d9c49c841232c127d174f;p=evince.git Merge evince-forms branch. 2007-07-08 Carlos Garcia Campos * configure.ac: * backend/pdf/ev-poppler.cc: (pdf_document_get_crop_box), (ev_form_field_from_poppler_field), (pdf_document_forms_get_form_fields), (pdf_document_forms_form_field_text_get_text), (pdf_document_forms_form_field_text_set_text), (pdf_document_forms_form_field_button_set_state), (pdf_document_forms_form_field_button_get_state), (pdf_document_forms_form_field_choice_get_item), (pdf_document_forms_form_field_choice_get_n_items), (pdf_document_forms_form_field_choice_is_item_selected), (pdf_document_forms_form_field_choice_select_item), (pdf_document_forms_form_field_choice_toggle_item), (pdf_document_forms_form_field_choice_unselect_all), (pdf_document_forms_form_field_choice_set_text), (pdf_document_forms_form_field_choice_get_text), (pdf_document_document_forms_iface_init): * libdocument/Makefile.am: * libdocument/ev-form-field.[ch]: * libdocument/ev-document-forms.[ch]: * shell/ev-pixbuf-cache.[ch]: (dispose_cache_job_info), (move_one_job), (copy_job_to_job_info), (add_job_if_needed), (add_job), (ev_pixbuf_cache_reload_page), (ev_pixbuf_cache_get_form_field_mapping): * shell/ev-jobs.[ch]: (ev_job_render_new), (ev_job_render_run): * shell/ev-view-private.h: * shell/ev-view.[ch]: (ev_view_set_scroll_adjustments), (ev_view_handle_cursor_over_xy), (ev_view_get_form_field_at_location), (ev_view_forms_remove_widgets), (ev_view_form_field_destroy), (ev_view_form_field_button_create_widget), (ev_view_form_field_text_save), (ev_view_form_field_text_changed), (ev_view_form_field_text_create_widget), (ev_view_form_field_choice_save), (ev_view_form_field_choice_changed), (ev_view_form_field_choice_create_widget), (ev_view_handle_form_field), (ev_view_size_allocate), (ev_view_realize), (draw_end_presentation_page), (ev_view_button_press_event), (ev_view_remove_all), (ev_view_motion_notify_event), (ev_view_key_press_event), (ev_view_enter_notify_event), (highlight_find_results), (draw_loading_text), (draw_one_page), (ev_view_destroy), (ev_view_class_init), (page_changed_cb), (on_adjustment_value_changed), (ev_view_set_presentation), (merge_selection_region), (ev_view_set_cursor), (ev_view_reset_presentation_state): Merge evince-forms branch. svn path=/trunk/; revision=2560 --- diff --git a/ChangeLog b/ChangeLog index 7fd60bd7..9fc7297b 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,54 @@ +2007-07-08 Carlos Garcia Campos + + * configure.ac: + * backend/pdf/ev-poppler.cc: (pdf_document_get_crop_box), + (ev_form_field_from_poppler_field), + (pdf_document_forms_get_form_fields), + (pdf_document_forms_form_field_text_get_text), + (pdf_document_forms_form_field_text_set_text), + (pdf_document_forms_form_field_button_set_state), + (pdf_document_forms_form_field_button_get_state), + (pdf_document_forms_form_field_choice_get_item), + (pdf_document_forms_form_field_choice_get_n_items), + (pdf_document_forms_form_field_choice_is_item_selected), + (pdf_document_forms_form_field_choice_select_item), + (pdf_document_forms_form_field_choice_toggle_item), + (pdf_document_forms_form_field_choice_unselect_all), + (pdf_document_forms_form_field_choice_set_text), + (pdf_document_forms_form_field_choice_get_text), + (pdf_document_document_forms_iface_init): + * libdocument/Makefile.am: + * libdocument/ev-form-field.[ch]: + * libdocument/ev-document-forms.[ch]: + * shell/ev-pixbuf-cache.[ch]: (dispose_cache_job_info), + (move_one_job), (copy_job_to_job_info), (add_job_if_needed), + (add_job), (ev_pixbuf_cache_reload_page), + (ev_pixbuf_cache_get_form_field_mapping): + * shell/ev-jobs.[ch]: (ev_job_render_new), (ev_job_render_run): + * shell/ev-view-private.h: + * shell/ev-view.[ch]: (ev_view_set_scroll_adjustments), + (ev_view_handle_cursor_over_xy), + (ev_view_get_form_field_at_location), + (ev_view_forms_remove_widgets), (ev_view_form_field_destroy), + (ev_view_form_field_button_create_widget), + (ev_view_form_field_text_save), (ev_view_form_field_text_changed), + (ev_view_form_field_text_create_widget), + (ev_view_form_field_choice_save), + (ev_view_form_field_choice_changed), + (ev_view_form_field_choice_create_widget), + (ev_view_handle_form_field), (ev_view_size_allocate), + (ev_view_realize), (draw_end_presentation_page), + (ev_view_button_press_event), (ev_view_remove_all), + (ev_view_motion_notify_event), (ev_view_key_press_event), + (ev_view_enter_notify_event), (highlight_find_results), + (draw_loading_text), (draw_one_page), (ev_view_destroy), + (ev_view_class_init), (page_changed_cb), + (on_adjustment_value_changed), (ev_view_set_presentation), + (merge_selection_region), (ev_view_set_cursor), + (ev_view_reset_presentation_state): + + Merge evince-forms branch. + 2007-07-03 Jaap Haitsma * cut-n-paste/toolbar-editor/update-toolbareditor-from-libegg: removed @@ -16,7 +67,7 @@ Adds a nice icon to page action during toolbar editing. See bug #452872. -2007-07-02 Nickolay V. Shmyrev * data/evince-toolbar.xml: * shell/ev-window.c: diff --git a/backend/pdf/ev-poppler.cc b/backend/pdf/ev-poppler.cc index 5cdeddec..3b3fe2be 100644 --- a/backend/pdf/ev-poppler.cc +++ b/backend/pdf/ev-poppler.cc @@ -19,6 +19,10 @@ #include "config.h" +#ifdef HAVE_POPPLER_FORM_FIELD_BUTTON_GET_BUTTON_TYPE +#define HAVE_FORMS +#endif + #include #include #include @@ -40,6 +44,7 @@ #include "ev-document-security.h" #include "ev-document-thumbnails.h" #include "ev-document-transition.h" +#include "ev-document-forms.h" #include "ev-selection.h" #include "ev-attachment.h" #include "ev-image.h" @@ -86,6 +91,7 @@ static void pdf_document_security_iface_init (EvDocumentSecurityIface static void pdf_document_document_thumbnails_iface_init (EvDocumentThumbnailsIface *iface); static void pdf_document_document_links_iface_init (EvDocumentLinksIface *iface); static void pdf_document_document_images_iface_init (EvDocumentImagesIface *iface); +static void pdf_document_document_forms_iface_init (EvDocumentFormsIface *iface); static void pdf_document_document_fonts_iface_init (EvDocumentFontsIface *iface); static void pdf_document_find_iface_init (EvDocumentFindIface *iface); static void pdf_document_file_exporter_iface_init (EvFileExporterIface *iface); @@ -104,7 +110,6 @@ static EvLink *ev_link_from_action (PdfDocument *pdf_document, static void pdf_document_search_free (PdfDocumentSearch *search); static void pdf_print_context_free (PdfPrintContext *ctx); - G_DEFINE_TYPE_WITH_CODE (PdfDocument, pdf_document, G_TYPE_OBJECT, { G_IMPLEMENT_INTERFACE (EV_TYPE_DOCUMENT, @@ -117,6 +122,10 @@ G_DEFINE_TYPE_WITH_CODE (PdfDocument, pdf_document, G_TYPE_OBJECT, pdf_document_document_links_iface_init); G_IMPLEMENT_INTERFACE (EV_TYPE_DOCUMENT_IMAGES, pdf_document_document_images_iface_init); +#ifdef HAVE_FORMS + G_IMPLEMENT_INTERFACE (EV_TYPE_DOCUMENT_FORMS, + pdf_document_document_forms_iface_init); +#endif /* HAVE_FORMS */ G_IMPLEMENT_INTERFACE (EV_TYPE_DOCUMENT_FONTS, pdf_document_document_fonts_iface_init); G_IMPLEMENT_INTERFACE (EV_TYPE_DOCUMENT_FIND, @@ -1775,3 +1784,392 @@ pdf_document_new (void) { 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; +} + +#ifdef HAVE_FORMS +static EvFormField * +ev_form_field_from_poppler_field (PopplerFormField *poppler_field) +{ + EvFormField *ev_field = NULL; + gint id; + gdouble font_size; + gboolean is_read_only; + + id = poppler_form_field_get_id (poppler_field); + font_size = poppler_form_field_get_font_size (poppler_field); + is_read_only = poppler_form_field_is_read_only (poppler_field); + + switch (poppler_form_field_get_field_type (poppler_field)) { + case POPPLER_FORM_FIELD_TEXT: { + EvFormFieldText *field_text; + EvFormFieldTextType ev_text_type = EV_FORM_FIELD_TEXT_NORMAL; + + switch (poppler_form_field_text_get_text_type (poppler_field)) { + case POPPLER_FORM_TEXT_NORMAL: + ev_text_type = EV_FORM_FIELD_TEXT_NORMAL; + break; + case POPPLER_FORM_TEXT_MULTILINE: + ev_text_type = EV_FORM_FIELD_TEXT_MULTILINE; + break; + case POPPLER_FORM_TEXT_PASSWORD: + ev_text_type = EV_FORM_FIELD_TEXT_PASSWORD; + break; + case POPPLER_FORM_TEXT_FILE_SELECT: + ev_text_type = EV_FORM_FIELD_TEXT_FILE_SELECT; + break; + } + + ev_field = ev_form_field_text_new (id, ev_text_type); + field_text = EV_FORM_FIELD_TEXT (ev_field); + + field_text->do_spell_check = poppler_form_field_text_do_spell_check (poppler_field); + field_text->do_scroll = poppler_form_field_text_do_scroll (poppler_field); + field_text->is_rich_text = poppler_form_field_text_is_rich_text (poppler_field); + + field_text->text = poppler_form_field_text_get_text (poppler_field); + + } + break; + case POPPLER_FORM_FIELD_BUTTON: { + EvFormFieldButton *field_button; + EvFormFieldButtonType ev_button_type = EV_FORM_FIELD_BUTTON_PUSH; + + switch (poppler_form_field_button_get_button_type (poppler_field)) { + case POPPLER_FORM_BUTTON_PUSH: + ev_button_type = EV_FORM_FIELD_BUTTON_PUSH; + break; + case POPPLER_FORM_BUTTON_CHECK: + ev_button_type = EV_FORM_FIELD_BUTTON_CHECK; + break; + case POPPLER_FORM_BUTTON_RADIO: + ev_button_type = EV_FORM_FIELD_BUTTON_RADIO; + break; + } + + ev_field = ev_form_field_button_new (id, ev_button_type); + field_button = EV_FORM_FIELD_BUTTON (ev_field); + + field_button->state = poppler_form_field_button_get_state (poppler_field); + } + break; + case POPPLER_FORM_FIELD_CHOICE: { + EvFormFieldChoice *field_choice; + EvFormFieldChoiceType ev_choice_type = EV_FORM_FIELD_CHOICE_COMBO; + + switch (poppler_form_field_choice_get_choice_type (poppler_field)) { + case POPPLER_FORM_CHOICE_COMBO: + ev_choice_type = EV_FORM_FIELD_CHOICE_COMBO; + break; + case EV_FORM_FIELD_CHOICE_LIST: + ev_choice_type = EV_FORM_FIELD_CHOICE_LIST; + break; + } + + ev_field = ev_form_field_choice_new (id, ev_choice_type); + field_choice = EV_FORM_FIELD_CHOICE (ev_field); + + field_choice->is_editable = poppler_form_field_choice_is_editable (poppler_field); + field_choice->multi_select = poppler_form_field_choice_can_select_multiple (poppler_field); + field_choice->do_spell_check = poppler_form_field_choice_do_spell_check (poppler_field); + field_choice->commit_on_sel_change = poppler_form_field_choice_commit_on_change (poppler_field); + + /* TODO: we need poppler_form_field_choice_get_selected_items in poppler + field_choice->selected_items = poppler_form_field_choice_get_selected_items (poppler_field);*/ + if (field_choice->is_editable) + field_choice->text = poppler_form_field_choice_get_text (poppler_field); + } + break; + case POPPLER_FORM_FIELD_SIGNATURE: + /* TODO */ + ev_field = ev_form_field_signature_new (id); + break; + case POPPLER_FORM_FIELD_UNKNOWN: + break; + } + + ev_field->font_size = font_size; + ev_field->is_read_only = is_read_only; + + return ev_field; +} + +static GList * +pdf_document_forms_get_form_fields (EvDocumentForms *document, + gint page) +{ + PdfDocument *pdf_document; + PopplerPage *poppler_page; + GList *retval = NULL; + GList *fields; + GList *list; + double height; + + + pdf_document = PDF_DOCUMENT (document); + poppler_page = poppler_document_get_page (pdf_document->document, page); + fields = poppler_page_get_form_field_mapping (poppler_page); + poppler_page_get_size (poppler_page, NULL, &height); + + for (list = fields; list; list = list->next) { + PopplerFormFieldMapping *mapping; + EvFormFieldMapping *field_mapping; + + mapping = (PopplerFormFieldMapping *)list->data; + + field_mapping = g_new0 (EvFormFieldMapping, 1); + field_mapping->x1 = mapping->area.x1; + field_mapping->x2 = mapping->area.x2; + field_mapping->y1 = height - mapping->area.y2; + field_mapping->y2 = height - mapping->area.y1; + field_mapping->field = ev_form_field_from_poppler_field (mapping->field); + field_mapping->field->page = page; + + retval = g_list_prepend (retval, field_mapping); + } + poppler_page_free_form_field_mapping (fields); + g_object_unref (poppler_page); + + return g_list_reverse (retval); +} + +static gchar * +pdf_document_forms_form_field_text_get_text (EvDocumentForms *document, + EvFormField *field) + +{ + PdfDocument *pdf_document = PDF_DOCUMENT (document); + PopplerFormField *poppler_field; + gchar *text; + + poppler_field = poppler_document_get_form_field (pdf_document->document, field->id); + if (!poppler_field) + return NULL; + + text = poppler_form_field_text_get_text (poppler_field); + g_object_unref (poppler_field); + + return text; +} + +static void +pdf_document_forms_form_field_text_set_text (EvDocumentForms *document, + EvFormField *field, + const gchar *text) +{ + PdfDocument *pdf_document = PDF_DOCUMENT (document); + PopplerFormField *poppler_field; + + poppler_field = poppler_document_get_form_field (pdf_document->document, field->id); + if (!poppler_field) + return; + poppler_form_field_text_set_text (poppler_field, text); + g_object_unref (poppler_field); +} + +static void +pdf_document_forms_form_field_button_set_state (EvDocumentForms *document, + EvFormField *field, + gboolean state) +{ + PdfDocument *pdf_document = PDF_DOCUMENT (document); + PopplerFormField *poppler_field; + + poppler_field = poppler_document_get_form_field (pdf_document->document, field->id); + if (!poppler_field) + return; + + poppler_form_field_button_set_state (poppler_field, state); + g_object_unref (poppler_field); +} + +static gboolean +pdf_document_forms_form_field_button_get_state (EvDocumentForms *document, + EvFormField *field) +{ + PdfDocument *pdf_document = PDF_DOCUMENT (document); + PopplerFormField *poppler_field; + gboolean state; + + poppler_field = poppler_document_get_form_field (pdf_document->document, field->id); + if (!poppler_field) + return FALSE; + + state = poppler_form_field_button_get_state (poppler_field); + g_object_unref (poppler_field); + + return state; +} + +static gchar * +pdf_document_forms_form_field_choice_get_item (EvDocumentForms *document, + EvFormField *field, + gint index) +{ + PdfDocument *pdf_document = PDF_DOCUMENT (document); + PopplerFormField *poppler_field; + gchar *text; + + poppler_field = poppler_document_get_form_field (pdf_document->document, field->id); + if (!poppler_field) + return NULL; + + text = poppler_form_field_choice_get_item (poppler_field, index); + g_object_unref (poppler_field); + + return text; +} + +static int +pdf_document_forms_form_field_choice_get_n_items (EvDocumentForms *document, + EvFormField *field) +{ + PdfDocument *pdf_document = PDF_DOCUMENT (document); + PopplerFormField *poppler_field; + gint n_items; + + poppler_field = poppler_document_get_form_field (pdf_document->document, field->id); + if (!poppler_field) + return -1; + + n_items = poppler_form_field_choice_get_n_items (poppler_field); + g_object_unref (poppler_field); + + return n_items; +} + +static gboolean +pdf_document_forms_form_field_choice_is_item_selected (EvDocumentForms *document, + EvFormField *field, + gint index) +{ + PdfDocument *pdf_document = PDF_DOCUMENT (document); + PopplerFormField *poppler_field; + gboolean selected; + + poppler_field = poppler_document_get_form_field (pdf_document->document, field->id); + if (!poppler_field) + return FALSE; + + selected = poppler_form_field_choice_is_item_selected (poppler_field, index); + g_object_unref (poppler_field); + + return selected; +} + +static void +pdf_document_forms_form_field_choice_select_item (EvDocumentForms *document, + EvFormField *field, + gint index) +{ + PdfDocument *pdf_document = PDF_DOCUMENT (document); + PopplerFormField *poppler_field; + + poppler_field = poppler_document_get_form_field (pdf_document->document, field->id); + if (!poppler_field) + return; + + poppler_form_field_choice_select_item (poppler_field, index); + g_object_unref (poppler_field); +} + +static void +pdf_document_forms_form_field_choice_toggle_item (EvDocumentForms *document, + EvFormField *field, + gint index) +{ + PdfDocument *pdf_document = PDF_DOCUMENT (document); + PopplerFormField *poppler_field; + + poppler_field = poppler_document_get_form_field (pdf_document->document, field->id); + if (!poppler_field) + return; + + poppler_form_field_choice_toggle_item (poppler_field, index); + g_object_unref (poppler_field); +} + +static void +pdf_document_forms_form_field_choice_unselect_all (EvDocumentForms *document, + EvFormField *field) +{ + PdfDocument *pdf_document = PDF_DOCUMENT (document); + PopplerFormField *poppler_field; + + poppler_field = poppler_document_get_form_field (pdf_document->document, field->id); + if (!poppler_field) + return; + + poppler_form_field_choice_unselect_all (poppler_field); + g_object_unref (poppler_field); +} + +static void +pdf_document_forms_form_field_choice_set_text (EvDocumentForms *document, + EvFormField *field, + const gchar *text) +{ + PdfDocument *pdf_document = PDF_DOCUMENT (document); + PopplerFormField *poppler_field; + + poppler_field = poppler_document_get_form_field (pdf_document->document, field->id); + if (!poppler_field) + return; + + poppler_form_field_choice_set_text (poppler_field, text); + g_object_unref (poppler_field); +} + +static gchar * +pdf_document_forms_form_field_choice_get_text (EvDocumentForms *document, + EvFormField *field) +{ + PdfDocument *pdf_document = PDF_DOCUMENT (document); + PopplerFormField *poppler_field; + gchar *text; + + poppler_field = poppler_document_get_form_field (pdf_document->document, field->id); + if (!poppler_field) + return NULL; + + text = poppler_form_field_choice_get_text (poppler_field); + g_object_unref (poppler_field); + + return text; +} + +static void +pdf_document_document_forms_iface_init (EvDocumentFormsIface *iface) +{ + iface->get_form_fields = pdf_document_forms_get_form_fields; + iface->form_field_text_get_text = pdf_document_forms_form_field_text_get_text; + iface->form_field_text_set_text = pdf_document_forms_form_field_text_set_text; + iface->form_field_button_set_state = pdf_document_forms_form_field_button_set_state; + iface->form_field_button_get_state = pdf_document_forms_form_field_button_get_state; + iface->form_field_choice_get_item = pdf_document_forms_form_field_choice_get_item; + iface->form_field_choice_get_n_items = pdf_document_forms_form_field_choice_get_n_items; + iface->form_field_choice_is_item_selected = pdf_document_forms_form_field_choice_is_item_selected; + iface->form_field_choice_select_item = pdf_document_forms_form_field_choice_select_item; + iface->form_field_choice_toggle_item = pdf_document_forms_form_field_choice_toggle_item; + iface->form_field_choice_unselect_all = pdf_document_forms_form_field_choice_unselect_all; + iface->form_field_choice_set_text = pdf_document_forms_form_field_choice_set_text; + iface->form_field_choice_get_text = pdf_document_forms_form_field_choice_get_text; +} +#endif /* HAVE_FORMS */ diff --git a/configure.ac b/configure.ac index 0846107b..0a0e97a9 100644 --- a/configure.ac +++ b/configure.ac @@ -247,6 +247,9 @@ if test "x$enable_pdf" = "xyes"; then evince_save_LIBS=$LIBS LIBS="$LIBS $FRONTEND_LIBS" AC_CHECK_FUNCS(poppler_page_render) + dnl we need latest poppler cvs head, + dnl this function was the last to be added + AC_CHECK_FUNCS(poppler_form_field_button_get_button_type) LIBS=$evince_save_LIBS PKG_CHECK_MODULES(CAIRO_PDF, cairo-pdf, enable_cairo_pdf=yes, enable_cairo_pdf=no) diff --git a/libdocument/Makefile.am b/libdocument/Makefile.am index 73340ff1..f96d0197 100644 --- a/libdocument/Makefile.am +++ b/libdocument/Makefile.am @@ -48,6 +48,10 @@ libevbackend_la_SOURCES= \ ev-document-info.h \ ev-document-transition.h \ ev-document-transition.c \ + ev-document-forms.h \ + ev-document-forms.c \ + ev-form-field.h \ + ev-form-field.c \ ev-file-exporter.c \ ev-file-exporter.h \ ev-file-helpers.c \ diff --git a/libdocument/ev-document-forms.c b/libdocument/ev-document-forms.c new file mode 100644 index 00000000..cdefb467 --- /dev/null +++ b/libdocument/ev-document-forms.c @@ -0,0 +1,165 @@ +/* ev-document-forms.c + * this file is part of evince, a gnome document viewer + * + * Copyright (C) 2007 Carlos Garcia Campos + * + * 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. + */ + +#include "ev-document-forms.h" + +GType +ev_document_forms_get_type (void) +{ + static GType type = 0; + + if (G_UNLIKELY (type == 0)) { + const GTypeInfo our_info = { + sizeof (EvDocumentFormsIface), + NULL, + NULL, + }; + + type = g_type_register_static (G_TYPE_INTERFACE, + "EvDocumentForms", + &our_info, (GTypeFlags)0); + } + + return type; +} + +GList * +ev_document_forms_get_form_fields (EvDocumentForms *document_forms, + gint page) +{ + EvDocumentFormsIface *iface = EV_DOCUMENT_FORMS_GET_IFACE (document_forms); + + return iface->get_form_fields (document_forms, page); +} + +gchar * +ev_document_forms_form_field_text_get_text (EvDocumentForms *document_forms, + EvFormField *field) +{ + EvDocumentFormsIface *iface = EV_DOCUMENT_FORMS_GET_IFACE (document_forms); + + return iface->form_field_text_get_text (document_forms, field); +} + +void +ev_document_forms_form_field_text_set_text (EvDocumentForms *document_forms, + EvFormField *field, + const gchar *text) +{ + EvDocumentFormsIface *iface = EV_DOCUMENT_FORMS_GET_IFACE (document_forms); + + iface->form_field_text_set_text (document_forms, field, text); +} + +gboolean +ev_document_forms_form_field_button_get_state (EvDocumentForms *document_forms, + EvFormField *field) +{ + EvDocumentFormsIface *iface = EV_DOCUMENT_FORMS_GET_IFACE (document_forms); + + return iface->form_field_button_get_state (document_forms, field); +} + +void +ev_document_forms_form_field_button_set_state (EvDocumentForms *document_forms, + EvFormField *field, + gboolean state) +{ + EvDocumentFormsIface *iface = EV_DOCUMENT_FORMS_GET_IFACE (document_forms); + + iface->form_field_button_set_state (document_forms, field, state); +} + +gchar * +ev_document_forms_form_field_choice_get_item (EvDocumentForms *document_forms, + EvFormField *field, + gint index) +{ + EvDocumentFormsIface *iface = EV_DOCUMENT_FORMS_GET_IFACE (document_forms); + + return iface->form_field_choice_get_item (document_forms, field, index); +} + +gint +ev_document_forms_form_field_choice_get_n_items (EvDocumentForms *document_forms, + EvFormField *field) +{ + EvDocumentFormsIface *iface = EV_DOCUMENT_FORMS_GET_IFACE (document_forms); + + return iface->form_field_choice_get_n_items (document_forms, field); +} + +gboolean +ev_document_forms_form_field_choice_is_item_selected (EvDocumentForms *document_forms, + EvFormField *field, + gint index) +{ + EvDocumentFormsIface *iface = EV_DOCUMENT_FORMS_GET_IFACE (document_forms); + + return iface->form_field_choice_is_item_selected (document_forms, field, index); +} + +void +ev_document_forms_form_field_choice_select_item (EvDocumentForms *document_forms, + EvFormField *field, + gint index) +{ + EvDocumentFormsIface *iface = EV_DOCUMENT_FORMS_GET_IFACE (document_forms); + + iface->form_field_choice_select_item (document_forms, field, index); +} + +void +ev_document_forms_form_field_choice_toggle_item (EvDocumentForms *document_forms, + EvFormField *field, + gint index) +{ + EvDocumentFormsIface *iface = EV_DOCUMENT_FORMS_GET_IFACE (document_forms); + + iface->form_field_choice_toggle_item (document_forms, field, index); +} + +void +ev_document_forms_form_field_choice_unselect_all (EvDocumentForms *document_forms, + EvFormField *field) +{ + EvDocumentFormsIface *iface = EV_DOCUMENT_FORMS_GET_IFACE (document_forms); + + iface->form_field_choice_unselect_all (document_forms, field); +} + +void +ev_document_forms_form_field_choice_set_text (EvDocumentForms *document_forms, + EvFormField *field, + const gchar *text) +{ + EvDocumentFormsIface *iface = EV_DOCUMENT_FORMS_GET_IFACE (document_forms); + + iface->form_field_choice_set_text (document_forms, field, text); +} + +gchar * +ev_document_forms_form_field_choice_get_text (EvDocumentForms *document_forms, + EvFormField *field) +{ + EvDocumentFormsIface *iface = EV_DOCUMENT_FORMS_GET_IFACE (document_forms); + + return iface->form_field_choice_get_text (document_forms, field); +} diff --git a/libdocument/ev-document-forms.h b/libdocument/ev-document-forms.h new file mode 100644 index 00000000..a1b192da --- /dev/null +++ b/libdocument/ev-document-forms.h @@ -0,0 +1,121 @@ +/* ev-document-forms.h + * this file is part of evince, a gnome document viewer + * + * Copyright (C) 2007 Carlos Garcia Campos + * + * 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_DOCUMENT_FORMS_H +#define EV_DOCUMENT_FORMS_H + +#include + +#include "ev-document.h" +#include "ev-form-field.h" + +G_BEGIN_DECLS + +#define EV_TYPE_DOCUMENT_FORMS (ev_document_forms_get_type ()) +#define EV_DOCUMENT_FORMS(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), EV_TYPE_DOCUMENT_FORMS, EvDocumentForms)) +#define EV_DOCUMENT_FORMS_IFACE(k) (G_TYPE_CHECK_CLASS_CAST((k), EV_TYPE_DOCUMENT_FORMS, EvDocumentFormsIface)) +#define EV_IS_DOCUMENT_FORMS(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), EV_TYPE_DOCUMENT_FORMS)) +#define EV_IS_DOCUMENT_FORMS_IFACE(k) (G_TYPE_CHECK_CLASS_TYPE ((k), EV_TYPE_DOCUMENT_FORMS)) +#define EV_DOCUMENT_FORMS_GET_IFACE(inst) (G_TYPE_INSTANCE_GET_INTERFACE ((inst), EV_TYPE_DOCUMENT_FORMS, EvDocumentFormsIface)) + +typedef struct _EvDocumentForms EvDocumentForms; +typedef struct _EvDocumentFormsIface EvDocumentFormsIface; + +struct _EvDocumentFormsIface +{ + GTypeInterface base_iface; + + /* Methods */ + GList *(* get_form_fields) (EvDocumentForms *document_forms, + gint page); + gchar *(* form_field_text_get_text) (EvDocumentForms *document_forms, + EvFormField *field); + void (* form_field_text_set_text) (EvDocumentForms *document_forms, + EvFormField *field, + const gchar *text); + gboolean (* form_field_button_get_state) (EvDocumentForms *document_forms, + EvFormField *field); + void (* form_field_button_set_state) (EvDocumentForms *document_forms, + EvFormField *field, + gboolean state); + gchar *(* form_field_choice_get_item) (EvDocumentForms *document_forms, + EvFormField *field, + gint index); + gint (* form_field_choice_get_n_items) (EvDocumentForms *document_forms, + EvFormField *field); + gboolean (* form_field_choice_is_item_selected) (EvDocumentForms *document_forms, + EvFormField *field, + gint index); + void (* form_field_choice_select_item) (EvDocumentForms *document_forms, + EvFormField *field, + gint index); + void (* form_field_choice_toggle_item) (EvDocumentForms *document_forms, + EvFormField *field, + gint index); + void (* form_field_choice_unselect_all) (EvDocumentForms *document_forms, + EvFormField *field); + void (* form_field_choice_set_text) (EvDocumentForms *document_forms, + EvFormField *field, + const gchar *text); + gchar *(* form_field_choice_get_text) (EvDocumentForms *document_forms, + EvFormField *field); +}; + +GType ev_document_forms_get_type (void) G_GNUC_CONST; +GList *ev_document_forms_get_form_fields (EvDocumentForms *document_forms, + gint page); + +gchar *ev_document_forms_form_field_text_get_text (EvDocumentForms *document_forms, + EvFormField *field); +void ev_document_forms_form_field_text_set_text (EvDocumentForms *document_forms, + EvFormField *field, + const gchar *text); + +gboolean ev_document_forms_form_field_button_get_state (EvDocumentForms *document_forms, + EvFormField *field); +void ev_document_forms_form_field_button_set_state (EvDocumentForms *document_forms, + EvFormField *field, + gboolean state); + +gchar *ev_document_forms_form_field_choice_get_item (EvDocumentForms *document_forms, + EvFormField *field, + gint index); +gint ev_document_forms_form_field_choice_get_n_items (EvDocumentForms *document_forms, + EvFormField *field); +gboolean ev_document_forms_form_field_choice_is_item_selected (EvDocumentForms *document_forms, + EvFormField *field, + gint index); +void ev_document_forms_form_field_choice_select_item (EvDocumentForms *document_forms, + EvFormField *field, + gint index); +void ev_document_forms_form_field_choice_toggle_item (EvDocumentForms *document_forms, + EvFormField *field, + gint index); +void ev_document_forms_form_field_choice_unselect_all (EvDocumentForms *document_forms, + EvFormField *field); +void ev_document_forms_form_field_choice_set_text (EvDocumentForms *document_forms, + EvFormField *field, + const gchar *text); +gchar *ev_document_forms_form_field_choice_get_text (EvDocumentForms *document_forms, + EvFormField *field); + +G_END_DECLS + +#endif /* EV_DOCUMENT_FORMS_H */ diff --git a/libdocument/ev-document.c b/libdocument/ev-document.c index f22f55f3..e0ce69fd 100644 --- a/libdocument/ev-document.c +++ b/libdocument/ev-document.c @@ -283,3 +283,6 @@ ev_rect_cmp (EvRectangle *a, (ABS (a->x2 - b->x2) < EPSILON) && (ABS (a->y2 - b->y2) < EPSILON)); } + + + diff --git a/libdocument/ev-document.h b/libdocument/ev-document.h index ce887fc6..e83295f0 100644 --- a/libdocument/ev-document.h +++ b/libdocument/ev-document.h @@ -134,8 +134,6 @@ cairo_surface_t *ev_document_render (EvDocument *document, gint ev_rect_cmp (EvRectangle *a, EvRectangle *b); - - G_END_DECLS #endif /* EV_DOCUMENT_H */ diff --git a/libdocument/ev-form-field.c b/libdocument/ev-form-field.c new file mode 100644 index 00000000..b3cc7919 --- /dev/null +++ b/libdocument/ev-form-field.c @@ -0,0 +1,269 @@ +/* -*- 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) 2007 Carlos Garcia Campos + * 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. + */ + +#include "ev-form-field.h" + +static void ev_form_field_init (EvFormField *field); +static void ev_form_field_class_init (EvFormFieldClass *klass); +static void ev_form_field_text_init (EvFormFieldText *field_text); +static void ev_form_field_text_class_init (EvFormFieldTextClass *klass); +static void ev_form_field_button_init (EvFormFieldButton *field_button); +static void ev_form_field_button_class_init (EvFormFieldButtonClass *klass); +static void ev_form_field_choice_init (EvFormFieldChoice *field_choice); +static void ev_form_field_choice_class_init (EvFormFieldChoiceClass *klass); +static void ev_form_field_signature_init (EvFormFieldSignature *field_choice); +static void ev_form_field_signature_class_init (EvFormFieldSignatureClass *klass); + +G_DEFINE_ABSTRACT_TYPE (EvFormField, ev_form_field, G_TYPE_OBJECT) +G_DEFINE_TYPE (EvFormFieldText, ev_form_field_text, EV_TYPE_FORM_FIELD) +G_DEFINE_TYPE (EvFormFieldButton, ev_form_field_button, EV_TYPE_FORM_FIELD) +G_DEFINE_TYPE (EvFormFieldChoice, ev_form_field_choice, EV_TYPE_FORM_FIELD) +G_DEFINE_TYPE (EvFormFieldSignature, ev_form_field_signature, EV_TYPE_FORM_FIELD) + +static void +ev_form_field_init (EvFormField *field) +{ + field->page = -1; + field->changed = FALSE; + field->is_read_only = FALSE; +} + +static void +ev_form_field_class_init (EvFormFieldClass *klass) +{ +} + +static void +ev_form_field_text_finalize (GObject *object) +{ + EvFormFieldText *field_text = EV_FORM_FIELD_TEXT (object); + + if (field_text->text) { + g_free (field_text->text); + field_text->text = NULL; + } + + (* G_OBJECT_CLASS (ev_form_field_text_parent_class)->finalize) (object); +} + +static void +ev_form_field_text_init (EvFormFieldText *field_text) +{ +} + +static void +ev_form_field_text_class_init (EvFormFieldTextClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + object_class->finalize = ev_form_field_text_finalize; +} + +static void +ev_form_field_button_init (EvFormFieldButton *field_button) +{ +} + +static void +ev_form_field_button_class_init (EvFormFieldButtonClass *klass) +{ +} + +static void +ev_form_field_choice_finalize (GObject *object) +{ + EvFormFieldChoice *field_choice = EV_FORM_FIELD_CHOICE (object); + + if (field_choice->selected_items) { + g_list_free (field_choice->selected_items); + field_choice->selected_items = NULL; + } + + if (field_choice->text) { + g_free (field_choice->text); + field_choice->text = NULL; + } + + (* G_OBJECT_CLASS (ev_form_field_choice_parent_class)->finalize) (object); +} + +static void +ev_form_field_choice_init (EvFormFieldChoice *field_choice) +{ +} + +static void +ev_form_field_choice_class_init (EvFormFieldChoiceClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + object_class->finalize = ev_form_field_choice_finalize; +} + +static void +ev_form_field_signature_init (EvFormFieldSignature *field_signature) +{ +} + +static void +ev_form_field_signature_class_init (EvFormFieldSignatureClass *klass) +{ +} + +EvFormField * +ev_form_field_text_new (gint id, + EvFormFieldTextType type) +{ + EvFormField *field; + + g_return_val_if_fail (id >= 0, NULL); + g_return_val_if_fail (type >= EV_FORM_FIELD_TEXT_NORMAL && + type <= EV_FORM_FIELD_TEXT_FILE_SELECT, NULL); + + field = EV_FORM_FIELD (g_object_new (EV_TYPE_FORM_FIELD_TEXT, NULL)); + field->id = id; + EV_FORM_FIELD_TEXT (field)->type = type; + + return field; +} + +EvFormField * +ev_form_field_button_new (gint id, + EvFormFieldButtonType type) +{ + EvFormField *field; + + g_return_val_if_fail (id >= 0, NULL); + g_return_val_if_fail (type >= EV_FORM_FIELD_BUTTON_PUSH && + type <= EV_FORM_FIELD_BUTTON_RADIO, NULL); + + field = EV_FORM_FIELD (g_object_new (EV_TYPE_FORM_FIELD_BUTTON, NULL)); + field->id = id; + EV_FORM_FIELD_BUTTON (field)->type = type; + + return field; +} + +EvFormField * +ev_form_field_choice_new (gint id, + EvFormFieldChoiceType type) +{ + EvFormField *field; + + g_return_val_if_fail (id >= 0, NULL); + g_return_val_if_fail (type >= EV_FORM_FIELD_CHOICE_COMBO && + type <= EV_FORM_FIELD_CHOICE_LIST, NULL); + + field = EV_FORM_FIELD (g_object_new (EV_TYPE_FORM_FIELD_CHOICE, NULL)); + field->id = id; + EV_FORM_FIELD_CHOICE (field)->type = type; + + return field; +} + +EvFormField * +ev_form_field_signature_new (gint id) +{ + EvFormField *field; + + g_return_val_if_fail (id >= 0, NULL); + + field = EV_FORM_FIELD (g_object_new (EV_TYPE_FORM_FIELD_SIGNATURE, NULL)); + field->id = id; + + return field; +} + +/* EvFormFieldMapping */ +static void +ev_form_field_mapping_free_foreach (EvFormFieldMapping *mapping) +{ + g_object_unref (mapping->field); + g_free (mapping); +} + +void +ev_form_field_mapping_free (GList *field_mapping) +{ + if (!field_mapping) + return; + + g_list_foreach (field_mapping, (GFunc)ev_form_field_mapping_free_foreach, NULL); + g_list_free (field_mapping); +} + +EvFormField * +ev_form_field_mapping_find (GList *field_mapping, + gdouble x, + gdouble y) +{ + GList *list; + + for (list = field_mapping; list; list = list->next) { + EvFormFieldMapping *mapping = list->data; + + if ((x >= mapping->x1) && + (y >= mapping->y1) && + (x <= mapping->x2) && + (y <= mapping->y2)) { + return mapping->field; + } + } + + return NULL; +} + +void +ev_form_field_mapping_get_area (GList *field_mapping, + EvFormField *field, + EvRectangle *area) +{ + GList *list; + + for (list = field_mapping; list; list = list->next) { + EvFormFieldMapping *mapping = list->data; + + if (mapping->field->id == field->id) { + area->x1 = mapping->x1; + area->y1 = mapping->y1; + area->x2 = mapping->x2; + area->y2 = mapping->y2; + + break; + } + } +} + +EvFormField * +ev_form_field_mapping_find_by_id (GList *field_mapping, + gint id) +{ + GList *list; + + for (list = field_mapping; list; list = list->next) { + EvFormFieldMapping *mapping = list->data; + + if (id == mapping->field->id) + return mapping->field; + } + + return NULL; +} diff --git a/libdocument/ev-form-field.h b/libdocument/ev-form-field.h new file mode 100644 index 00000000..14059998 --- /dev/null +++ b/libdocument/ev-form-field.h @@ -0,0 +1,230 @@ +/* -*- 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 + +#include "ev-document.h" + +G_BEGIN_DECLS + +#define EV_TYPE_FORM_FIELD (ev_form_field_get_type()) +#define EV_FORM_FIELD(object) (G_TYPE_CHECK_INSTANCE_CAST((object), EV_TYPE_FORM_FIELD, EvFormField)) +#define EV_FORM_FIELD_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), EV_TYPE_FORM_FIELD, EvFormFieldClass)) +#define EV_IS_FORM_FIELD(object) (G_TYPE_CHECK_INSTANCE_TYPE((object), EV_TYPE_FORM_FIELD)) +#define EV_IS_FORM_FIELD_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), EV_TYPE_FORM_FIELD)) +#define EV_FORM_FIELD_GET_CLASS(object) (G_TYPE_INSTANCE_GET_CLASS((object), EV_TYPE_FORM_FIELD, EvFormFieldClass)) + +#define EV_TYPE_FORM_FIELD_TEXT (ev_form_field_text_get_type()) +#define EV_FORM_FIELD_TEXT(object) (G_TYPE_CHECK_INSTANCE_CAST((object), EV_TYPE_FORM_FIELD_TEXT, EvFormFieldText)) +#define EV_FORM_FIELD_TEXT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), EV_TYPE_FORM_FIELD_TEXT, EvFormFieldTextClass)) +#define EV_IS_FORM_FIELD_TEXT(object) (G_TYPE_CHECK_INSTANCE_TYPE((object), EV_TYPE_FORM_FIELD_TEXT)) +#define EV_IS_FORM_FIELD_TEXT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), EV_TYPE_FORM_FIELD_TEXT)) +#define EV_FORM_FIELD_TEXT_GET_CLASS(object) (G_TYPE_INSTANCE_GET_CLASS((object), EV_TYPE_FORM_FIELD_TEXT, EvFormFieldTextClass)) + +#define EV_TYPE_FORM_FIELD_BUTTON (ev_form_field_button_get_type()) +#define EV_FORM_FIELD_BUTTON(object) (G_TYPE_CHECK_INSTANCE_CAST((object), EV_TYPE_FORM_FIELD_BUTTON, EvFormFieldButton)) +#define EV_FORM_FIELD_BUTTON_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), EV_TYPE_FORM_FIELD_BUTTON, EvFormFieldButtonClass)) +#define EV_IS_FORM_FIELD_BUTTON(object) (G_TYPE_CHECK_INSTANCE_TYPE((object), EV_TYPE_FORM_FIELD_BUTTON)) +#define EV_IS_FORM_FIELD_BUTTON_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), EV_TYPE_FORM_FIELD_BUTTON)) +#define EV_FORM_FIELD_BUTTON_GET_CLASS(object) (G_TYPE_INSTANCE_GET_CLASS((object), EV_TYPE_FORM_FIELD_BUTTON, EvFormFieldButtonClass)) + +#define EV_TYPE_FORM_FIELD_CHOICE (ev_form_field_choice_get_type()) +#define EV_FORM_FIELD_CHOICE(object) (G_TYPE_CHECK_INSTANCE_CAST((object), EV_TYPE_FORM_FIELD_CHOICE, EvFormFieldChoice)) +#define EV_FORM_FIELD_CHOICE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), EV_TYPE_FORM_FIELD_CHOICE, EvFormFieldChoiceClass)) +#define EV_IS_FORM_FIELD_CHOICE(object) (G_TYPE_CHECK_INSTANCE_TYPE((object), EV_TYPE_FORM_FIELD_CHOICE)) +#define EV_IS_FORM_FIELD_CHOICE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), EV_TYPE_FORM_FIELD_CHOICE)) +#define EV_FORM_FIELD_CHOICE_GET_CLASS(object) (G_TYPE_INSTANCE_GET_CLASS((object), EV_TYPE_FORM_FIELD_CHOICE, EvFormFieldChoiceClass)) + +#define EV_TYPE_FORM_FIELD_SIGNATURE (ev_form_field_signature_get_type()) +#define EV_FORM_FIELD_SIGNATURE(object) (G_TYPE_CHECK_INSTANCE_CAST((object), EV_TYPE_FORM_FIELD_SIGNATURE, EvFormFieldSignature)) +#define EV_FORM_FIELD_SIGNATURE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), EV_TYPE_FORM_FIELD_SIGNATURE, EvFormFieldSignatureClass)) +#define EV_IS_FORM_FIELD_SIGNATURE(object) (G_TYPE_CHECK_INSTANCE_TYPE((object), EV_TYPE_FORM_FIELD_SIGNATURE)) +#define EV_IS_FORM_FIELD_SIGNATURE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), EV_TYPE_FORM_FIELD_SIGNATURE)) +#define EV_FORM_FIELD_SIGNATURE_GET_CLASS(object) (G_TYPE_INSTANCE_GET_CLASS((object), EV_TYPE_FORM_FIELD_SIGNATURE, EvFormFieldSignatureClass)) + +typedef struct _EvFormField EvFormField; +typedef struct _EvFormFieldClass EvFormFieldClass; + +typedef struct _EvFormFieldText EvFormFieldText; +typedef struct _EvFormFieldTextClass EvFormFieldTextClass; + +typedef struct _EvFormFieldButton EvFormFieldButton; +typedef struct _EvFormFieldButtonClass EvFormFieldButtonClass; + +typedef struct _EvFormFieldChoice EvFormFieldChoice; +typedef struct _EvFormFieldChoiceClass EvFormFieldChoiceClass; + +typedef struct _EvFormFieldSignature EvFormFieldSignature; +typedef struct _EvFormFieldSignatureClass EvFormFieldSignatureClass; + +typedef enum +{ + EV_FORM_FIELD_TEXT_NORMAL, + EV_FORM_FIELD_TEXT_MULTILINE, + EV_FORM_FIELD_TEXT_PASSWORD, + EV_FORM_FIELD_TEXT_FILE_SELECT +} EvFormFieldTextType; + +typedef enum +{ + EV_FORM_FIELD_BUTTON_PUSH, + EV_FORM_FIELD_BUTTON_CHECK, + EV_FORM_FIELD_BUTTON_RADIO +} EvFormFieldButtonType; + +typedef enum +{ + EV_FORM_FIELD_CHOICE_COMBO, + EV_FORM_FIELD_CHOICE_LIST +} EvFormFieldChoiceType; + +struct _EvFormField +{ + GObject parent; + + gint id; + gboolean is_read_only; + gdouble font_size; + + gint page; + gboolean changed; +}; + +struct _EvFormFieldClass +{ + GObjectClass parent_class; +}; + +struct _EvFormFieldText +{ + EvFormField partent; + + EvFormFieldTextType type; + + gboolean do_spell_check : 1; + gboolean do_scroll : 1; + gboolean comb : 1; + gboolean is_rich_text : 1; + + gint max_len; + gchar *text; +}; + +struct _EvFormFieldTextClass +{ + EvFormFieldClass partent_class; +}; + +struct _EvFormFieldButton +{ + EvFormField partent; + + EvFormFieldButtonType type; + + gboolean state; +}; + +struct _EvFormFieldButtonClass +{ + EvFormFieldClass partent_class; +}; + +struct _EvFormFieldChoice +{ + EvFormField partent; + + EvFormFieldChoiceType type; + + gboolean multi_select : 1; + gboolean is_editable : 1; + gboolean do_spell_check : 1; + gboolean commit_on_sel_change : 1; + + GList *selected_items; + gchar *text; +}; + +struct _EvFormFieldChoiceClass +{ + EvFormFieldClass partent_class; +}; + +struct _EvFormFieldSignature +{ + EvFormField partent; + + /* TODO */ +}; + +struct _EvFormFieldSignatureClass +{ + EvFormFieldClass partent_class; +}; + +/* EvFormField base class */ +GType ev_form_field_get_type (void) G_GNUC_CONST; + +/* EvFormFieldText */ +GType ev_form_field_text_get_type (void) G_GNUC_CONST; +EvFormField *ev_form_field_text_new (gint id, + EvFormFieldTextType type); + +/* EvFormFieldButton */ +GType ev_form_field_button_get_type (void) G_GNUC_CONST; +EvFormField *ev_form_field_button_new (gint id, + EvFormFieldButtonType type); + +/* EvFormFieldChoice */ +GType ev_form_field_choice_get_type (void) G_GNUC_CONST; +EvFormField *ev_form_field_choice_new (gint id, + EvFormFieldChoiceType type); + +/* EvFormFieldSignature */ +GType ev_form_field_signature_get_type (void) G_GNUC_CONST; +EvFormField *ev_form_field_signature_new (gint id); + + +/* FormField Mapping stuff */ +typedef struct _EvFormFieldMapping EvFormFieldMapping; +struct _EvFormFieldMapping { + EvFormField *field; + gdouble x1; + gdouble y1; + gdouble x2; + gdouble y2; +}; + +void ev_form_field_mapping_free (GList *field_mapping); +EvFormField *ev_form_field_mapping_find (GList *field_mapping, + gdouble x, + gdouble y); +void ev_form_field_mapping_get_area (GList *field_mapping, + EvFormField *field, + EvRectangle *area); +EvFormField *ev_form_field_mapping_find_by_id (GList *form_field_mapping, + gint id); + +G_END_DECLS + +#endif /* !EV_FORM_FIELD_H */ + diff --git a/shell/ev-jobs.c b/shell/ev-jobs.c index d9cdac8a..0f0a0daf 100644 --- a/shell/ev-jobs.c +++ b/shell/ev-jobs.c @@ -3,6 +3,7 @@ #include "ev-document-thumbnails.h" #include "ev-document-links.h" #include "ev-document-images.h" +#include "ev-document-forms.h" #include "ev-document-factory.h" #include "ev-document-misc.h" #include "ev-file-helpers.h" @@ -265,6 +266,7 @@ ev_job_render_new (EvDocument *document, EvRectangle *selection_points, GdkColor *text, GdkColor *base, + gboolean include_forms, gboolean include_links, gboolean include_images, gboolean include_text, @@ -284,6 +286,7 @@ ev_job_render_new (EvDocument *document, job->target_height = height; job->text = *text; job->base = *base; + job->include_forms = include_forms; job->include_links = include_links; job->include_images = include_images; job->include_text = include_text; @@ -330,6 +333,7 @@ ev_job_render_run (EvJobRender *job) ev_document_fc_mutex_lock (); job->surface = ev_document_render (EV_JOB (job)->document, job->rc); + 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), @@ -338,6 +342,10 @@ ev_job_render_run (EvJobRender *job) job->image_mapping = ev_document_images_get_images (EV_DOCUMENT_IMAGES (EV_JOB (job)->document), job->rc->page); + if (job->include_forms && EV_IS_DOCUMENT_FORMS (EV_JOB (job)->document)) + job->form_field_mapping = + ev_document_forms_get_form_fields (EV_DOCUMENT_FORMS (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), diff --git a/shell/ev-jobs.h b/shell/ev-jobs.h index fc681d37..05231989 100644 --- a/shell/ev-jobs.h +++ b/shell/ev-jobs.h @@ -126,6 +126,7 @@ struct _EvJobRender GList *link_mapping; GdkRegion *text_mapping; GList *image_mapping; + GList *form_field_mapping; cairo_surface_t *selection; GdkRegion *selection_region; @@ -133,6 +134,7 @@ struct _EvJobRender GdkColor base; GdkColor text; + gint include_forms : 1; gint include_links : 1; gint include_text : 1; gint include_selection : 1; @@ -223,6 +225,7 @@ EvJob *ev_job_render_new (EvDocument *document, EvRectangle *selection_points, GdkColor *text, GdkColor *base, + gboolean include_forms, gboolean include_links, gboolean include_images, gboolean include_text, diff --git a/shell/ev-pixbuf-cache.c b/shell/ev-pixbuf-cache.c index 20446b10..6cc0580b 100644 --- a/shell/ev-pixbuf-cache.c +++ b/shell/ev-pixbuf-cache.c @@ -4,6 +4,7 @@ #include "ev-selection.h" #include "ev-document-images.h" #include "ev-image.h" +#include "ev-form-field.h" typedef struct _CacheJobInfo { @@ -14,6 +15,7 @@ typedef struct _CacheJobInfo cairo_surface_t *surface; GList *link_mapping; GList *image_mapping; + GList *form_field_mapping; GdkRegion *text_mapping; /* Selection data. @@ -161,6 +163,10 @@ dispose_cache_job_info (CacheJobInfo *job_info, ev_image_mapping_free (job_info->image_mapping); job_info->image_mapping = 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->text_mapping) { gdk_region_destroy (job_info->text_mapping); job_info->text_mapping = NULL; @@ -323,6 +329,7 @@ move_one_job (CacheJobInfo *job_info, job_info->surface = NULL; job_info->link_mapping = NULL; job_info->image_mapping = NULL; + job_info->form_field_mapping = NULL; if (new_priority != priority && target_page->job) { ev_job_queue_update_job (target_page->job, new_priority); @@ -432,6 +439,12 @@ copy_job_to_job_info (EvJobRender *job_render, job_info->image_mapping = job_render->image_mapping; } + if (job_render->include_forms) { + 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_text) { if (job_info->text_mapping) gdk_region_destroy (job_info->text_mapping); @@ -540,6 +553,7 @@ add_job_if_needed (EvPixbufCache *pixbuf_cache, gfloat scale, EvJobPriority priority) { + gboolean include_forms = FALSE; gboolean include_links = FALSE; gboolean include_text = FALSE; gboolean include_selection = FALSE; @@ -572,6 +586,8 @@ add_job_if_needed (EvPixbufCache *pixbuf_cache, include_links = TRUE; if (job_info->image_mapping == NULL) include_images = TRUE; + if (job_info->form_field_mapping == NULL) + include_forms = TRUE; if (job_info->text_mapping == NULL) include_text = TRUE; if (new_selection_surface_needed (pixbuf_cache, job_info, page, scale)) { @@ -587,6 +603,7 @@ add_job_if_needed (EvPixbufCache *pixbuf_cache, width, height, &(job_info->target_points), text, base, + include_forms, include_links, include_images, include_text, @@ -1102,3 +1119,101 @@ ev_pixbuf_cache_get_selection_list (EvPixbufCache *pixbuf_cache) 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_links = FALSE; + gboolean include_text = FALSE; + gboolean include_selection = FALSE; + gboolean include_images = TRUE; + gboolean include_forms = 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 */ + if (job_info->link_mapping == NULL) + include_links = TRUE; + if (job_info->image_mapping == NULL) + include_images = TRUE; + if (job_info->form_field_mapping == NULL) + include_forms = TRUE; + if (job_info->text_mapping == NULL) + include_text = TRUE; + if (new_selection_surface_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_forms, + 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; +} + diff --git a/shell/ev-pixbuf-cache.h b/shell/ev-pixbuf-cache.h index 79e0810a..a8ff30ab 100644 --- a/shell/ev-pixbuf-cache.h +++ b/shell/ev-pixbuf-cache.h @@ -65,9 +65,14 @@ GList *ev_pixbuf_cache_get_image_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 */ cairo_surface_t *ev_pixbuf_cache_get_selection_surface (EvPixbufCache *pixbuf_cache, gint page, diff --git a/shell/ev-view-private.h b/shell/ev-view-private.h index cab09417..4908711f 100644 --- a/shell/ev-view-private.h +++ b/shell/ev-view-private.h @@ -25,6 +25,7 @@ #include "ev-pixbuf-cache.h" #include "ev-page-cache.h" #include "ev-image.h" +#include "ev-form-field.h" /* Information for middle clicking and moving around the doc */ typedef struct { @@ -73,7 +74,7 @@ typedef enum { } EvPresentationState; struct _EvView { - GtkWidget parent_instance; + GtkLayout layout; EvDocument *document; @@ -152,11 +153,8 @@ struct _EvView { }; struct _EvViewClass { - GtkWidgetClass parent_class; + GtkLayoutClass parent_class; - void (*set_scroll_adjustments) (EvView *view, - GtkAdjustment *hadjustment, - GtkAdjustment *vadjustment); void (*binding_activated) (EvView *view, EvScrollType scroll, gboolean horizontal); diff --git a/shell/ev-view.c b/shell/ev-view.c index 08694725..468a8946 100644 --- a/shell/ev-view.c +++ b/shell/ev-view.c @@ -37,6 +37,7 @@ #include "ev-document-images.h" #include "ev-document-find.h" #include "ev-document-transition.h" +#include "ev-document-forms.h" #include "ev-document-misc.h" #include "ev-job-queue.h" #include "ev-page-cache.h" @@ -115,7 +116,7 @@ typedef enum { /*** Scrolling ***/ static void scroll_to_current_page (EvView *view, GtkOrientation orientation); -static void ev_view_set_scroll_adjustments (EvView *view, +static void ev_view_set_scroll_adjustments (GtkLayout *layout, GtkAdjustment *hadjustment, GtkAdjustment *vadjustment); static void view_update_range_and_current_page (EvView *view); @@ -157,19 +158,21 @@ static void find_page_at_location (EvView gint *page, gint *x_offset, gint *y_offset); -static gboolean doc_point_to_view_point (EvView *view, - int page, - EvPoint *doc_point, - GdkPoint *view_point); +static gboolean doc_point_to_view_point (EvView *view, + int page, + EvPoint *doc_point, + GdkPoint *view_point); /*** Hyperrefs ***/ -static EvLink * ev_view_get_link_at_location (EvView *view, - gdouble x, - gdouble y); +static EvLink * ev_view_get_link_at_location (EvView *view, + gdouble x, + gdouble y); static char* tip_from_link (EvView *view, EvLink *link); -static void handle_link_over_xy (EvView *view, - gint x, - gint y); +/*** Forms ***/ +static EvFormField *ev_view_get_form_field_at_location (EvView *view, + gdouble x, + gdouble y); + /*** GtkWidget implementation ***/ static void ev_view_size_request_continuous_dual_page (EvView *view, GtkRequisition *requisition); @@ -201,6 +204,7 @@ static gboolean ev_view_leave_notify_event (GtkWidget GdkEventCrossing *event); static void ev_view_style_set (GtkWidget *widget, GtkStyle *old_style); +static void ev_view_remove_all (EvView *view); static AtkObject *ev_view_get_accessible (GtkWidget *widget); @@ -292,6 +296,9 @@ static void ev_view_zoom_for_size_single_page (EvView *view, static GdkCursor* ev_view_create_invisible_cursor (void); static void ev_view_set_cursor (EvView *view, EvViewCursor new_cursor); +static void ev_view_handle_cursor_over_xy (EvView *view, + gint x, + gint y); /*** Status messages ***/ static void ev_view_set_status (EvView *view, @@ -326,7 +333,7 @@ static void ev_view_presentation_transition_start (EvView static void ev_view_presentation_transition_stop (EvView *ev_view); -G_DEFINE_TYPE (EvView, ev_view, GTK_TYPE_WIDGET) +G_DEFINE_TYPE (EvView, ev_view, GTK_TYPE_LAYOUT) static void scroll_to_current_page (EvView *view, GtkOrientation orientation) @@ -554,13 +561,15 @@ set_scroll_adjustment (EvView *view, } static void -ev_view_set_scroll_adjustments (EvView *view, +ev_view_set_scroll_adjustments (GtkLayout *layout, GtkAdjustment *hadjustment, GtkAdjustment *vadjustment) { + EvView *view = EV_VIEW (layout); + set_scroll_adjustment (view, GTK_ORIENTATION_HORIZONTAL, hadjustment); set_scroll_adjustment (view, GTK_ORIENTATION_VERTICAL, vadjustment); - + on_adjustment_value_changed (NULL, view); } @@ -1481,7 +1490,7 @@ tip_from_link (EvView *view, EvLink *link) } static void -handle_link_over_xy (EvView *view, gint x, gint y) +ev_view_handle_cursor_over_xy (EvView *view, gint x, gint y) { EvLink *link; @@ -1511,6 +1520,8 @@ handle_link_over_xy (EvView *view, gint x, gint y) ev_view_set_cursor (view, EV_VIEW_CURSOR_LINK); } else if (location_in_text (view, x + view->scroll_x, y + view->scroll_y)) { ev_view_set_cursor (view, EV_VIEW_CURSOR_IBEAM); + } else if (ev_view_get_form_field_at_location (view, x, y)) { + ev_view_set_cursor (view, EV_VIEW_CURSOR_LINK); } else { ev_view_set_status (view, NULL); if (view->cursor == EV_VIEW_CURSOR_LINK || @@ -1553,6 +1564,440 @@ ev_view_get_image_at_location (EvView *view, return NULL; } +/*** 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; + gint x_new = 0, y_new = 0; + GList *forms_mapping; + + if (!EV_IS_DOCUMENT_FORMS (view->document)) + return NULL; + + 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; + + if (get_doc_point_from_offset (view, page, x_offset, + y_offset, &x_new, &y_new) == FALSE) + return NULL; + + forms_mapping = ev_pixbuf_cache_get_form_field_mapping (view->pixbuf_cache, page); + + if (forms_mapping) + return ev_form_field_mapping_find (forms_mapping, x_new, y_new); + else + return NULL; +} + +static gboolean +ev_view_forms_remove_widgets (EvView *view) +{ + ev_view_remove_all (view); + + return FALSE; +} + +static void +ev_view_form_field_destroy (GtkWidget *widget, + EvView *view) +{ + g_idle_add ((GSourceFunc)ev_view_forms_remove_widgets, view); +} + +static GtkWidget * +ev_view_form_field_button_create_widget (EvView *view, + EvFormField *field) +{ + EvFormFieldButton *field_button = EV_FORM_FIELD_BUTTON (field); + + switch (field_button->type) { + case EV_FORM_FIELD_BUTTON_PUSH: + break; + case EV_FORM_FIELD_BUTTON_CHECK: + case EV_FORM_FIELD_BUTTON_RADIO: { + gboolean state; + + state = ev_document_forms_form_field_button_get_state (EV_DOCUMENT_FORMS (view->document), + field); + ev_document_forms_form_field_button_set_state (EV_DOCUMENT_FORMS (view->document), + field, !state); + ev_pixbuf_cache_reload_page (view->pixbuf_cache, + field->page, + view->rotation, + view->scale); + } + break; + } + + return NULL; +} + +static void +ev_view_form_field_text_save (EvView *view, + GtkWidget *widget) +{ + EvFormField *field; + + field = g_object_get_data (G_OBJECT (widget), "form-field"); + + if (field->changed) { + EvFormFieldText *field_text = EV_FORM_FIELD_TEXT (field); + + ev_document_forms_form_field_text_set_text (EV_DOCUMENT_FORMS (view->document), + field, field_text->text); + field->changed = FALSE; + ev_pixbuf_cache_reload_page (view->pixbuf_cache, + field->page, + view->rotation, + view->scale); + } +} + +static void +ev_view_form_field_text_changed (GtkWidget *widget, + EvFormField *field) +{ + EvFormFieldText *field_text = EV_FORM_FIELD_TEXT (field); + gchar *text = NULL; + + if (GTK_IS_ENTRY (widget)) { + text = g_strdup (gtk_entry_get_text (GTK_ENTRY (widget))); + } else if (GTK_IS_TEXT_BUFFER (widget)) { + GtkTextIter start, end; + + gtk_text_buffer_get_bounds (GTK_TEXT_BUFFER (widget), &start, &end); + text = gtk_text_buffer_get_text (GTK_TEXT_BUFFER (widget), + &start, &end, FALSE); + } + + if (!field_text->text || + (field_text->text && g_ascii_strcasecmp (field_text->text, text) != 0)) { + g_free (field_text->text); + field_text->text = text; + field->changed = TRUE; + } +} + +static GtkWidget * +ev_view_form_field_text_create_widget (EvView *view, + EvFormField *field) +{ + EvFormFieldText *field_text = EV_FORM_FIELD_TEXT (field); + GtkWidget *text = NULL; + gchar *txt; + + txt = ev_document_forms_form_field_text_get_text (EV_DOCUMENT_FORMS (view->document), + field); + + switch (field_text->type) { + case EV_FORM_FIELD_TEXT_FILE_SELECT: + /* TODO */ + case EV_FORM_FIELD_TEXT_NORMAL: + case EV_FORM_FIELD_TEXT_PASSWORD: + text = gtk_entry_new (); + gtk_entry_set_has_frame (GTK_ENTRY (text), FALSE); + gtk_entry_set_max_length (GTK_ENTRY (text), field_text->max_len); + gtk_entry_set_visibility (GTK_ENTRY (text), + !(field_text->type == EV_FORM_FIELD_TEXT_PASSWORD)); + + if (txt) { + gtk_entry_set_text (GTK_ENTRY (text), txt); + g_free (txt); + } + + g_signal_connect (G_OBJECT (text), "changed", + G_CALLBACK (ev_view_form_field_text_changed), + field); + g_signal_connect_after (G_OBJECT (text), "activate", + G_CALLBACK (ev_view_form_field_destroy), + view); + break; + case EV_FORM_FIELD_TEXT_MULTILINE: { + GtkTextBuffer *buffer; + + text = gtk_text_view_new (); + buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (text)); + + if (txt) { + gtk_text_buffer_set_text (buffer, txt, -1); + g_free (txt); + } + + g_signal_connect (G_OBJECT (buffer), "changed", + G_CALLBACK (ev_view_form_field_text_changed), + field); + } + break; + } + + g_object_weak_ref (G_OBJECT (text), + (GWeakNotify)ev_view_form_field_text_save, + view); + + return text; +} + +static void +ev_view_form_field_choice_save (EvView *view, + GtkWidget *widget) +{ + EvFormField *field; + + field = g_object_get_data (G_OBJECT (widget), "form-field"); + + if (field->changed) { + GList *l; + EvFormFieldChoice *field_choice = EV_FORM_FIELD_CHOICE (field); + + if (field_choice->is_editable) { + ev_document_forms_form_field_choice_set_text (EV_DOCUMENT_FORMS (view->document), + field, field_choice->text); + } + + ev_document_forms_form_field_choice_unselect_all (EV_DOCUMENT_FORMS (view->document), field); + for (l = field_choice->selected_items; l && l->data; l = g_list_next (l)) { + ev_document_forms_form_field_choice_select_item (EV_DOCUMENT_FORMS (view->document), + field, + GPOINTER_TO_INT (l->data)); + } + field->changed = FALSE; + ev_pixbuf_cache_reload_page (view->pixbuf_cache, + field->page, + view->rotation, + view->scale); + } +} + +static void +ev_view_form_field_choice_changed (GtkWidget *widget, + EvFormField *field) +{ + EvFormFieldChoice *field_choice = EV_FORM_FIELD_CHOICE (field); + + if (GTK_IS_COMBO_BOX (widget)) { + gint item; + + item = gtk_combo_box_get_active (GTK_COMBO_BOX (widget)); + if (GPOINTER_TO_INT (field_choice->selected_items->data) != item) { + g_list_free (field_choice->selected_items); + field_choice->selected_items = NULL; + field_choice->selected_items = g_list_prepend (field_choice->selected_items, + GINT_TO_POINTER (item)); + field->changed = TRUE; + } + + if (GTK_IS_COMBO_BOX_ENTRY (widget)) { + gchar *text; + + text = gtk_combo_box_get_active_text (GTK_COMBO_BOX (widget)); + if (!field_choice->text || + (field_choice->text && g_ascii_strcasecmp (field_choice->text, text) != 0)) { + g_free (field_choice->text); + field_choice->text = text; + field->changed = TRUE; + } + } + } else if (GTK_IS_TREE_SELECTION (widget)) { + GtkTreeSelection *selection = GTK_TREE_SELECTION (widget); + GtkTreeModel *model; + GList *items, *l; + + items = gtk_tree_selection_get_selected_rows (selection, &model); + g_list_free (field_choice->selected_items); + field_choice->selected_items = NULL; + + for (l = items; l && l->data; l = g_list_next (l)) { + GtkTreeIter iter; + GtkTreePath *path = (GtkTreePath *)l->data; + gint item; + + gtk_tree_model_get_iter (model, &iter, path); + gtk_tree_model_get (model, &iter, 1, &item, -1); + + field_choice->selected_items = g_list_prepend (field_choice->selected_items, + GINT_TO_POINTER (item)); + + gtk_tree_path_free (path); + } + + g_list_free (items); + + field->changed = TRUE; + } +} + +static GtkWidget * +ev_view_form_field_choice_create_widget (EvView *view, + EvFormField *field) +{ + EvFormFieldChoice *field_choice = EV_FORM_FIELD_CHOICE (field); + GtkWidget *choice; + GtkTreeModel *model; + gint n_items, i; + gint selected_item = 0; + + n_items = ev_document_forms_form_field_choice_get_n_items (EV_DOCUMENT_FORMS (view->document), + field); + model = GTK_TREE_MODEL (gtk_list_store_new (2, G_TYPE_STRING, G_TYPE_INT)); + for (i = 0; i < n_items; i++) { + GtkTreeIter iter; + gchar *item; + + item = ev_document_forms_form_field_choice_get_item (EV_DOCUMENT_FORMS (view->document), + field, i); + if (ev_document_forms_form_field_choice_is_item_selected ( + EV_DOCUMENT_FORMS (view->document), field, i)) { + selected_item = i; + /* FIXME: we need a get_selected_items function in poppler */ + field_choice->selected_items = g_list_prepend (field_choice->selected_items, + GINT_TO_POINTER (i)); + } + + if (item) { + gtk_list_store_append (GTK_LIST_STORE (model), &iter); + gtk_list_store_set (GTK_LIST_STORE (model), &iter, + 0, item, + 1, i, + -1); + g_free (item); + } + } + + if (field_choice->type == EV_FORM_FIELD_CHOICE_LIST) { + GtkCellRenderer *renderer; + GtkWidget *tree_view; + GtkTreeSelection *selection; + + tree_view = gtk_tree_view_new_with_model (model); + gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (tree_view), FALSE); + + selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (tree_view)); + if (field_choice->multi_select) { + gtk_tree_selection_set_mode (selection, GTK_SELECTION_MULTIPLE); + } + + /* TODO: set selected items */ + + renderer = gtk_cell_renderer_text_new (); + gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW (tree_view), + 0, + "choix", renderer, + "text", 0, + NULL); + + choice = gtk_scrolled_window_new (NULL, NULL); + gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (choice), + GTK_POLICY_AUTOMATIC, + GTK_POLICY_AUTOMATIC); + gtk_container_add (GTK_CONTAINER (choice), tree_view); + gtk_widget_show (tree_view); + + g_signal_connect (G_OBJECT (selection), "changed", + G_CALLBACK (ev_view_form_field_choice_changed), + field); + g_signal_connect_after (G_OBJECT (selection), "changed", + G_CALLBACK (ev_view_form_field_destroy), + view); + } else if (field_choice->is_editable) { /* ComboBoxEntry */ + gchar *text; + + choice = gtk_combo_box_entry_new_with_model (model, 0); + text = ev_document_forms_form_field_choice_get_text (EV_DOCUMENT_FORMS (view->document), field); + if (text) { + gtk_entry_set_text (GTK_ENTRY (gtk_bin_get_child (GTK_BIN (choice))), text); + g_free (text); + } + + g_signal_connect (G_OBJECT (choice), "changed", + G_CALLBACK (ev_view_form_field_choice_changed), + field); + g_signal_connect_after (G_OBJECT (GTK_BIN (choice)->child), "activate", + G_CALLBACK (ev_view_form_field_destroy), + view); + } else { /* ComboBoxText */ + GtkCellRenderer *renderer; + + choice = gtk_combo_box_new_with_model (model); + renderer = gtk_cell_renderer_text_new (); + gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (choice), + renderer, TRUE); + gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (choice), + renderer, + "text", 0, + NULL); + gtk_combo_box_set_active (GTK_COMBO_BOX (choice), selected_item); + gtk_combo_box_popup (GTK_COMBO_BOX (choice)); + + g_signal_connect (G_OBJECT (choice), "changed", + G_CALLBACK (ev_view_form_field_choice_changed), + field); + g_signal_connect_after (G_OBJECT (choice), "changed", + G_CALLBACK (ev_view_form_field_destroy), + view); + } + + g_object_unref (model); + + g_object_weak_ref (G_OBJECT (choice), + (GWeakNotify)ev_view_form_field_choice_save, + view); + + return choice; +} + +static void +ev_view_handle_form_field (EvView *view, + EvFormField *field, + gdouble x, + gdouble y) +{ + GtkWidget *field_widget = NULL; + GList *form_field_mapping; + EvRectangle field_area; + GdkRectangle view_area; + + if (field->is_read_only) + return; + + if (EV_IS_FORM_FIELD_BUTTON (field)) { + field_widget = ev_view_form_field_button_create_widget (view, field); + } else if (EV_IS_FORM_FIELD_TEXT (field)) { + field_widget = ev_view_form_field_text_create_widget (view, field); + } else if (EV_IS_FORM_FIELD_CHOICE (field)) { + field_widget = ev_view_form_field_choice_create_widget (view, field); + } else if (EV_IS_FORM_FIELD_SIGNATURE (field)) { + /* TODO */ + } + + /* Form field doesn't require a widget */ + if (!field_widget) + return; + + g_object_set_data_full (G_OBJECT (field_widget), "form-field", + g_object_ref (field), + (GDestroyNotify)g_object_unref); + + form_field_mapping = ev_pixbuf_cache_get_form_field_mapping (view->pixbuf_cache, field->page); + ev_form_field_mapping_get_area (form_field_mapping, field, &field_area); + + doc_rect_to_view_rect (view, field->page, &field_area, &view_area); + view_area.x -= view->scroll_x; + view_area.y -= view->scroll_y; + + gtk_layout_put (GTK_LAYOUT (view), field_widget, view_area.x, view_area.y); + gtk_widget_show (field_widget); + gtk_widget_grab_focus (field_widget); +} + /*** GtkWidget implementation ***/ static void @@ -1680,7 +2125,7 @@ ev_view_size_request (GtkWidget *widget, GtkRequisition *requisition) { EvView *view = EV_VIEW (widget); - + if (view->document == NULL) { requisition->width = 1; requisition->height = 1; @@ -1708,6 +2153,7 @@ ev_view_size_allocate (GtkWidget *widget, GtkAllocation *allocation) { EvView *view = EV_VIEW (widget); + GList *children, *l; GTK_WIDGET_CLASS (ev_view_parent_class)->size_allocate (widget, allocation); @@ -1718,7 +2164,7 @@ ev_view_size_allocate (GtkWidget *widget, ev_view_size_request (widget, &widget->requisition); } - + view_set_adjustment_values (view, GTK_ORIENTATION_HORIZONTAL); view_set_adjustment_values (view, GTK_ORIENTATION_VERTICAL); @@ -1727,47 +2173,71 @@ ev_view_size_allocate (GtkWidget *widget, view->pending_scroll = SCROLL_TO_KEEP_POSITION; view->pending_resize = FALSE; + + children = gtk_container_get_children (GTK_CONTAINER (widget)); + for (l = children; l && l->data; l = g_list_next (l)) { + EvFormField *field; + EvRectangle field_area; + GdkRectangle view_area; + GList *form_field_mapping; + GtkAllocation child_allocation; + GtkRequisition child_requisition; + GtkWidget *child = (GtkWidget *)l->data; + + field = g_object_get_data (G_OBJECT (child), "form-field"); + if (!field) + continue; + + form_field_mapping = ev_pixbuf_cache_get_form_field_mapping (view->pixbuf_cache, + field->page); + ev_form_field_mapping_get_area (form_field_mapping, field, &field_area); + + doc_rect_to_view_rect (view, field->page, &field_area, &view_area); + view_area.x -= view->scroll_x; + view_area.y -= view->scroll_y; + + gtk_widget_size_request (child, &child_requisition); + if (child_requisition.width != view_area.width || + child_requisition.height != view_area.height) + gtk_widget_set_size_request (child, view_area.width, view_area.height); + + gtk_container_child_get (GTK_CONTAINER (widget), + child, + "x", &child_allocation.x, + "y", &child_allocation.y, + NULL); + if (child_allocation.x != view_area.x || + child_allocation.y != view_area.y) { + gtk_layout_move (GTK_LAYOUT (widget), child, view_area.x, view_area.y); + } + } + g_list_free (children); } static void ev_view_realize (GtkWidget *widget) { EvView *view = EV_VIEW (widget); - GdkWindowAttr attributes; - - GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED); - attributes.window_type = GDK_WINDOW_CHILD; - attributes.wclass = GDK_INPUT_OUTPUT; - attributes.visual = gtk_widget_get_visual (widget); - attributes.colormap = gtk_widget_get_colormap (widget); + if (GTK_WIDGET_CLASS (ev_view_parent_class)->realize) + (* GTK_WIDGET_CLASS (ev_view_parent_class)->realize) (widget); - attributes.x = widget->allocation.x; - attributes.y = widget->allocation.y; - attributes.width = widget->allocation.width; - attributes.height = widget->allocation.height; - attributes.event_mask = GDK_EXPOSURE_MASK | + gdk_window_set_events (view->layout.bin_window, + (gdk_window_get_events (view->layout.bin_window) | + GDK_EXPOSURE_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | GDK_SCROLL_MASK | GDK_KEY_PRESS_MASK | GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | - GDK_ENTER_NOTIFY_MASK | - GDK_LEAVE_NOTIFY_MASK; - - widget->window = gdk_window_new (gtk_widget_get_parent_window (widget), - &attributes, - GDK_WA_X | GDK_WA_Y | - GDK_WA_COLORMAP | - GDK_WA_VISUAL); - gdk_window_set_user_data (widget->window, widget); - widget->style = gtk_style_attach (widget->style, widget->window); + GDK_ENTER_NOTIFY_MASK | + GDK_LEAVE_NOTIFY_MASK)); if (view->presentation) - gdk_window_set_background (widget->window, &widget->style->black); + gdk_window_set_background (view->layout.bin_window, &widget->style->black); else - gdk_window_set_background (widget->window, &widget->style->mid [GTK_STATE_NORMAL]); + gdk_window_set_background (view->layout.bin_window, &widget->style->mid [GTK_STATE_NORMAL]); } static gboolean @@ -1869,7 +2339,7 @@ draw_end_presentation_page (EvView *view, pango_layout_set_font_description (layout, font_desc); gtk_paint_layout (GTK_WIDGET (view)->style, - GTK_WIDGET (view)->window, + view->layout.bin_window, GTK_WIDGET_STATE (view), FALSE, page_area, @@ -1939,6 +2409,9 @@ ev_view_expose_event (GtkWidget *widget, highlight_find_results (view, i); } + if (GTK_WIDGET_CLASS (ev_view_parent_class)->expose_event) + (* GTK_WIDGET_CLASS (ev_view_parent_class)->expose_event) (widget, event); + return FALSE; } @@ -1995,6 +2468,7 @@ ev_view_button_press_event (GtkWidget *widget, switch (event->button) { case 1: { EvImage *image; + EvFormField *field; if (view->selection_info.selections) { if (location_in_selected_text (view, @@ -2018,7 +2492,11 @@ ev_view_button_press_event (GtkWidget *widget, view->image_dnd_info.start.x = event->x + view->scroll_x; view->image_dnd_info.start.y = event->y + view->scroll_y; + } else if ((field = ev_view_get_form_field_at_location (view, event->x, event->y))) { + ev_view_remove_all (view); + ev_view_handle_form_field (view, field, event->x, event->y); } else { + ev_view_remove_all (view); view->selection_info.start.x = event->x + view->scroll_x; view->selection_info.start.y = event->y + view->scroll_y; } @@ -2042,6 +2520,19 @@ ev_view_button_press_event (GtkWidget *widget, return FALSE; } +static void +ev_view_remove_all (EvView *view) +{ + GList *children, *child; + + children = gtk_container_get_children (GTK_CONTAINER (view)); + for (child = children; child && child->data; child = g_list_next (child)) { + gtk_container_remove (GTK_CONTAINER (view), + GTK_WIDGET (child->data)); + } + g_list_free (children); +} + /*** Drag and Drop ***/ static void ev_view_drag_data_get (GtkWidget *widget, @@ -2196,7 +2687,7 @@ ev_view_motion_notify_event (GtkWidget *widget, if (!view->document) return FALSE; - if (event->is_hint || event->window != widget->window) { + if (event->is_hint || event->window != view->layout.bin_window) { gtk_widget_get_pointer (widget, &x, &y); } else { x = event->x; @@ -2306,7 +2797,7 @@ ev_view_motion_notify_event (GtkWidget *widget, return TRUE; } } else if (view->pressed_button <= 0) { - handle_link_over_xy (view, x, y); + ev_view_handle_cursor_over_xy (view, x, y); return TRUE; } @@ -2642,11 +3133,11 @@ ev_view_key_press_event (GtkWidget *widget, switch (view->presentation_state) { case EV_PRESENTATION_NORMAL: case EV_PRESENTATION_BLACK: - gdk_window_set_background (widget->window, + gdk_window_set_background (view->layout.bin_window, &widget->style->black); break; case EV_PRESENTATION_WHITE: - gdk_window_set_background (widget->window, + gdk_window_set_background (view->layout.bin_window, &widget->style->white); break; default: @@ -2706,7 +3197,7 @@ ev_view_enter_notify_event (GtkWidget *widget, GdkEventCrossing *event) { EvView *view = EV_VIEW (widget); - handle_link_over_xy (view, event->x, event->y); + ev_view_handle_cursor_over_xy (view, event->x, event->y); return FALSE; } @@ -2793,7 +3284,7 @@ highlight_find_results (EvView *view, int page) ev_document_find_get_result (find, page, i, &rectangle); doc_rect_to_view_rect (view, page, &rectangle, &view_rectangle); - draw_rubberband (GTK_WIDGET (view), GTK_WIDGET(view)->window, + draw_rubberband (GTK_WIDGET (view), view->layout.bin_window, &view_rectangle, alpha); } } @@ -2857,7 +3348,7 @@ draw_loading_text (EvView *view, width = (page_area->width - cairo_image_surface_get_width (view->loading_text)) / 2; height = (page_area->height - cairo_image_surface_get_height (view->loading_text)) / 2; - cr = gdk_cairo_create (GTK_WIDGET (view)->window); + cr = gdk_cairo_create (view->layout.bin_window); cairo_translate (cr, page_area->x + width, page_area->y + height); @@ -2893,9 +3384,9 @@ draw_one_page (EvView *view, if (!view->presentation) { gint current_page; - + current_page = ev_page_cache_get_current_page (view->page_cache); - ev_document_misc_paint_one_page (GTK_WIDGET (view)->window, + ev_document_misc_paint_one_page (view->layout.bin_window, GTK_WIDGET (view), page_area, border, page == current_page); @@ -2925,7 +3416,7 @@ draw_one_page (EvView *view, view->scale, &width, &height); - cr = gdk_cairo_create (GTK_WIDGET (view)->window); + cr = gdk_cairo_create (view->layout.bin_window); cairo_save (cr); @@ -3057,7 +3548,7 @@ ev_view_destroy (GtkObject *object) ev_view_presentation_transition_stop (view); - ev_view_set_scroll_adjustments (view, NULL, NULL); + ev_view_set_scroll_adjustments (GTK_LAYOUT (view), NULL, NULL); GTK_OBJECT_CLASS (ev_view_parent_class)->destroy (object); } @@ -3179,6 +3670,7 @@ ev_view_class_init (EvViewClass *class) GObjectClass *object_class = G_OBJECT_CLASS (class); GtkObjectClass *gtk_object_class = GTK_OBJECT_CLASS (class); GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (class); + GtkLayoutClass *layout_class = GTK_LAYOUT_CLASS (class); GtkBindingSet *binding_set; object_class->finalize = ev_view_finalize; @@ -3204,22 +3696,13 @@ ev_view_class_init (EvViewClass *class) widget_class->drag_motion = ev_view_drag_motion; widget_class->drag_data_received = ev_view_drag_data_received; widget_class->popup_menu = ev_view_popup_menu; + gtk_object_class->destroy = ev_view_destroy; - class->set_scroll_adjustments = ev_view_set_scroll_adjustments; + layout_class->set_scroll_adjustments = ev_view_set_scroll_adjustments; + class->binding_activated = ev_view_scroll; - 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, - GTK_TYPE_ADJUSTMENT, - GTK_TYPE_ADJUSTMENT); - signals[SIGNAL_BINDING_ACTIVATED] = g_signal_new ("binding_activated", G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION, @@ -3379,6 +3862,9 @@ ev_view_init (EvView *view) view->pending_scroll = SCROLL_TO_KEEP_POSITION; view->jump_to_find_result = TRUE; + gtk_layout_set_hadjustment (GTK_LAYOUT (view), NULL); + gtk_layout_set_vadjustment (GTK_LAYOUT (view), NULL); + gtk_drag_dest_set (GTK_WIDGET (view), GTK_DEST_DEFAULT_ALL, view_drop_targets, @@ -3429,7 +3915,7 @@ page_changed_cb (EvPageCache *page_cache, ev_view_presentation_transition_start (view); gtk_widget_get_pointer (GTK_WIDGET (view), &x, &y); - handle_link_over_xy (view, x, y); + ev_view_handle_cursor_over_xy (view, x, y); gtk_widget_queue_resize (GTK_WIDGET (view)); } else { @@ -3448,6 +3934,7 @@ on_adjustment_value_changed (GtkAdjustment *adjustment, { int dx = 0, dy = 0; gint x, y; + GList *children, *l; if (! GTK_WIDGET_REALIZED (view)) return; @@ -3466,13 +3953,27 @@ on_adjustment_value_changed (GtkAdjustment *adjustment, view->scroll_y = 0; } + children = gtk_container_get_children (GTK_CONTAINER (view)); + for (l = children; l && l->data; l = g_list_next (l)) { + gint child_x, child_y; + GtkWidget *child = (GtkWidget *)l->data; + + gtk_container_child_get (GTK_CONTAINER (view), + child, + "x", &child_x, + "y", &child_y, + NULL); + gtk_layout_move (GTK_LAYOUT (view), child, child_x + dx, child_y + dy); + } + g_list_free (children); + if (view->pending_resize) gtk_widget_queue_draw (GTK_WIDGET (view)); else - gdk_window_scroll (GTK_WIDGET (view)->window, dx, dy); + gdk_window_scroll (view->layout.bin_window, dx, dy); gtk_widget_get_pointer (GTK_WIDGET (view), &x, &y); - handle_link_over_xy (view, x, y); + ev_view_handle_cursor_over_xy (view, x, y); if (view->document) view_update_range_and_current_page (view); @@ -3725,10 +4226,10 @@ ev_view_set_presentation (EvView *view, if (GTK_WIDGET_REALIZED (view)) { if (view->presentation) - gdk_window_set_background (GTK_WIDGET(view)->window, + gdk_window_set_background (view->layout.bin_window, >K_WIDGET (view)->style->black); else - gdk_window_set_background (GTK_WIDGET(view)->window, + gdk_window_set_background (view->layout.bin_window, >K_WIDGET (view)->style->mid [GTK_STATE_NORMAL]); } @@ -4629,7 +5130,7 @@ merge_selection_region (EvView *view, gdk_region_offset (region, page_area.x + border.left - view->scroll_x, page_area.y + border.top - view->scroll_y); - gdk_window_invalidate_region (GTK_WIDGET (view)->window, region, TRUE); + gdk_window_invalidate_region (view->layout.bin_window, region, TRUE); gdk_region_destroy (region); } } @@ -4843,7 +5344,7 @@ ev_view_set_cursor (EvView *view, EvViewCursor new_cursor) switch (new_cursor) { case EV_VIEW_CURSOR_NORMAL: - gdk_window_set_cursor (widget->window, NULL); + gdk_window_set_cursor (view->layout.bin_window, NULL); break; case EV_VIEW_CURSOR_IBEAM: cursor = gdk_cursor_new_for_display (display, GDK_XTERM); @@ -4863,7 +5364,7 @@ ev_view_set_cursor (EvView *view, EvViewCursor new_cursor) } if (cursor) { - gdk_window_set_cursor (widget->window, cursor); + gdk_window_set_cursor (view->layout.bin_window, cursor); gdk_cursor_unref (cursor); gdk_flush(); } @@ -4889,7 +5390,7 @@ ev_view_reset_presentation_state (EvView *view) return; view->presentation_state = EV_PRESENTATION_NORMAL; - gdk_window_set_background (GTK_WIDGET (view)->window, + gdk_window_set_background (view->layout.bin_window, >K_WIDGET (view)->style->black); gtk_widget_queue_draw (GTK_WIDGET (view)); } diff --git a/shell/ev-view.h b/shell/ev-view.h index e9b8afa5..78fc6598 100644 --- a/shell/ev-view.h +++ b/shell/ev-view.h @@ -21,6 +21,7 @@ #define __EV_VIEW_H__ #include +#include #include "ev-document.h" #include "ev-link.h"