From 4f3691d183f6393f05e08ffc00e53102b5d65753 Mon Sep 17 00:00:00 2001 From: John Mark Bell Date: Thu, 5 Aug 2004 20:32:00 +0000 Subject: [project @ 2004-08-05 20:32:00 by jmb] Text search. Press F4 to access it svn path=/import/netsurf/; revision=1182 --- riscos/dialog.c | 30 +++++- riscos/gui.h | 15 ++- riscos/search.c | 296 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ riscos/window.c | 7 +- 4 files changed, 345 insertions(+), 3 deletions(-) create mode 100644 riscos/search.c (limited to 'riscos') diff --git a/riscos/dialog.c b/riscos/dialog.c index 3bd0fffa4..d98cf1127 100644 --- a/riscos/dialog.c +++ b/riscos/dialog.c @@ -38,7 +38,7 @@ wimp_w dialog_info, dialog_saveas, dialog_config, dialog_config_br, #endif dialog_zoom, dialog_pageinfo, dialog_objinfo, dialog_tooltip, dialog_warning, dialog_config_th_pane, dialog_debug, - dialog_folder, dialog_entry; + dialog_folder, dialog_entry, dialog_search; static int ro_gui_choices_font_size; static int ro_gui_choices_font_min_size; @@ -102,6 +102,7 @@ void ro_gui_dialog_init(void) dialog_debug = ro_gui_dialog_create("debug"); dialog_folder = ro_gui_dialog_create("new_folder"); dialog_entry = ro_gui_dialog_create("new_entry"); + dialog_search = ro_gui_dialog_create("search"); } @@ -345,6 +346,8 @@ void ro_gui_dialog_close_persistant(wimp_w parent) { bool ro_gui_dialog_keypress(wimp_key *key) { wimp_pointer pointer; + int i; + if (key->c == wimp_KEY_ESCAPE) { ro_gui_dialog_close(key->w); return true; @@ -358,6 +361,20 @@ bool ro_gui_dialog_keypress(wimp_key *key) ro_gui_hotlist_dialog_click(&pointer); return true; } + else if (key->w == dialog_search) { + pointer.w = key->w; + pointer.i = ICON_SEARCH_FIND; + pointer.buttons = wimp_CLICK_SELECT; + for (i = 0; i < MAX_PERSISTANT; i++) { + if (persistant_dialog[i].dialog == + dialog_search) { + ro_gui_search_click(&pointer, + persistant_dialog[i].parent); + break; + } + } + return true; + } } #ifdef WITH_AUTH if (key->w == dialog_401li) @@ -373,6 +390,8 @@ bool ro_gui_dialog_keypress(wimp_key *key) void ro_gui_dialog_click(wimp_pointer *pointer) { + int i; + if (pointer->buttons == wimp_CLICK_MENU) return; @@ -396,6 +415,15 @@ void ro_gui_dialog_click(wimp_pointer *pointer) ro_gui_dialog_click_warning(pointer); else if ((pointer->w == dialog_folder) || (pointer->w == dialog_entry)) ro_gui_hotlist_dialog_click(pointer); + else if (pointer->w == dialog_search) { + for (i = 0; i < MAX_PERSISTANT; i++) { + if (persistant_dialog[i].dialog == dialog_search) { + ro_gui_search_click(pointer, + persistant_dialog[i].parent); + break; + } + } + } } diff --git a/riscos/gui.h b/riscos/gui.h index 005b3a036..d16cfed86 100644 --- a/riscos/gui.h +++ b/riscos/gui.h @@ -26,7 +26,7 @@ struct toolbar; extern wimp_w dialog_info, dialog_saveas, dialog_config, dialog_config_br, dialog_config_prox, dialog_config_th, dialog_zoom, dialog_pageinfo, dialog_objinfo, dialog_tooltip, dialog_warning, dialog_config_th_pane, - dialog_debug, dialog_folder, dialog_entry; + dialog_debug, dialog_folder, dialog_entry, dialog_search; extern wimp_w history_window; extern wimp_w hotlist_window; extern wimp_menu *iconbar_menu, *browser_menu, *combo_menu, *hotlist_menu, @@ -238,6 +238,10 @@ void ro_gui_debugwin_open(void); void ro_gui_debugwin_close(void); void ro_gui_debugwin_redraw(wimp_draw *redraw); +/* in search.c */ +void ro_gui_search_click(wimp_pointer *pointer, wimp_w parent); +void ro_gui_search_prepare(void); + /* toolbar types */ #define TOOLBAR_BROWSER 0 #define TOOLBAR_HOTLIST 1 @@ -345,4 +349,13 @@ void ro_gui_debugwin_redraw(wimp_draw *redraw); #define ICON_WARNING_CONTINUE 1 #define ICON_WARNING_HELP 2 +#define ICON_SEARCH_TEXT 0 +#define ICON_SEARCH_START 1 +#define ICON_SEARCH_CASE_SENSITIVE 2 +#define ICON_SEARCH_FORWARDS 3 +#define ICON_SEARCH_BACKWARDS 4 +#define ICON_SEARCH_CANCEL 5 +#define ICON_SEARCH_FIND 6 + + #endif diff --git a/riscos/search.c b/riscos/search.c new file mode 100644 index 000000000..9dc46299a --- /dev/null +++ b/riscos/search.c @@ -0,0 +1,296 @@ +/* + * This file is part of NetSurf, http://netsurf.sourceforge.net/ + * Licensed under the GNU General Public License, + * http://www.opensource.org/licenses/gpl-license + * Copyright 2004 John M Bell + */ + +#include + +#include "oslib/wimp.h" + +#include "netsurf/utils/config.h" +#include "netsurf/content/content_type.h" +#include "netsurf/desktop/browser.h" +#include "netsurf/desktop/gui.h" +#include "netsurf/render/box.h" +#include "netsurf/render/html.h" +#include "netsurf/riscos/gui.h" +#include "netsurf/riscos/wimp.h" +#include "netsurf/utils/log.h" +#include "netsurf/utils/utils.h" + + +#ifdef WITH_SEARCH + +struct list_entry { + struct box *box; + struct list_entry *prev; + struct list_entry *next; +}; + +static char *search_string = 0; +static struct list_entry head = { 0, 0, 0 }; +static struct list_entry *found = &head; +static struct list_entry *current = 0; +static struct gui_window *w = 0; +static bool prev_from_top = false; +static bool prev_case_sens = false; + +static void do_search(struct gui_window *g, char *string, bool from_top, bool case_sens, bool forwards); +static bool find_occurrences(char *string, struct box *cur, bool case_sens); +static char * strcasestr(char *s1, char *s2); + + +/** + * Handle clicks in the search dialog + * + * \param pointer wimp_pointer block + * \param parent The parent window of this persistent dialog + */ +void ro_gui_search_click(wimp_pointer *pointer, wimp_w parent) +{ + struct gui_window *g; + char *string; + + if (pointer->buttons == wimp_CLICK_MENU) + return; + + switch(pointer->i) { + case ICON_SEARCH_FORWARDS: + case ICON_SEARCH_BACKWARDS: + /* prevent deselection on adjust clicking */ + if (pointer->buttons == wimp_CLICK_ADJUST) + ro_gui_set_icon_selected_state(dialog_search, + pointer->i, true); + break; + case ICON_SEARCH_FIND: + g = ro_gui_window_lookup(parent); + string = ro_gui_get_icon_string(pointer->w, + ICON_SEARCH_TEXT); + if (!g || strlen(string) == 0) + return; + do_search(g, string, + ro_gui_get_icon_selected_state(pointer->w, + ICON_SEARCH_START), + ro_gui_get_icon_selected_state(pointer->w, + ICON_SEARCH_CASE_SENSITIVE), + ro_gui_get_icon_selected_state(pointer->w, + ICON_SEARCH_FORWARDS)); + break; + case ICON_SEARCH_CANCEL: + ro_gui_dialog_close(dialog_search); + break; + } +} + +/** + * Prepare the search dialog for display + */ +void ro_gui_search_prepare(void) +{ + ro_gui_set_icon_string(dialog_search, ICON_SEARCH_TEXT, ""); + ro_gui_set_icon_selected_state(dialog_search, ICON_SEARCH_FORWARDS, + true); + ro_gui_set_icon_selected_state(dialog_search, ICON_SEARCH_BACKWARDS, + false); + ro_gui_set_icon_selected_state(dialog_search, ICON_SEARCH_START, + false); + ro_gui_set_icon_selected_state(dialog_search, + ICON_SEARCH_CASE_SENSITIVE, false); +} + +/** + * Search for a string in the box tree + * + * \param g gui_window which contains content to search + * \param string the string to search for + * \param from_top whether to display results from the top of the page, or + * the current scroll position + * \param case_sens whether to perform a case sensitive search + * \param forwards direction to search in + */ +void do_search(struct gui_window *g, char *string, bool from_top, bool case_sens, bool forwards) +{ + struct content *c; + struct box *box; + struct list_entry *a, *b; + int x,y; + bool new = false; + + if (!g) + return; + + c = g->bw->current_content; + + /* only handle html contents */ + if (c->type != CONTENT_HTML) + return; + + box = c->data.html.layout->children; + + if (!box) + return; + +// LOG(("'%s' - '%s' (%p, %p) %p (%d, %d) (%d, %d) %d", search_string, string, w, g, found->next, prev_from_top, from_top, prev_case_sens, case_sens, forwards)); + + /* check if we need to start a new search or continue an old one */ + if (!search_string || !w || g != w || !found->next || + prev_from_top != from_top || prev_case_sens != case_sens || + (case_sens && strcmp(string, search_string) != 0) || + (!case_sens && strcasecmp(string, search_string) != 0)) { + if (search_string) + free(search_string); + search_string = strdup(string); + current = 0; + for (a = found->next; a; a = b) { + b = a->next; + free(a); + } + found->prev = 0; + found->next = 0; + if (!find_occurrences(string, box, case_sens)) { + for (a = found->next; a; a = b) { + b = a->next; + free(a); + } + found->prev = 0; + found->next = 0; + return; + } + new = true; + w = g; + prev_from_top = from_top; + prev_case_sens = case_sens; + } + +// LOG(("%d %p %p (%p, %p)", new, found->next, current, current->prev, current->next)); + + if (!found->next) + return; + + if (new && from_top) { + /* new search, beginning at the top of the page */ + current = found->next; + } + else if (new) { + /* new search, beginning from user's current scroll + * position */ + wimp_window_state state; + os_error *error; + + state.w = g->window; + error = xwimp_get_window_state(&state); + if (error) { + LOG(("xwimp_get_window_state: 0x%x: %s", + error->errnum, error->errmess)); + warn_user("WimpError", error->errmess); + return; + } + + for (a = found->next; a; a = a->next) { + box_coords(a->box, &x, &y); + LOG(("%d, %d", y, state.yscroll / 2)); + if (forwards && -y <= state.yscroll / 2) + break; + if (!forwards && -y >= state.yscroll / 2) + break; + } + + if (a) + current = a; + else + return; + } + else { + /* continued search in the direction specified */ + if (forwards && current && current->next) { + current = current->next; + } + else if (!forwards && current && current->prev) { + current = current->prev; + } + } + + if (!current) + return; + + /* get box position and jump to it */ + box_coords(current->box, &x, &y); +// LOG(("%p (%d, %d)", current, x, y)); + gui_window_set_scroll(g, x, y); + +} + +/** + * Finds all occurrences of a given string in the box tree + * + * \param string the string to search for + * \param cur pointer to the current box + * \param case_sens whether to perform a case sensitive search + * \return true on success, false on memory allocation failure + */ +bool find_occurrences(char *string, struct box *cur, bool case_sens) +{ + struct box *a; + char *pos, *buf; + struct list_entry *entry; + + /* ignore this box, if there's no visible text */ + if (!cur->object && cur->text) { + buf = strndup(cur->text, cur->length); + if (case_sens) + pos = strstr(buf, string); + else + pos = strcasestr(buf, string); + free(buf); + if (pos) { + /* found string in box => add to list */ + entry = calloc(1, sizeof(*entry)); + if (!entry) { + warn_user("NoMemory", 0); + return false; + } + entry->box = cur; + entry->next = 0; + entry->prev = found->prev; + if (!found->prev) + found->next = entry; + else + found->prev->next = entry; + found->prev = entry; + } + } + + /* and recurse */ + for (a = cur->children; a; a = a->next) { + if (a->type != BOX_FLOAT_LEFT && a->type != BOX_FLOAT_RIGHT) + if (!find_occurrences(string, a, case_sens)) + return false; + } + + for (a = cur->float_children; a; a = a->next_float) { + if (a->type != BOX_FLOAT_LEFT && a->type != BOX_FLOAT_RIGHT) + if (!find_occurrences(string, a, case_sens)) + return false; + } + + return true; +} + +/* case insensitive strstr */ +char * strcasestr(char *s1, char *s2) +{ + int l1 = strlen(s1), l2 = strlen(s2); + char *e1 = s1 + l1 - l2; + + while (s1 <= e1) { + if (!strncasecmp(s1, s2, l2)) + return s1; + s1++; + } + + return 0; +} + +#endif diff --git a/riscos/window.c b/riscos/window.c index 1a914f707..39d21f8d5 100644 --- a/riscos/window.c +++ b/riscos/window.c @@ -521,7 +521,7 @@ void gui_window_update_box(struct gui_window *g, clear_background = true; while (more) { - + if (use_buffer) ro_gui_buffer_open(&update); if (data->redraw.full_redraw) { if (clear_background) { @@ -1265,6 +1265,11 @@ bool ro_gui_window_keypress(struct gui_window *g, int key, bool toolbar) ro_gui_open_help_page("docs"); return true; + case wimp_KEY_F4: /* Search */ + ro_gui_search_prepare(); + ro_gui_dialog_open_persistant(g->window, dialog_search, false); + return true; + case wimp_KEY_F5: /* Refresh. */ browser_window_reload(g->bw, false); return true; -- cgit v1.2.3