/* * Copyright 2004 John M Bell * Copyright 2005 Adrian Lees * Copyright 2008 Chris Young * * This file is part of NetSurf, http://www.netsurf-browser.org/ * * NetSurf 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; version 2 of the License. * * NetSurf 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, see . */ /** \file * Free text search (implementation) */ #include "utils/config.h" #include #include #include "content/content.h" #include "desktop/browser.h" #include "desktop/gui.h" #include "desktop/search.h" #include "desktop/selection.h" #include "render/box.h" #include "render/html.h" #include "utils/log.h" #include "utils/messages.h" #include "utils/utils.h" #include "amiga/os3support.h" #include "amiga/search.h" #include "amiga/object.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifndef NOF_ELEMENTS #define NOF_ELEMENTS(array) (sizeof(array)/sizeof(*(array))) #endif struct list_entry { unsigned start_idx; /* start position of match */ unsigned end_idx; /* end of match */ struct box *start_box; /* used only for html contents */ struct box *end_box; struct selection *sel; struct list_entry *prev; struct list_entry *next; }; static bool search_insert; static struct find_window *fwin = NULL; search_flags_t ami_search_flags(void); char *ami_search_string(void); static void ami_search_set_status(bool found, void *p); static void ami_search_set_hourglass(bool active, void *p); static void ami_search_add_recent(const char *string, void *p); static void ami_search_set_forward_state(bool active, void *p); static void ami_search_set_back_state(bool active, void *p); static struct search_callbacks ami_search_callbacks = { ami_search_set_forward_state, ami_search_set_back_state, ami_search_set_status, ami_search_set_hourglass, ami_search_add_recent }; /** * Change the displayed search status. * * \param found search pattern matched in text */ void ami_search_open(struct gui_window *gwin) { struct hlcache_handle *c = gwin->shared->bw->current_content; /* only handle html/textplain contents */ if ((!c) || (content_get_type(c) != CONTENT_HTML && content_get_type(c) != CONTENT_TEXTPLAIN)) return; if (gwin->shared->bw->search_context == NULL) search_create_context(gwin->shared->bw, &ami_search_callbacks, NULL); search_insert = true; if(fwin) { if(fwin->gwin->shared->bw->search_context != NULL) search_destroy_context(fwin->gwin->shared->bw-> search_context); ami_search_set_forward_state(true, NULL); ami_search_set_back_state(true, NULL); fwin->gwin->shared->searchwin = NULL; fwin->gwin = gwin; gwin->shared->searchwin = fwin; WindowToFront(fwin->win); ActivateWindow(fwin->win); return; } fwin = AllocVec(sizeof(struct find_window),MEMF_PRIVATE | MEMF_CLEAR); fwin->objects[OID_MAIN] = WindowObject, WA_ScreenTitle,nsscreentitle, WA_Title,messages_get("FindTextNS"), WA_Activate, TRUE, WA_DepthGadget, TRUE, WA_DragBar, TRUE, WA_CloseGadget, TRUE, WA_SizeGadget, TRUE, WA_CustomScreen,scrn, WINDOW_SharedPort,sport, WINDOW_UserData,fwin, WINDOW_IconifyGadget, FALSE, WINDOW_LockHeight,TRUE, WINDOW_Position, WPOS_CENTERSCREEN, WINDOW_ParentGroup, fwin->gadgets[GID_MAIN] = VGroupObject, LAYOUT_AddChild, fwin->gadgets[GID_SEARCHSTRING] = StringObject, GA_ID,GID_SEARCHSTRING, GA_TabCycle,TRUE, GA_RelVerify,TRUE, StringEnd, /* CHILD_Label, LabelObject, LABEL_Text,messages_get("searchstring"), LabelEnd, */ CHILD_WeightedHeight,0, LAYOUT_AddChild, fwin->gadgets[GID_CASE] = CheckBoxObject, GA_ID,GID_CASE, GA_Text,messages_get("CaseSens"), GA_Selected,FALSE, GA_TabCycle,TRUE, GA_RelVerify,TRUE, CheckBoxEnd, LAYOUT_AddChild, fwin->gadgets[GID_SHOWALL] = CheckBoxObject, GA_ID,GID_SHOWALL, GA_Text,messages_get("ShowAll"), GA_Selected,FALSE, GA_TabCycle,TRUE, GA_RelVerify,TRUE, CheckBoxEnd, LAYOUT_AddChild, HGroupObject, LAYOUT_AddChild, fwin->gadgets[GID_PREV] = ButtonObject, GA_ID,GID_PREV, GA_RelVerify,TRUE, GA_Text,messages_get("Prev"), GA_TabCycle,TRUE, GA_Disabled,TRUE, ButtonEnd, CHILD_WeightedHeight,0, LAYOUT_AddChild, fwin->gadgets[GID_NEXT] = ButtonObject, GA_ID,GID_NEXT, GA_RelVerify,TRUE, GA_Text,messages_get("Next"), GA_TabCycle,TRUE, GA_Disabled,TRUE, ButtonEnd, LayoutEnd, CHILD_WeightedHeight,0, EndGroup, EndWindow; fwin->win = (struct Window *)RA_OpenWindow(fwin->objects[OID_MAIN]); fwin->gwin = gwin; fwin->node = AddObject(window_list,AMINS_FINDWINDOW); fwin->node->objstruct = fwin; gwin->shared->searchwin = fwin; } void ami_search_close(void) { if (fwin->gwin->shared->bw->search_context != NULL) search_destroy_context(fwin->gwin->shared->bw->search_context); ami_search_set_forward_state(true, NULL); ami_search_set_back_state(true, NULL); fwin->gwin->shared->searchwin = NULL; DisposeObject(fwin->objects[OID_MAIN]); DelObject(fwin->node); fwin=NULL; } BOOL ami_search_event(void) { /* return TRUE if window destroyed */ ULONG class,result,relevent = 0; ULONG column; uint16 code; search_flags_t flags; while((result = RA_HandleInput(fwin->objects[OID_MAIN],&code)) != WMHI_LASTMSG) { switch(result & WMHI_CLASSMASK) // class { case WMHI_GADGETUP: switch(result & WMHI_GADGETMASK) { case GID_NEXT: search_insert = true; flags = SEARCH_FLAG_FORWARDS | ami_search_flags(); if (search_verify_new( fwin->gwin->shared->bw, &ami_search_callbacks, NULL)) search_step(fwin->gwin->shared->bw->search_context, flags, ami_search_string()); ActivateWindow(fwin->gwin->shared->win); break; case GID_PREV: search_insert = true; flags = ~SEARCH_FLAG_FORWARDS & ami_search_flags(); if (search_verify_new( fwin->gwin->shared->bw, &ami_search_callbacks, NULL)) search_step(fwin->gwin->shared->bw->search_context, flags, ami_search_string()); ActivateWindow(fwin->gwin->shared->win); break; case GID_SEARCHSTRING: if (fwin->gwin->shared-> bw->search_context != NULL) search_destroy_context( fwin->gwin-> shared->bw-> search_context); ami_search_set_forward_state( true, NULL); ami_search_set_back_state( true, NULL); RefreshSetGadgetAttrs(fwin->gadgets[GID_PREV],fwin->win,NULL, GA_Disabled,FALSE, TAG_DONE); RefreshSetGadgetAttrs(fwin->gadgets[GID_NEXT],fwin->win,NULL, GA_Disabled,FALSE, TAG_DONE); break; } break; case WMHI_CLOSEWINDOW: ami_search_close(); return TRUE; break; } } return FALSE; } /** * Change the displayed search status. * \param found search pattern matched in text * \param p the pointer sent to search_verify_new() / search_create_context() */ void ami_search_set_status(bool found, void *p) { } /** * display hourglass while searching * \param active start/stop indicator * \param p the pointer sent to search_verify_new() / search_create_context() */ void ami_search_set_hourglass(bool active, void *p) { SetWindowPointer(fwin->win, WA_BusyPointer,active, WA_PointerDelay,active, TAG_DONE); } /** * retrieve string being searched for from gui */ char *ami_search_string(void) { char *text; GetAttr(STRINGA_TextVal,fwin->gadgets[GID_SEARCHSTRING],(ULONG *)&text); return text; } /** * add search string to recent searches list * front is at liberty how to implement the bare notification * should normally store a strdup() of the string; * core gives no guarantee of the integrity of the const char * * \param string search pattern * \param p the pointer sent to search_verify_new() / search_create_context() */ void ami_search_add_recent(const char *string, void *p) { } /** * activate search forwards button in gui * \param active activate/inactivate * \param p the pointer sent to search_verify_new() / search_create_context() */ void ami_search_set_forward_state(bool active, void *p) { RefreshSetGadgetAttrs(fwin->gadgets[GID_NEXT],fwin->win,NULL, GA_Disabled, active ? FALSE : TRUE, TAG_DONE); } /** * activate search forwards button in gui * \param active activate/inactivate * \param p the pointer sent to search_verify_new() / search_create_context() */ void ami_search_set_back_state(bool active, void *p) { RefreshSetGadgetAttrs(fwin->gadgets[GID_PREV],fwin->win,NULL, GA_Disabled, active ? FALSE : TRUE, TAG_DONE); } /** * retrieve state of 'case sensitive', 'show all' checks in gui */ search_flags_t ami_search_flags(void) { ULONG case_sensitive, showall; search_flags_t flags; GetAttr(GA_Selected,fwin->gadgets[GID_CASE],(ULONG *)&case_sensitive); GetAttr(GA_Selected,fwin->gadgets[GID_SHOWALL],(ULONG *)&showall); flags = 0 | (case_sensitive ? SEARCH_FLAG_CASE_SENSITIVE : 0) | (showall ? SEARCH_FLAG_SHOWALL : 0); return flags; }