summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorrootavish <[email protected]>2014-08-06 15:34:02 +0530
committerrootavish <[email protected]>2014-08-06 15:34:02 +0530
commit56880392a6678ccec12bbec016939597acd49b07 (patch)
treefd127f796f5127a63f564a5dea82d64f422a9580
parent5f3f572777cfcb64a92a4671fb2aff5faa5cefa4 (diff)
downloadatril-56880392a6678ccec12bbec016939597acd49b07.tar.bz2
atril-56880392a6678ccec12bbec016939597acd49b07.tar.xz
Searching in epub documents
I added the capability to search through documents. The search is quite buggy, and we'll be taking care of each bug one at a time.
-rw-r--r--backend/epub/epub-document.c92
-rw-r--r--libdocument/ev-document-find.c2
-rw-r--r--libdocument/ev-document-find.h4
-rw-r--r--libview/ev-jobs.c8
-rw-r--r--libview/ev-web-view.c273
-rw-r--r--libview/ev-web-view.h10
-rw-r--r--shell/ev-window.c14
7 files changed, 271 insertions, 132 deletions
diff --git a/backend/epub/epub-document.c b/backend/epub/epub-document.c
index e9443c09..3a574151 100644
--- a/backend/epub/epub-document.c
+++ b/backend/epub/epub-document.c
@@ -29,14 +29,13 @@
#include "ev-document-misc.h"
#include <libxml/parser.h>
#include <libxml/xmlmemory.h>
-
+#include <libxml/HTMLparser.h>
#include <config.h>
#include <glib/gi18n.h>
#include <glib/gstdio.h>
#include <gtk/gtk.h>
-#include <stdio.h>
/*For strcasestr(),strstr()*/
#include <string.h>
@@ -130,47 +129,72 @@ epub_document_thumbnails_get_thumbnail (EvDocumentThumbnails *document,
}
static gboolean
+in_tag(const char* found)
+{
+ const char* bracket = found ;
+
+ /* Since the dump started with the body tag, the '<' will be the first
+ * character in the haystack.
+ */
+ while (*bracket != '<') {
+ bracket--;
+ if (*bracket == '>') {
+ /*We encounted a close brace before an open*/
+ return FALSE ;
+ }
+ }
+
+ return TRUE;
+}
+
+static int
+get_substr_count(const char * haystack,const char *needle,gboolean case_sensitive)
+{
+ const char* tmp = haystack ;
+ char* (*string_compare_function)(const char*,const char*);
+ int count=0;
+ if (case_sensitive) {
+ string_compare_function = strstr ;
+ }
+ else {
+ string_compare_function = strcasestr;
+ }
+
+ while ((tmp=string_compare_function(tmp,needle))) {
+ if (!in_tag(tmp)) {
+ count++;
+ }
+ tmp = tmp + strlen(needle);
+ }
+
+ return count;
+}
+
+static guint
epub_document_check_hits(EvDocumentFind *document_find,
EvPage *page,
const gchar *text,
gboolean case_sensitive)
{
gchar *filepath = g_filename_from_uri((gchar*)page->backend_page,NULL,NULL);
- FILE *fp = fopen(filepath,"r");
- GString *buffer;
- gchar *found ;
-
- while (!feof(fp)) {
- gchar c;
- gint pos=0;
- buffer = g_string_sized_new (1024);
-
- while ((c = fgetc(fp)) != '\n' && !feof(fp)) {
- g_string_insert_c(buffer,pos++,c);
- }
+ htmlDocPtr htmldoc = xmlParseFile(filepath);
+ htmlNodePtr htmltag = xmlDocGetRootElement(htmldoc);
+ int count=0;
+ htmlNodePtr bodytag = htmltag->xmlChildrenNode;
- g_string_insert_c(buffer,pos,'\0');
-
- if (case_sensitive) {
- if ((found = strstr(buffer->str,text)) != NULL) {
- g_string_free(buffer,TRUE);
- fclose(fp);
- return TRUE;
- }
- }
- else {
-
- if ( (found = strcasestr(buffer->str,text)) != NULL) {
- g_string_free(buffer,TRUE);
- fclose(fp);
- return TRUE;
- }
- }
- g_string_free(buffer,TRUE);
+ while ( xmlStrcmp(bodytag->name,(xmlChar*)"body") ) {
+ bodytag = bodytag->next;
}
- fclose(fp);
- return FALSE;
+ xmlBufferPtr bodybuffer = xmlBufferCreate();
+ xmlNodeDump(bodybuffer,htmldoc,bodytag,0,1);
+
+ count = get_substr_count((char*)bodybuffer->content,text,case_sensitive);
+
+ xmlBufferFree(bodybuffer);
+ xmlFreeDoc(htmldoc);
+
+ return count;
}
static gboolean
diff --git a/libdocument/ev-document-find.c b/libdocument/ev-document-find.c
index c22b913d..92dfffe5 100644
--- a/libdocument/ev-document-find.c
+++ b/libdocument/ev-document-find.c
@@ -40,7 +40,7 @@ ev_document_find_find_text (EvDocumentFind *document_find,
return iface->find_text (document_find, page, text, case_sensitive);
}
-gboolean
+guint
ev_document_find_check_for_hits(EvDocumentFind *document_find,
EvPage *page,
const gchar *text,
diff --git a/libdocument/ev-document-find.h b/libdocument/ev-document-find.h
index 7fb5d22c..2b6ba68b 100644
--- a/libdocument/ev-document-find.h
+++ b/libdocument/ev-document-find.h
@@ -53,7 +53,7 @@ struct _EvDocumentFindInterface
const gchar *text,
gboolean case_sensitive);
- gboolean (* check_for_hits)(EvDocumentFind *document_find,
+ guint (* check_for_hits) (EvDocumentFind *document_find,
EvPage *page,
const gchar *text,
gboolean case_sensitive);
@@ -65,7 +65,7 @@ GList *ev_document_find_find_text (EvDocumentFind *document_find,
const gchar *text,
gboolean case_sensitive);
-gboolean ev_document_find_check_for_hits(EvDocumentFind *document_find,
+guint ev_document_find_check_for_hits (EvDocumentFind *document_find,
EvPage *page,
const gchar *text,
gboolean case_sensitive);
diff --git a/libview/ev-jobs.c b/libview/ev-jobs.c
index 155990e9..3a7dfd27 100644
--- a/libview/ev-jobs.c
+++ b/libview/ev-jobs.c
@@ -1379,7 +1379,7 @@ ev_job_find_run (EvJob *job)
ev_page = ev_document_get_page (job->document, job_find->current_page);
if (job->document->iswebdocument) {
- job_find->has_results = ev_document_find_check_for_hits(find, ev_page, job_find->text,
+ job_find->results[job_find->current_page] = ev_document_find_check_for_hits(find, ev_page, job_find->text,
job_find->case_sensitive);
}else {
matches = ev_document_find_find_text (find, ev_page, job_find->text,
@@ -1393,10 +1393,14 @@ ev_job_find_run (EvJob *job)
if (!job_find->has_results && !job->document->iswebdocument) {
job_find->has_results = (matches != NULL);
}
-
+ else if (!job_find->has_results && job->document->iswebdocument){
+ job_find->has_results = (job_find->results[job_find->current_page] > 0);
+ }
+
if (job->document->iswebdocument == FALSE) {
job_find->pages[job_find->current_page] = matches;
}
+
g_signal_emit (job_find, job_find_signals[FIND_UPDATED], 0, job_find->current_page);
job_find->current_page = (job_find->current_page + 1) % job_find->n_pages;
diff --git a/libview/ev-web-view.c b/libview/ev-web-view.c
index 152e2542..0756b0f0 100644
--- a/libview/ev-web-view.c
+++ b/libview/ev-web-view.c
@@ -37,13 +37,19 @@
#define EV_IS_WEB_VIEW_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), EV_TYPE_WEB_VIEW))
#define EV_WEB_VIEW_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), EV_TYPE_WEB_VIEW, EvWebViewClass))
+ typedef enum {
+ EV_WEB_VIEW_FIND_NEXT,
+ EV_WEB_VIEW_FIND_PREV
+ } EvWebViewFindDirection;
+
typedef struct _SearchParams {
gboolean case_sensitive;
- guint page_current;
gboolean search_jump;
gchar* search_string;
- guint on_result;
+ gint on_result;
guint n_results;
+ guint *results;
+ EvWebViewFindDirection direction;
}SearchParams;
struct _EvWebView
@@ -65,20 +71,21 @@ struct _EvWebViewClass
/*** Callbacks ***/
static void ev_web_view_change_page (EvWebView *webview,
- gint new_page);
+ gint new_page);
static void ev_web_view_page_changed_cb (EvDocumentModel *model,
gint old_page,
gint new_page,
EvWebView *webview);
/*** GObject ***/
-static void ev_web_view_dispose (GObject *object);
+static void ev_web_view_dispose (GObject *object);
-static void ev_web_view_finalize (GObject *object);
+static void ev_web_view_finalize (GObject *object);
static void ev_web_view_class_init (EvWebViewClass *klass);
static void ev_web_view_init (EvWebView *webview);
G_DEFINE_TYPE (EvWebView, ev_web_view, WEBKIT_TYPE_WEB_VIEW)
+
static void
web_view_update_range_and_current_page (EvWebView *webview)
{
@@ -106,12 +113,18 @@ ev_web_view_dispose (GObject *object)
if (webview->model) {
g_object_unref(webview->model);
webview->model = NULL;
- };
+ }
+
if (webview->hlink) {
g_free(webview->hlink);
webview->hlink = NULL;
}
+ if (webview->search) {
+ g_free(webview->search);
+ webview->search = NULL;
+ }
+
G_OBJECT_CLASS (ev_web_view_parent_class)->dispose (object);
}
@@ -132,7 +145,10 @@ ev_web_view_init (EvWebView *webview)
webview->current_page = 0;
webview->search = g_new0(SearchParams, 1);
-
+ webview->search->search_string = NULL;
+ webview->search->on_result = -1 ;
+ webview->search->n_results = 0;
+ webview->search->results = NULL;
webview->search->search_jump = TRUE ;
webview->fullscreen = FALSE;
@@ -400,112 +416,205 @@ ev_web_view_handle_link(EvWebView *webview,EvLink *link)
}
/* Searching */
-void
-ev_web_view_find_next(EvWebView *webview)
-{
- /*First search for the next item on the current page*/
- webkit_web_view_search_text (WEBKIT_WEB_VIEW(webview),
- webview->search->search_string,
- webview->search->case_sensitive,
- TRUE,
- FALSE);
-}
-void
-ev_web_view_find_previous(EvWebView *webview)
+static void
+jump_to_find_result_on_page(EvWebView *webview,EvWebViewFindDirection direction)
{
+ gboolean forward,wrap;
+
+ if (direction == EV_WEB_VIEW_FIND_NEXT) {
+ forward = TRUE;
+ wrap = FALSE;
+ }
+ else {
+ forward = FALSE;
+ wrap = FALSE;
+ }
+
webkit_web_view_search_text (WEBKIT_WEB_VIEW(webview),
- webview->search->search_string,
- webview->search->case_sensitive,
- FALSE,
- TRUE);
+ webview->search->search_string,
+ webview->search->case_sensitive,
+ forward,
+ wrap);
}
-void
-ev_web_view_find_set_highlight_search(EvWebView *webview, gboolean visible)
+static void
+jump_to_find_result(EvWebView *webview,
+ GParamSpec *pspec,
+ gpointer data)
{
- webkit_web_view_set_highlight_text_matches(WEBKIT_WEB_VIEW(webview),visible);
+ gint n_results;
+ gboolean forward ;
+ gboolean wrap ;
+
+ if (webkit_web_view_get_load_status(WEBKIT_WEB_VIEW(webview)) != WEBKIT_LOAD_FINISHED) {
+ return;
+ }
+
+ if (!webview->search->search_string) {
+ return;
+ }
+
+ n_results = webkit_web_view_mark_text_matches (WEBKIT_WEB_VIEW(webview),
+ webview->search->search_string,
+ webview->search->case_sensitive,
+ 0);
+
+ ev_web_view_find_set_highlight_search(webview,TRUE);
+
+ if (webview->search->direction == EV_WEB_VIEW_FIND_NEXT) {
+ forward = TRUE ;
+ wrap = FALSE;
+ }
+ else {
+ forward = FALSE;
+ wrap = TRUE ;
+ }
+
+ if (n_results > 0 && webview->search->on_result < n_results) {
+ webkit_web_view_search_text (WEBKIT_WEB_VIEW(webview),
+ webview->search->search_string,
+ webview->search->case_sensitive,
+ forward,
+ wrap);
+
+ webview->search->search_jump = FALSE;
+ }
}
-typedef struct _FindCBStruct {
- EvJobFind *job;
- gint page;
-}FindCBStruct;
+static gint
+ev_web_view_find_get_n_results (EvWebView *webview, gint page)
+{
+ return webview->search->results[page];
+}
+/**
+ * jump_to_find_page
+ * @webview: #EvWebView instance
+ * @direction: Direction to look
+ * @shift: Shift from current page
+ *
+ * Jumps to the first page that has occurences of searched word.
+ * Uses a direction where to look and a shift from current page.
+ *
+ */
static void
-find_page_change_cb(WebKitWebView *webview,
- WebKitWebFrame *webframe,
- FindCBStruct *findcbs)
-{
- findcbs->job->results[findcbs->page] = webkit_web_view_mark_text_matches(WEBKIT_WEB_VIEW(webview),
- findcbs->job->text,
- findcbs->job->case_sensitive,
- 0);
- ev_web_view_find_set_highlight_search(EV_WEB_VIEW(webview), TRUE);
-
- webkit_web_view_search_text (WEBKIT_WEB_VIEW(webview),
- findcbs->job->text,
- findcbs->job->case_sensitive,
- TRUE,
- FALSE);
+jump_to_find_page (EvWebView *webview, EvWebViewFindDirection direction, gint shift)
+{
+ int n_pages, i;
+
+ n_pages = ev_document_get_n_pages (webview->document);
+
+ for (i = 0; i < n_pages; i++) {
+ int page;
+
+ if (direction == EV_WEB_VIEW_FIND_NEXT)
+ page = webview->current_page + i;
+ else
+ page = webview->current_page - i;
+ page += shift;
+
+ if (page >= n_pages) {
+ page = page - n_pages;
+ } else if (page < 0)
+ page = page + n_pages;
+
+ if (page == webview->current_page)
+ jump_to_find_result_on_page(webview,EV_WEB_VIEW_FIND_NEXT);
+
+ if (ev_web_view_find_get_n_results (webview, page) > 0) {
+ webkit_web_view_unmark_text_matches (WEBKIT_WEB_VIEW(webview));
+ ev_document_model_set_page (webview->model, page);
+ webview->search->direction = direction;
+ break;
+ }
+ }
}
+
void
-ev_web_view_find_changed(EvWebView *webview, gint page_found_on,EvJobFind *job)
+ev_web_view_find_changed (EvWebView *webview, guint *results, gchar *text,gboolean case_sensitive)
{
- if (job->has_results == FALSE)
- return;
+ webview->search->results = results;
+ webview->search->search_string = g_strdup(text);
+ webview->search->case_sensitive = case_sensitive;
if (webview->search->search_jump == TRUE) {
+ jump_to_find_page (webview, EV_WEB_VIEW_FIND_NEXT, 0);
+ } else {
+ jump_to_find_result_on_page(webview,EV_WEB_VIEW_FIND_NEXT);
+ }
+}
- webview->search->on_result = 1;
- webview->search->case_sensitive = job->case_sensitive;
- webview->search->search_string = g_strdup(job->text);
- webview->search->search_jump = FALSE;
-
- if (page_found_on != webview->current_page) {
- ev_web_view_change_page(webview, page_found_on);
+void
+ev_web_view_find_next (EvWebView *webview)
+{
+ gint n_results;
- FindCBStruct *findstruct = g_new0 (FindCBStruct, 1);
- findstruct->job = job;
- findstruct->page = page_found_on;
-
- g_signal_connect(WEBKIT_WEB_VIEW(webview),"document-load-finished",G_CALLBACK(find_page_change_cb),findstruct);
- }
- else {
- job->results[webview->current_page] = webkit_web_view_mark_text_matches(WEBKIT_WEB_VIEW(webview),
- job->text,
- job->case_sensitive,
- 0);
+ n_results = ev_web_view_find_get_n_results (webview, webview->current_page);
+ webview->search->on_result++;
- ev_web_view_find_set_highlight_search(webview, TRUE);
- }
+ if (webview->search->on_result >= n_results) {
+ webview->search->on_result = 0;
+ jump_to_find_page (webview, EV_WEB_VIEW_FIND_NEXT, 1);
+ }
+ else {
+ jump_to_find_result_on_page (webview, EV_WEB_VIEW_FIND_NEXT);
}
}
void
-ev_web_view_find_search_changed(EvWebView *webview)
+ev_web_view_find_previous (EvWebView *webview)
{
- ev_web_view_find_set_highlight_search(webview,FALSE);
- webkit_web_view_unmark_text_matches (WEBKIT_WEB_VIEW(webview));
+ webview->search->on_result--;
+
+ if (webview->search->on_result < 0) {
+ jump_to_find_page (webview, EV_WEB_VIEW_FIND_PREV, -1);
+ webview->search->on_result = MAX (0, ev_web_view_find_get_n_results (webview, webview->current_page) - 1);
+ } else {
+ jump_to_find_result_on_page (webview,EV_WEB_VIEW_FIND_PREV);
+ }
+}
+
+void
+ev_web_view_find_search_changed (EvWebView *webview,gboolean visible)
+{
+ /* search string has changed, focus on new search result */
+ if (visible) {
+ g_signal_connect(webview,
+ "notify::load-status",
+ G_CALLBACK(jump_to_find_result),
+ NULL);
+ }
+ else {
+ g_signal_handlers_disconnect_by_func(webview,
+ jump_to_find_result,
+ NULL);
+ }
+ webkit_web_view_unmark_text_matches(WEBKIT_WEB_VIEW(webview));
+
webview->search->search_jump = TRUE;
+
+ if (webview->search->search_string) {
+ g_free(webview->search->search_string);
+ webview->search->search_string = NULL;
+ }
}
void
-ev_web_view_find_cancel(EvWebView *webview)
+ev_web_view_find_set_highlight_search (EvWebView *webview, gboolean value)
{
- ev_web_view_find_set_highlight_search(webview,FALSE);
- webkit_web_view_unmark_text_matches (WEBKIT_WEB_VIEW(webview));
+ webkit_web_view_set_highlight_text_matches (WEBKIT_WEB_VIEW(webview),value);
}
void
-ev_web_view_empty_search(EvWebView *webview)
-{
- SearchParams *search = webview->search ;
- search->case_sensitive = FALSE;
- if (search->search_string)
- g_free(search->search_string);
- search->search_string = NULL;
- search->search_jump = TRUE ;
+ev_web_view_find_cancel (EvWebView *webview)
+{
+ g_signal_handlers_disconnect_by_func(webview,
+ jump_to_find_result,
+ NULL);
+
+ webkit_web_view_unmark_text_matches(WEBKIT_WEB_VIEW(webview));
+ ev_web_view_find_set_highlight_search(webview,FALSE);
}
/* Selection */
diff --git a/libview/ev-web-view.h b/libview/ev-web-view.h
index aa2d5492..751e7381 100644
--- a/libview/ev-web-view.h
+++ b/libview/ev-web-view.h
@@ -63,11 +63,15 @@ void ev_web_view_handle_link (EvWebView *webview, EvLink* link);
/* Searching */
void ev_web_view_find_next (EvWebView *webview);
void ev_web_view_find_previous (EvWebView *webview);
-void ev_web_view_find_changed (EvWebView *webview, gint page_found_on,EvJobFind *job);
-void ev_web_view_find_search_changed (EvWebView *webview);
+
+void ev_web_view_find_changed (EvWebView *webview,
+ guint *results,
+ gchar *text,
+ gboolean case_sensitive);
+
+void ev_web_view_find_search_changed (EvWebView *webview,gboolean visible);
void ev_web_view_find_cancel (EvWebView *webview);
void ev_web_view_find_set_highlight_search (EvWebView *webview,gboolean visible);
-void ev_web_view_empty_search (EvWebView *webview);
/* Selection */
gboolean ev_web_view_get_has_selection (EvWebView *webview);
diff --git a/shell/ev-window.c b/shell/ev-window.c
index 43963fec..dfb3d7f2 100644
--- a/shell/ev-window.c
+++ b/shell/ev-window.c
@@ -3668,7 +3668,7 @@ static void
ev_window_cmd_scroll_forward (GtkAction *action, EvWindow *window)
{
/*If the webview is occupying the window*/
- if ( window->priv->document->iswebdocument == FALSE) return ;
+ if ( window->priv->document->iswebdocument == TRUE) return ;
ev_view_scroll (EV_VIEW (window->priv->view), GTK_SCROLL_PAGE_FORWARD, FALSE);
}
@@ -3677,7 +3677,7 @@ static void
ev_window_cmd_scroll_backward (GtkAction *action, EvWindow *window)
{
/*If the webview is occupying the window*/
- if ( window->priv->document->iswebdocument == FALSE ) return ;
+ if ( window->priv->document->iswebdocument == TRUE ) return ;
ev_view_scroll (EV_VIEW (window->priv->view), GTK_SCROLL_PAGE_BACKWARD, FALSE);
}
@@ -5069,7 +5069,7 @@ ev_window_find_job_updated_cb (EvJobFind *job,
{
ev_window_update_actions (ev_window);
if (ev_window->priv->document->iswebdocument == TRUE ) {
- ev_web_view_find_changed(EV_WEB_VIEW(ev_window->priv->webview), page,job);
+ ev_web_view_find_changed(EV_WEB_VIEW(ev_window->priv->webview), job->results,job->text, job->case_sensitive);
}
else {
ev_view_find_changed (EV_VIEW (ev_window->priv->view),
@@ -5150,7 +5150,7 @@ find_bar_search_changed_cb (EggFindBar *find_bar,
search_string = egg_find_bar_get_search_string (find_bar);
if (ev_window->priv->document->iswebdocument) {
- ev_web_view_find_search_changed(EV_WEB_VIEW(ev_window->priv->webview));
+ ev_web_view_find_search_changed(EV_WEB_VIEW(ev_window->priv->webview),TRUE);
} else {
ev_view_find_search_changed (EV_VIEW (ev_window->priv->view));
}
@@ -5174,9 +5174,7 @@ find_bar_search_changed_cb (EggFindBar *find_bar,
ev_window_update_actions (ev_window);
egg_find_bar_set_status_text (EGG_FIND_BAR (ev_window->priv->find_bar),
NULL);
- if (ev_window->priv->document->iswebdocument == TRUE) {
- ev_web_view_empty_search(EV_WEB_VIEW(ev_window->priv->webview));
- } else {
+ if (ev_window->priv->document->iswebdocument == FALSE) {
gtk_widget_queue_draw (GTK_WIDGET (ev_window->priv->view));
}
}
@@ -5199,7 +5197,7 @@ find_bar_visibility_changed_cb (EggFindBar *find_bar,
}
else {
ev_web_view_find_set_highlight_search(EV_WEB_VIEW(ev_window->priv->webview),visible);
- ev_web_view_find_search_changed(EV_WEB_VIEW(ev_window->priv->webview));
+ ev_web_view_find_search_changed(EV_WEB_VIEW(ev_window->priv->webview),visible);
}
ev_window_update_actions (ev_window);