]> www.fi.muni.cz Git - evince.git/blob - backend/djvu/djvu-text.c
Translation updated
[evince.git] / backend / djvu / djvu-text.c
1 /*
2  * Implements search and copy functionality for Djvu files.
3  * Copyright (C) 2006 Michael Hofmann <mh21@piware.de>
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 2, or (at your option)
8  * any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18  */
19
20 #include <config.h>
21 #include <string.h>
22 #include <glib.h>
23 #include <libdjvu/miniexp.h>
24
25 #include "djvu-document-private.h"
26 #include "djvu-document.h"
27 #include "djvu-text.h"
28 #include "djvu-text-page.h"
29 #include "ev-document-find.h"
30 #include "ev-document.h"
31
32
33
34 struct _DjvuText {
35         DjvuDocument *document;
36         gboolean case_sensitive;
37         char *text;
38         GList **pages;
39         guint idle;
40         int start_page;
41         int search_page;
42 };
43
44 /**
45  * djvu_text_idle_callback:
46  * @data: #DjvuText instance
47  * 
48  * Idle callback that processes one page at a time.
49  * 
50  * Returns: whether there are more pages to be processed
51  */
52 static gboolean 
53 djvu_text_idle_callback (void *data)
54 {
55         DjvuText *djvu_text = (DjvuText *) data;
56         DjvuDocument *djvu_document = djvu_text->document;
57         int n_pages;
58         miniexp_t page_text;
59
60         ev_document_doc_mutex_lock ();
61         while ((page_text =
62                 ddjvu_document_get_pagetext (djvu_document->d_document,
63                                              djvu_text->search_page,
64                                              "char")) == miniexp_dummy)
65                 djvu_handle_events (djvu_document, TRUE);
66
67         if (page_text != miniexp_nil) {
68                 DjvuTextPage *page = djvu_text_page_new (page_text);
69                 djvu_text_page_prepare_search (page, djvu_text->case_sensitive); 
70                 if (page->links->len > 0) {
71                         djvu_text_page_search (page, djvu_text->text);
72                         djvu_text->pages[djvu_text->search_page] = page->results;
73                         ev_document_find_changed (EV_DOCUMENT_FIND
74                                                   (djvu_document),
75                                                   djvu_text->search_page);
76                 }
77                 djvu_text_page_free (page);
78                 ddjvu_miniexp_release (djvu_document->d_document,
79                                        page_text);
80         }
81         ev_document_doc_mutex_unlock ();
82
83         n_pages =
84             djvu_document_get_n_pages (EV_DOCUMENT (djvu_text->document));
85         djvu_text->search_page += 1;
86         if (djvu_text->search_page == n_pages) {
87                 /* wrap around */
88                 djvu_text->search_page = 0;
89         }
90
91         if (djvu_text->search_page != djvu_text->start_page)
92                 return TRUE;
93
94         /* We're done. */
95         djvu_text->idle = 0;
96         /* will return FALSE to remove */
97         return FALSE;
98 }
99
100 /**
101  * djvu_text_new:
102  * @djvu_document: document to search
103  * @start_page: first page to search
104  * @case_sensitive: uses g_utf8_case_fold() to enable case-insensitive 
105  *      searching
106  * @text: text to search
107  * 
108  * Creates a new #DjvuText instance to enable searching. An idle call
109  * is used to process all pages starting from @start_page.
110  * 
111  * Returns: newly created instance
112  */
113 DjvuText *
114 djvu_text_new (DjvuDocument *djvu_document,
115                int           start_page,
116                gboolean      case_sensitive, 
117                const char   *text)
118 {
119         DjvuText *djvu_text;
120         int n_pages;
121         int i;
122
123         n_pages = djvu_document_get_n_pages (EV_DOCUMENT (djvu_document));
124
125         djvu_text = g_new0 (DjvuText, 1);
126
127         if (case_sensitive)
128                 djvu_text->text = g_strdup (text);
129         else
130                 djvu_text->text = g_utf8_casefold (text, -1);
131         djvu_text->pages = g_new0 (GList *, n_pages);
132         for (i = 0; i < n_pages; i++) {
133                 djvu_text->pages[i] = NULL;
134         }
135
136         djvu_text->document = djvu_document;
137
138         /* We add at low priority so the progress bar repaints */
139         djvu_text->idle = g_idle_add_full (G_PRIORITY_LOW,
140                                         djvu_text_idle_callback,
141                                         djvu_text, NULL);
142
143         djvu_text->case_sensitive = case_sensitive;
144         djvu_text->start_page = start_page;
145         djvu_text->search_page = start_page;
146
147         return djvu_text;
148 }
149
150 /**
151  * djvu_text_copy:
152  * @djvu_document: document to search
153  * @page: page to search
154  * @rectangle: rectangle to copy
155  * 
156  * Copies and returns the text in the given rectangle.
157  * 
158  * Returns: newly allocated text or NULL of none is available
159  */
160 char *
161 djvu_text_copy (DjvuDocument *djvu_document,
162                 int           page,
163                 EvRectangle  *rectangle)
164 {
165         miniexp_t page_text;
166         char* text = NULL;
167
168         while ((page_text =
169                 ddjvu_document_get_pagetext (djvu_document->d_document,
170                                              page, "char")) == miniexp_dummy)
171                 djvu_handle_events (djvu_document, TRUE);
172
173         if (page_text != miniexp_nil) {
174                 DjvuTextPage *page = djvu_text_page_new (page_text);
175                 text = djvu_text_page_copy (page, rectangle);
176                 djvu_text_page_free (page);
177                 ddjvu_miniexp_release (djvu_document->d_document, page_text);
178         }
179         
180         return text;
181 }
182
183 /**
184  * djvu_text_free:
185  * @djvu_text: instance to free
186  * 
187  * Frees the given #DjvuText instance.
188  */
189 void djvu_text_free (DjvuText * djvu_text)
190 {
191         DjvuDocument *djvu_document = djvu_text->document;
192         int n_pages;
193         int i;
194
195         if (djvu_text->idle != 0)
196                 g_source_remove (djvu_text->idle);
197
198         n_pages = djvu_document_get_n_pages (EV_DOCUMENT (djvu_document));
199         for (i = 0; i < n_pages; i++) {
200                 g_list_foreach (djvu_text->pages[i], (GFunc) g_free, NULL);
201                 g_list_free (djvu_text->pages[i]);
202         }
203
204         g_free (djvu_text->text);
205 }
206
207 /**
208  * djvu_text_get_text:
209  * @djvu_text: #DjvuText instance
210  * 
211  * Returns the search text. This is mainly to be able to avoid reinstantiation 
212  * for the same search text.
213  * 
214  * Returns: the text this instance of #DjvuText is looking for
215  */
216 const char *
217 djvu_text_get_text (DjvuText *djvu_text)
218 {
219         return djvu_text->text;
220 }
221
222 /**
223  * djvu_text_n_results:
224  * @djvu_text: #DjvuText instance
225  * @page: page number
226  * 
227  * Returns the number of search results available for the given page.
228  * 
229  * Returns: number of search results
230  */
231 int 
232 djvu_text_n_results (DjvuText *djvu_text, 
233                      int       page)
234 {
235         return g_list_length (djvu_text->pages[page]);
236 }
237
238 /**
239  * djvu_text_has_results:
240  * @djvu_text: #DjvuText instance
241  * @page: page number
242  * 
243  * Returns whether there are search results available for the given page.
244  * This method executes faster than djvu_text_n_results().
245  * 
246  * Returns: whether there are search results
247  */
248 int 
249 djvu_text_has_results (DjvuText *djvu_text, 
250                        int       page)
251 {
252         return djvu_text->pages[page] != NULL;
253 }
254
255 /**
256  * djvu_text_get_result:
257  * @djvu_text: #DjvuText instance
258  * @page: page number
259  * @n_result: result number
260  * 
261  * Returns the n-th search result of a given page. The coordinates are 
262  * Djvu-specific and need to be processed to be compatible with the Evince
263  * coordinate system. The result may span several lines!
264  * 
265  * Returns: the rectangle for the search result
266  */
267 EvRectangle *
268 djvu_text_get_result (DjvuText *djvu_text, 
269                       int       page,
270                       int       n_result)
271 {
272         return (EvRectangle *) g_list_nth_data (djvu_text->pages[page],
273                                                 n_result);
274 }
275
276 /**
277  * djvu_text_get_progress:
278  * @djvu_text: #DjvuText instance
279  * 
280  * Returns the percentage of pages done searching.
281  * 
282  * Returns: the progress as value between 0 and 1
283  */
284 double
285 djvu_text_get_progress (DjvuText *djvu_text)
286 {
287         int pages_done;
288         int n_pages;
289
290         n_pages =
291             djvu_document_get_n_pages (EV_DOCUMENT (djvu_text->document));
292         if (djvu_text->search_page > djvu_text->start_page) {
293                 pages_done = djvu_text->search_page - djvu_text->start_page + 1;
294         } else if (djvu_text->search_page == djvu_text->start_page) {
295                 pages_done = n_pages;
296         } else {
297                 pages_done =
298                     n_pages - djvu_text->start_page + djvu_text->search_page;
299         }
300         return pages_done / (double) n_pages;
301 }
302