]> www.fi.muni.cz Git - evince.git/blob - ev-view.c
99c688e9445a65a5e6dea04d33875d8833dbe24f
[evince.git] / ev-view.c
1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8; c-indent-level: 8 -*- */
2 /* this file is part of evince, a gnome document viewer
3  *
4  *  Copyright (C) 2004 Red Hat, Inc
5  *
6  * Evince is free software; you can redistribute it and/or modify it
7  * under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * Evince is distributed in the hope that it will be useful, but
12  * WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
19  */
20
21 #include <gtk/gtkalignment.h>
22 #include <glib/gi18n.h>
23
24 #include "ev-marshal.h"
25 #include "ev-view.h"
26 #include "ev-document-find.h"
27
28 #define EV_VIEW_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), EV_TYPE_VIEW, EvViewClass))
29 #define EV_IS_VIEW_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), EV_TYPE_VIEW))
30 #define EV_VIEW_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), EV_TYPE_VIEW, EvViewClass))
31
32 struct _EvView {
33         GtkWidget parent_instance;
34
35         EvDocument *document;
36         
37         GdkWindow *bin_window;
38         
39         int scroll_x;
40         int scroll_y;
41
42         GtkAdjustment *hadjustment;
43         GtkAdjustment *vadjustment;
44
45         GArray *find_results;
46         int results_on_this_page;
47         int next_page_with_result;
48         double find_percent_complete;
49
50         double scale;
51 };
52
53 struct _EvViewClass {
54         GtkWidgetClass parent_class;
55
56         void    (*set_scroll_adjustments) (EvView         *view,
57                                            GtkAdjustment  *hadjustment,
58                                            GtkAdjustment  *vadjustment);
59         
60         /* Should this be notify::page? */
61         void    (*page_changed)           (EvView         *view);
62 };
63
64 static guint page_changed_signal = 0;
65
66 static void ev_view_set_scroll_adjustments (EvView         *view,
67                                             GtkAdjustment  *hadjustment,
68                                             GtkAdjustment  *vadjustment);
69      
70 G_DEFINE_TYPE (EvView, ev_view, GTK_TYPE_WIDGET)
71
72 /*** Helper functions ***/       
73      
74 static void
75 view_update_adjustments (EvView *view)
76 {
77         int old_x = view->scroll_x;
78         int old_y = view->scroll_y;
79   
80         if (view->hadjustment)
81                 view->scroll_x = view->hadjustment->value;
82         else
83                 view->scroll_x = 0;
84
85         if (view->vadjustment)
86                 view->scroll_y = view->vadjustment->value;
87         else
88                 view->scroll_y = 0;
89   
90         if (GTK_WIDGET_REALIZED (view) &&
91             (view->scroll_x != old_x || view->scroll_y != old_y)) {
92                 gdk_window_move (view->bin_window, - view->scroll_x, - view->scroll_y);
93                 gdk_window_process_updates (view->bin_window, TRUE);
94         }
95 }
96
97 static void
98 view_set_adjustment_values (EvView         *view,
99                             GtkOrientation  orientation)
100 {
101         GtkWidget *widget = GTK_WIDGET (view);
102         GtkAdjustment *adjustment;
103         gboolean value_changed = FALSE;
104         int requisition;
105         int allocation;
106
107         if (orientation == GTK_ORIENTATION_HORIZONTAL)  {
108                 requisition = widget->requisition.width;
109                 allocation = widget->allocation.width;
110                 adjustment = view->hadjustment;
111         } else {
112                 requisition = widget->requisition.height;
113                 allocation = widget->allocation.height;
114                 adjustment = view->vadjustment;
115         }
116
117         if (!adjustment)
118                 return;
119   
120         adjustment->page_size = allocation;
121         adjustment->step_increment = allocation * 0.1;
122         adjustment->page_increment = allocation * 0.9;
123         adjustment->lower = 0;
124         adjustment->upper = MAX (allocation, requisition);
125
126         if (adjustment->value > adjustment->upper - adjustment->page_size) {
127                 adjustment->value = adjustment->upper - adjustment->page_size;
128                 value_changed = TRUE;
129         }
130
131         gtk_adjustment_changed (adjustment);
132         if (value_changed)
133                 gtk_adjustment_value_changed (adjustment);
134 }
135
136 /*** Virtual function implementations ***/       
137      
138 static void
139 ev_view_finalize (GObject *object)
140 {
141         EvView *view = EV_VIEW (object);
142
143         if (view->document)
144                 g_object_unref (view->document);
145
146         ev_view_set_scroll_adjustments (view, NULL, NULL);
147
148         g_array_free (view->find_results, TRUE);
149         view->find_results = NULL;
150         
151         G_OBJECT_CLASS (ev_view_parent_class)->finalize (object);
152 }
153
154 static void
155 ev_view_destroy (GtkObject *object)
156 {
157         EvView *view = EV_VIEW (object);
158
159         ev_view_set_scroll_adjustments (view, NULL, NULL);
160   
161         GTK_OBJECT_CLASS (ev_view_parent_class)->destroy (object);
162 }
163
164 static void
165 ev_view_size_request (GtkWidget      *widget,
166                       GtkRequisition *requisition)
167 {
168         EvView *view = EV_VIEW (widget);
169
170         if (GTK_WIDGET_REALIZED (widget)) {
171                 if (view->document) {
172                         ev_document_get_page_size (view->document,
173                                                    &requisition->width,
174                                                    &requisition->height);
175                 } else {
176                         requisition->width = 10;
177                         requisition->height = 10;
178                 }
179         }
180   
181 }
182
183 static void
184 ev_view_size_allocate (GtkWidget      *widget,
185                        GtkAllocation  *allocation)
186 {
187         EvView *view = EV_VIEW (widget);
188
189         GTK_WIDGET_CLASS (ev_view_parent_class)->size_allocate (widget, allocation);
190
191         view_set_adjustment_values (view, GTK_ORIENTATION_HORIZONTAL);
192         view_set_adjustment_values (view, GTK_ORIENTATION_VERTICAL);
193
194         if (GTK_WIDGET_REALIZED (widget)) {
195                 gdk_window_resize (view->bin_window,
196                                    MAX (widget->allocation.width, widget->requisition.width),
197                                    MAX (widget->allocation.height, widget->requisition.height));
198         }
199 }
200
201 static void
202 update_window_backgrounds (EvView *view)
203 {
204         GtkWidget *widget = GTK_WIDGET (view);
205   
206         if (GTK_WIDGET_REALIZED (view)) {
207                 gdk_window_set_background (view->bin_window,
208                                            &widget->style->base[GTK_WIDGET_STATE (widget)]);
209         }
210 }
211
212 static void
213 ev_view_realize (GtkWidget *widget)
214 {
215         EvView *view = EV_VIEW (widget);
216         GdkWindowAttr attributes;
217
218         GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED);
219   
220         attributes.window_type = GDK_WINDOW_CHILD;
221         attributes.wclass = GDK_INPUT_OUTPUT;
222         attributes.visual = gtk_widget_get_visual (widget);
223         attributes.colormap = gtk_widget_get_colormap (widget);
224   
225         attributes.x = widget->allocation.x;
226         attributes.y = widget->allocation.y;
227         attributes.width = widget->allocation.width;
228         attributes.height = widget->allocation.height;
229         attributes.event_mask = 0;
230   
231         widget->window = gdk_window_new (gtk_widget_get_parent_window (widget),
232                                          &attributes,
233                                          GDK_WA_X | GDK_WA_Y |
234                                          GDK_WA_COLORMAP |
235                                          GDK_WA_VISUAL);
236         gdk_window_set_user_data (widget->window, widget);
237         widget->style = gtk_style_attach (widget->style, widget->window);
238   
239         attributes.x = 0;
240         attributes.y = 0;
241         attributes.width = MAX (widget->allocation.width, widget->requisition.width);
242         attributes.height = MAX (widget->allocation.height, widget->requisition.height);
243         attributes.event_mask = GDK_EXPOSURE_MASK | GDK_SCROLL_MASK;
244   
245         view->bin_window = gdk_window_new (widget->window,
246                                            &attributes,
247                                            GDK_WA_X | GDK_WA_Y |
248                                            GDK_WA_COLORMAP |
249                                            GDK_WA_VISUAL);
250         gdk_window_set_user_data (view->bin_window, widget);
251         gdk_window_show (view->bin_window);
252
253         if (view->document) {
254                 ev_document_set_target (view->document, view->bin_window);
255
256                 /* We can't get page size without a target, so we have to
257                  * queue a size request at realization. Could be fixed
258                  * with EvDocument changes to allow setting a GdkScreen
259                  * without setting a target.
260                  */
261                 gtk_widget_queue_resize (widget);
262         }
263
264         update_window_backgrounds (view);
265 }
266
267 static void
268 ev_view_unrealize (GtkWidget *widget)
269 {
270         EvView *view = EV_VIEW (widget);
271
272         if (view->document)
273                 ev_document_set_target (view->document, NULL);
274
275         gdk_window_set_user_data (view->bin_window, NULL);
276         gdk_window_destroy (view->bin_window);
277         view->bin_window = NULL;
278
279         GTK_WIDGET_CLASS (ev_view_parent_class)->unrealize (widget);
280 }
281
282 static void
283 ev_view_style_set (GtkWidget      *widget,
284                    GtkStyle       *previous_style)
285 {
286         update_window_backgrounds (EV_VIEW (widget));
287 }
288
289 static void
290 ev_view_state_changed (GtkWidget    *widget,
291                        GtkStateType  previous_state)
292 {
293         update_window_backgrounds (EV_VIEW (widget));
294 }
295
296 static void
297 expose_bin_window (GtkWidget      *widget,
298                    GdkEventExpose *event)
299 {
300         EvView *view = EV_VIEW (widget);
301         int i;
302         int current_page;
303         const EvFindResult *results;
304
305         if (view->document == NULL)
306                 return;
307         
308         ev_document_render (view->document,
309                             event->area.x, event->area.y,
310                             event->area.width, event->area.height);
311
312         results = (EvFindResult*) view->find_results->data;
313         current_page = ev_document_get_page (view->document);
314         i = 0;
315         while (i < view->find_results->len) {
316 #if 0
317                 g_printerr ("highlighting result %d page %d at %d,%d %dx%d\n",
318                             i, results[i].page_num,
319                             results[i].highlight_area.x,
320                             results[i].highlight_area.y,
321                             results[i].highlight_area.width,
322                             results[i].highlight_area.height);
323 #endif
324                 if (results[i].page_num == current_page)
325                         gdk_draw_rectangle (view->bin_window,
326                                             widget->style->base_gc[GTK_STATE_SELECTED],
327                                             FALSE,
328                                             results[i].highlight_area.x,
329                                             results[i].highlight_area.y,
330                                             results[i].highlight_area.width,
331                                             results[i].highlight_area.height);
332                 ++i;
333         }
334 }
335
336 static gboolean
337 ev_view_expose_event (GtkWidget      *widget,
338                       GdkEventExpose *event)
339 {
340         EvView *view = EV_VIEW (widget);
341
342         if (event->window == view->bin_window)
343                 expose_bin_window (widget, event);
344         else
345                 return GTK_WIDGET_CLASS (ev_view_parent_class)->expose_event (widget, event);
346
347         return FALSE;
348 }
349
350 static gboolean
351 ev_view_button_press_event (GtkWidget      *widget,
352                             GdkEventButton *event)
353 {
354         /* EvView *view = EV_VIEW (widget); */
355
356         return FALSE;
357 }
358
359 static gboolean
360 ev_view_motion_notify_event (GtkWidget      *widget,
361                              GdkEventMotion *event)
362 {
363         /* EvView *view = EV_VIEW (widget); */
364   
365         return FALSE;
366 }
367
368 static gboolean
369 ev_view_button_release_event (GtkWidget      *widget,
370                               GdkEventButton *event)
371 {
372         /* EvView *view = EV_VIEW (widget); */
373
374         return FALSE;
375 }
376
377 static void
378 on_adjustment_value_changed (GtkAdjustment  *adjustment,
379                              EvView *view)
380 {
381         view_update_adjustments (view);
382 }
383
384 static void
385 set_scroll_adjustment (EvView *view,
386                        GtkOrientation  orientation,
387                        GtkAdjustment  *adjustment)
388 {
389         GtkAdjustment **to_set;
390
391         if (orientation == GTK_ORIENTATION_HORIZONTAL)
392                 to_set = &view->hadjustment;
393         else
394                 to_set = &view->vadjustment;
395   
396         if (*to_set != adjustment) {
397                 if (*to_set) {
398                         g_signal_handlers_disconnect_by_func (*to_set,
399                                                               (gpointer) on_adjustment_value_changed,
400                                                               view);
401                         g_object_unref (*to_set);
402                 }
403
404                 *to_set = adjustment;
405                 view_set_adjustment_values (view, orientation);
406
407                 if (*to_set) {
408                         g_object_ref (*to_set);
409                         g_signal_connect (*to_set, "value_changed",
410                                           G_CALLBACK (on_adjustment_value_changed), view);
411                 }
412         }
413 }
414
415 static void
416 ev_view_set_scroll_adjustments (EvView *view,
417                                 GtkAdjustment  *hadjustment,
418                                 GtkAdjustment  *vadjustment)
419 {
420         set_scroll_adjustment (view, GTK_ORIENTATION_HORIZONTAL, hadjustment);
421         set_scroll_adjustment (view, GTK_ORIENTATION_VERTICAL, vadjustment);
422
423         view_update_adjustments (view);
424 }
425
426 static void
427 ev_view_class_init (EvViewClass *class)
428 {
429         GObjectClass *object_class = G_OBJECT_CLASS (class);
430         GtkObjectClass *gtk_object_class = GTK_OBJECT_CLASS (class);
431         GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (class);
432
433         object_class->finalize = ev_view_finalize;
434
435         widget_class->expose_event = ev_view_expose_event;
436         widget_class->button_press_event = ev_view_button_press_event;
437         widget_class->motion_notify_event = ev_view_motion_notify_event;
438         widget_class->button_release_event = ev_view_button_release_event;
439         widget_class->size_request = ev_view_size_request;
440         widget_class->size_allocate = ev_view_size_allocate;
441         widget_class->realize = ev_view_realize;
442         widget_class->unrealize = ev_view_unrealize;
443         widget_class->style_set = ev_view_style_set;
444         widget_class->state_changed = ev_view_state_changed;
445         gtk_object_class->destroy = ev_view_destroy;
446   
447         class->set_scroll_adjustments = ev_view_set_scroll_adjustments;
448
449         widget_class->set_scroll_adjustments_signal =  g_signal_new ("set-scroll-adjustments",
450                                                                      G_OBJECT_CLASS_TYPE (object_class),
451                                                                      G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
452                                                                      G_STRUCT_OFFSET (EvViewClass, set_scroll_adjustments),
453                                                                      NULL, NULL,
454                                                                      ev_marshal_VOID__OBJECT_OBJECT,
455                                                                      G_TYPE_NONE, 2,
456                                                                      GTK_TYPE_ADJUSTMENT,
457                                                                      GTK_TYPE_ADJUSTMENT);
458         page_changed_signal = g_signal_new ("page-changed",
459                                             G_OBJECT_CLASS_TYPE (object_class),
460                                             G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
461                                             G_STRUCT_OFFSET (EvViewClass, page_changed),
462                                             NULL, NULL,
463                                             ev_marshal_VOID__NONE,
464                                             G_TYPE_NONE, 0);
465
466         g_signal_new ("find-status-changed",
467                       G_OBJECT_CLASS_TYPE (object_class),
468                       G_SIGNAL_RUN_LAST,
469                       0,
470                       NULL, NULL,
471                       ev_marshal_VOID__NONE,
472                       G_TYPE_NONE, 0);
473 }
474
475 static void
476 ev_view_init (EvView *view)
477 {
478         static const GdkColor white = { 0, 0xffff, 0xffff, 0xffff };
479
480         view->scale = 1.0;
481         
482         gtk_widget_modify_bg (GTK_WIDGET (view), GTK_STATE_NORMAL, &white);
483
484         view->find_results = g_array_new (FALSE,
485                                           FALSE,
486                                           sizeof (EvFindResult));
487         view->results_on_this_page = 0;
488         view->next_page_with_result = 0;
489 }
490
491 static void
492 update_find_results (EvView *view)
493 {
494         const EvFindResult *results;
495         int i;
496         int on_this_page;
497         int next_page_with_result;
498         int earliest_page_with_result;
499         int current_page;
500         gboolean counts_changed;
501         
502         results = (EvFindResult*) view->find_results->data;
503         current_page = ev_document_get_page (view->document);
504         next_page_with_result = 0;
505         on_this_page = 0;
506         earliest_page_with_result = 0;
507         
508         i = 0;
509         while (i < view->find_results->len) {
510                 if (results[i].page_num == current_page) {
511                         ++on_this_page;
512                 } else {
513                         int delta = results[i].page_num - current_page;
514                         
515                         if (delta > 0 && /* result on later page */
516                             (next_page_with_result == 0 ||
517                              results[i].page_num < next_page_with_result))
518                                 next_page_with_result = results[i].page_num;
519
520                         if (delta < 0 && /* result on a previous page */
521                             (earliest_page_with_result == 0 ||
522                              results[i].page_num < earliest_page_with_result))
523                                 earliest_page_with_result = results[i].page_num;
524                 }
525                 ++i;
526         }
527
528         /* If earliest page is just the current page, there is no earliest page */
529         if (earliest_page_with_result == current_page)
530                 earliest_page_with_result = 0;
531         
532         /* If no next page, then wrap and the wrapped page is the next page */
533         if (next_page_with_result == 0)
534                 next_page_with_result = earliest_page_with_result;
535
536         counts_changed = FALSE;
537         if (on_this_page != view->results_on_this_page ||
538             next_page_with_result != view->next_page_with_result) {
539                 view->results_on_this_page = on_this_page;
540                 view->next_page_with_result = next_page_with_result;
541                 counts_changed = TRUE;
542         }
543
544         /* If there are no results at all, then the
545          * results of ev_view_get_find_status_message() will change
546          * to reflect the percent_complete so we have to emit the signal
547          */
548         if (counts_changed ||
549             view->find_results->len == 0) {
550                 g_signal_emit_by_name (view,
551                                        "find-status-changed");
552         }
553 }
554
555 static void
556 found_results_callback (EvDocument         *document,
557                         const EvFindResult *results,
558                         int                 n_results,
559                         double              percent_complete,
560                         void               *data)
561 {
562   EvView *view = EV_VIEW (data);
563   
564   g_array_set_size (view->find_results, 0);
565
566   if (n_results > 0)
567           g_array_append_vals (view->find_results,
568                                results, n_results);
569
570 #if 0
571   {
572           int i;
573
574           g_printerr ("%d results %d%%: ", n_results,
575                       (int) (percent_complete * 100));
576           i = 0;
577           while (i < n_results) {
578                   g_printerr ("%d ", results[i].page_num);
579                   ++i;
580           }
581           g_printerr ("\n");
582   }
583 #endif
584
585   view->find_percent_complete = percent_complete;
586   update_find_results (view);
587   
588   gtk_widget_queue_draw (GTK_WIDGET (view));
589 }
590
591 /*** Public API ***/       
592      
593 GtkWidget*
594 ev_view_new (void)
595 {
596         return g_object_new (EV_TYPE_VIEW, NULL);
597 }
598
599 static void
600 document_changed_callback (EvDocument *document,
601                            EvView     *view)
602 {
603         gtk_widget_queue_draw (GTK_WIDGET (view));
604 }
605
606 void
607 ev_view_set_document (EvView     *view,
608                       EvDocument *document)
609 {
610         g_return_if_fail (EV_IS_VIEW (view));
611
612         if (document != view->document) {
613                 int old_page = ev_view_get_page (view);
614                 
615                 if (view->document) {
616                         g_signal_handlers_disconnect_by_func (view->document,
617                                                               found_results_callback,
618                                                               view);
619                         g_array_set_size (view->find_results, 0);
620                         view->results_on_this_page = 0;
621                         view->next_page_with_result = 0;
622
623                         g_object_unref (view->document);
624                 }
625
626                 view->document = document;
627
628                 if (view->document) {
629                         g_object_ref (view->document);
630                         g_signal_connect (view->document,
631                                           "found",
632                                           G_CALLBACK (found_results_callback),
633                                           view);
634                         g_signal_connect (view->document,
635                                           "changed",
636                                           G_CALLBACK (document_changed_callback),
637                                           view);
638                 }
639
640                 if (GTK_WIDGET_REALIZED (view))
641                         ev_document_set_target (view->document, view->bin_window);
642                 
643                 gtk_widget_queue_resize (GTK_WIDGET (view));
644                 
645                 if (old_page != ev_view_get_page (view))
646                         g_signal_emit (view, page_changed_signal, 0);
647         }
648 }
649
650 void
651 ev_view_set_page (EvView *view,
652                   int     page)
653 {
654         if (view->document) {
655                 int old_page = ev_document_get_page (view->document);
656                 if (old_page != page)
657                         ev_document_set_page (view->document, page);
658                 if (old_page != ev_document_get_page (view->document)) {
659                         g_signal_emit (view, page_changed_signal, 0);
660
661                         view->find_percent_complete = 0.0;
662                         update_find_results (view);     
663                 }
664         }
665 }
666
667 int
668 ev_view_get_page (EvView *view)
669 {
670         if (view->document)
671                 return ev_document_get_page (view->document);
672         else
673                 return 1;
674 }
675
676 #define ZOOM_IN_FACTOR  1.2
677 #define ZOOM_OUT_FACTOR (1.0/ZOOM_IN_FACTOR)
678
679 #define MIN_SCALE 0.05409
680 #define MAX_SCALE 18.4884
681
682 static void
683 ev_view_zoom (EvView   *view,
684               double    factor,
685               gboolean  relative)
686 {
687         double scale;
688
689         if (relative)
690                 scale = view->scale * factor;
691         else
692                 scale = factor;
693
694         view->scale = CLAMP (scale, MIN_SCALE, MAX_SCALE);
695
696         ev_document_set_scale (view->document, view->scale);
697
698         gtk_widget_queue_draw (GTK_WIDGET (view));
699 }
700
701 void
702 ev_view_zoom_in (EvView *view)
703 {
704         ev_view_zoom (view, ZOOM_IN_FACTOR, TRUE);
705 }
706
707 void
708 ev_view_zoom_out (EvView *view)
709 {
710         ev_view_zoom (view, ZOOM_OUT_FACTOR, TRUE);
711 }
712
713 void
714 ev_view_normal_size (EvView *view)
715 {
716         ev_view_zoom (view, 1.0, FALSE);
717 }
718
719 void
720 ev_view_best_fit (EvView *view)
721 {
722         double scale;
723         int width, height;
724
725         width = height = 0;
726         ev_document_get_page_size (view->document, &width, &height);
727
728         scale = 1.0;
729         if (width != 0 && height != 0) {
730                 double scale_w, scale_h;
731
732                 scale_w = (double)GTK_WIDGET (view)->allocation.width * view->scale / width;
733                 scale_h = (double)GTK_WIDGET (view)->allocation.height * view->scale / height;
734
735                 scale = (scale_w < scale_h) ? scale_w : scale_h;
736         }
737
738         ev_view_zoom (view, scale, FALSE);
739 }
740
741 void
742 ev_view_fit_width (EvView *view)
743 {
744         double scale = 1.0;
745         int width;
746
747         width = 0;
748         ev_document_get_page_size (view->document, &width, NULL);
749
750         scale = 1.0;
751         if (width != 0)
752                 scale = (double)GTK_WIDGET (view)->allocation.width * view->scale / width;
753
754         ev_view_zoom (view, scale, FALSE);
755 }
756
757 char*
758 ev_view_get_find_status_message (EvView *view)
759 {
760         if (view->find_results->len == 0) {
761                 if (view->find_percent_complete >= (1.0 - 1e-10)) {
762                         return g_strdup (_("Not found"));
763                 } else {
764                         return g_strdup_printf (_("%3d%% remaining to search"),
765                                                 (int) ((1.0 - view->find_percent_complete) * 100));
766                 }
767         } else if (view->results_on_this_page == 0) {
768                 g_assert (view->next_page_with_result != 0);
769                 return g_strdup_printf (_("Found on page %d"),
770                                         view->next_page_with_result);
771         } else {
772                 return g_strdup_printf (_("%d found on this page"),
773                                         view->results_on_this_page);
774         }
775 }