/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ /* This file is part of the GtkHTML library. Copyright (C) 1999, 2000 Helix Code, Inc. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library 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 Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include #include #include "htmlcursor.h" #include "htmlengine.h" #include "htmlengine-edit.h" #include "htmlengine-edit-cursor.h" #include "htmlengine-search.h" #include "htmlinterval.h" #include "htmlsearch.h" #include "htmlselection.h" #include "htmltextslave.h" static HTMLEngine * get_root_engine (HTMLEngine *e) { return e->widget->iframe_parent ? GTK_HTML (e->widget->iframe_parent)->engine : e; } static void add_iframe_off (HTMLEngine *e, gint *x, gint *y) { g_assert (e); g_assert (e->widget); if (e->widget->iframe_parent) { *x += e->widget->iframe_parent->allocation.x; *y += e->widget->iframe_parent->allocation.y; } } static void move_to_found (HTMLSearch *info) { HTMLEngine *e = info->engine; HTMLEngine *ep = get_root_engine (info->engine); HTMLObject *first = HTML_OBJECT (info->found->data); HTMLObject *last = HTML_OBJECT (g_list_last (info->found)->data); HTMLTextSlave *slave; gint x, y, ex, ey, w, h; gint nx = e->x_offset; gint ny = e->y_offset; /* x,y is top-left corner, ex+w,ey+h is bottom-right */ html_object_calc_abs_position (first, &x, &y); add_iframe_off (e, &x, &y); /* find slave where starts selection and get its coordinates as upper-left corner */ while (first->next && HTML_OBJECT_TYPE (first->next) == HTML_TYPE_TEXTSLAVE) { first = first->next; slave = HTML_TEXT_SLAVE (first); if (slave->posStart+slave->posLen >= info->start_pos) { html_object_calc_abs_position (HTML_OBJECT (slave), &x, &y); add_iframe_off (e, &x, &y); break; } } /* the same with last */ html_object_calc_abs_position (last, &ex, &ey); while (last->next && HTML_OBJECT_TYPE (last->next) == HTML_TYPE_TEXTSLAVE) { last = last->next; slave = HTML_TEXT_SLAVE (last); if (slave->posStart+slave->posLen >= info->start_pos) { html_object_calc_abs_position (HTML_OBJECT (slave), &ex, &ey); add_iframe_off (e, &ex, &ey); break; } } y -= first->ascent; ex += last->width; ey += last->descent; w = ex - x; h = ey - y; /* now calculate gtkhtml adustments */ if (x <= ep->x_offset) nx = x; else if (x + w > ep->x_offset + ep->width) nx = x + w - ep->width; if (y <= ep->y_offset) ny = y; else if (y + h > ep->y_offset + ep->height) ny = y + h - ep->height; /* finally adjust them if they changed */ if (ep->x_offset != nx) gtk_adjustment_set_value (GTK_LAYOUT (ep->widget)->hadjustment, nx); if (ep->y_offset != ny) gtk_adjustment_set_value (GTK_LAYOUT (ep->widget)->vadjustment, ny); } static void display_search_results (HTMLSearch *info) { HTMLEngine *e = info->engine; if (!info->found) return; if (e->editable) { html_engine_hide_cursor (e); html_engine_disable_selection (e); html_cursor_jump_to (e->cursor, e, HTML_OBJECT (info->found->data), info->start_pos); html_engine_set_mark (e); html_cursor_jump_to (e->cursor, e, info->last, info->stop_pos); html_engine_show_cursor (e); } else { html_engine_select_interval (e, html_interval_new (HTML_OBJECT (info->found->data), info->last, info->start_pos, info->stop_pos)); move_to_found (info); } } gboolean html_engine_search (HTMLEngine *e, const gchar *text, gboolean case_sensitive, gboolean forward, gboolean regular) { HTMLSearch *info; HTMLObject *p; if (e->search_info) { html_search_destroy (e->search_info); } info = e->search_info = html_search_new (e, text, case_sensitive, forward, regular); p = HTML_OBJECT (e->search_info->stack->data)->parent; if (html_object_search (p ? p : e->clue, info)) { display_search_results (info); return TRUE; } else return FALSE; } void html_engine_search_set_forward (HTMLEngine *e, gboolean forward) { html_search_set_forward (e->search_info, forward); } gboolean html_engine_search_next (HTMLEngine *e) { HTMLSearch *info = e->search_info; gboolean retval = FALSE; if (!info) return FALSE; if (html_engine_get_editable (e)) { gchar *text = g_strdup (info->text); retval = html_engine_search (e, text, info->case_sensitive, info->forward, info->regular); g_free (text); } else { if (info->stack) retval = html_object_search (HTML_OBJECT (info->stack->data), info); else { html_search_push (info, e->clue); retval = html_object_search (e->clue, info); } if (retval) display_search_results (info); else { html_search_pop (info); html_engine_disable_selection (e); } } return retval; } gboolean html_engine_search_incremental (HTMLEngine *e, const gchar *text, gboolean forward) { HTMLSearch *info = e->search_info; if (info) { html_search_set_forward (info, forward); html_search_set_text (info, text); if (info->found) info->start_pos += ((info->forward) ? -1 : g_utf8_strlen (text, -1)); return html_engine_search_next (e); } else return html_engine_search (e, text, FALSE, forward, FALSE); }