]> www.fi.muni.cz Git - evince.git/blob - previewer/ev-previewer-window.c
15a16071b9822344345b5be36c37fc846b9e6132
[evince.git] / previewer / ev-previewer-window.c
1 /* ev-previewer-window.c: 
2  *  this file is part of evince, a gnome document viewer
3  *
4  * Copyright (C) 2009 Carlos Garcia Campos <carlosgc@gnome.org>
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 <config.h>
22
23 #include <gtk/gtkunixprint.h>
24 #include <glib/gi18n.h>
25 #include <evince-view.h>
26 #include "ev-page-action.h"
27
28 #include "ev-previewer-window.h"
29
30 struct _EvPreviewerWindow {
31         GtkWindow         base_instance;
32
33         EvDocument       *document;
34
35         GtkActionGroup   *action_group;
36         GtkUIManager     *ui_manager;
37
38         GtkWidget        *swindow;
39         EvView           *view;
40         gdouble           dpi;
41
42         /* Printing */
43         GtkPrintSettings *print_settings;
44         GtkPageSetup     *print_page_setup;
45         GtkPrinter       *printer;
46         gchar            *print_job_title;
47         gchar            *source_file;
48 };
49
50 struct _EvPreviewerWindowClass {
51         GtkWindowClass base_class;
52 };
53
54 G_DEFINE_TYPE (EvPreviewerWindow, ev_previewer_window, GTK_TYPE_WINDOW)
55
56 static gdouble
57 get_screen_dpi (GtkWindow *window)
58 {
59         GdkScreen *screen;
60         gdouble    xdpi, ydpi;
61
62         screen = gtk_window_get_screen (window);
63
64         xdpi = 25.4 * gdk_screen_get_width (screen) / gdk_screen_get_width_mm (screen);
65         ydpi = 25.4 * gdk_screen_get_height (screen) / gdk_screen_get_height_mm (screen);
66
67         return (xdpi + ydpi) / 2.0;
68 }
69
70 static void
71 ev_previewer_window_set_view_size (EvPreviewerWindow *window)
72 {
73         gint width, height;
74         GtkRequisition vsb_requisition;
75         GtkRequisition hsb_requisition;
76         gint scrollbar_spacing;
77
78         if (!window->view)
79                 return;
80
81         /* Calculate the width available for the content */
82         width  = window->swindow->allocation.width;
83         height = window->swindow->allocation.height;
84
85         if (gtk_scrolled_window_get_shadow_type (GTK_SCROLLED_WINDOW (window->swindow)) == GTK_SHADOW_IN) {
86                 width -=  2 * GTK_WIDGET (window->view)->style->xthickness;
87                 height -= 2 * GTK_WIDGET (window->view)->style->ythickness;
88         }
89
90         gtk_widget_size_request (GTK_SCROLLED_WINDOW (window->swindow)->vscrollbar,
91                                  &vsb_requisition);
92         gtk_widget_size_request (GTK_SCROLLED_WINDOW (window->swindow)->hscrollbar,
93                                  &hsb_requisition);
94         gtk_widget_style_get (window->swindow,
95                               "scrollbar_spacing",
96                               &scrollbar_spacing,
97                               NULL);
98
99         ev_view_set_zoom_for_size (window->view,
100                                    MAX (1, width),
101                                    MAX (1, height),
102                                    vsb_requisition.width + scrollbar_spacing,
103                                    hsb_requisition.height + scrollbar_spacing);
104 }
105
106 static void
107 ev_previewer_window_error_dialog_run (EvPreviewerWindow *window,
108                                       GError            *error)
109 {
110         GtkWidget *dialog;
111
112         dialog = gtk_message_dialog_new (GTK_WINDOW (window),
113                                          GTK_DIALOG_MODAL |
114                                          GTK_DIALOG_DESTROY_WITH_PARENT,
115                                          GTK_MESSAGE_ERROR,
116                                          GTK_BUTTONS_CLOSE,
117                                          "%s", _("Failed to print document"));
118         gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog),
119                                                   "%s", error->message);
120         gtk_dialog_run (GTK_DIALOG (dialog));
121         gtk_widget_destroy (dialog);
122 }
123
124 static void
125 ev_previewer_window_previous_page (GtkAction         *action,
126                                    EvPreviewerWindow *window)
127 {
128         ev_view_previous_page (window->view);
129 }
130
131 static void
132 ev_previewer_window_next_page (GtkAction         *action,
133                                EvPreviewerWindow *window)
134 {
135         ev_view_next_page (window->view);
136 }
137
138 static void
139 ev_previewer_window_zoom_in (GtkAction         *action,
140                              EvPreviewerWindow *window)
141 {
142         ev_view_set_sizing_mode (window->view, EV_SIZING_FREE);
143         ev_view_zoom_in (window->view);
144 }
145
146 static void
147 ev_previewer_window_zoom_out (GtkAction         *action,
148                               EvPreviewerWindow *window)
149 {
150         ev_view_set_sizing_mode (window->view, EV_SIZING_FREE);
151         ev_view_zoom_out (window->view);
152 }
153
154 static void
155 ev_previewer_window_zoom_best_fit (GtkToggleAction   *action,
156                                    EvPreviewerWindow *window)
157 {
158         if (gtk_toggle_action_get_active (action)) {
159                 ev_view_set_sizing_mode (window->view, EV_SIZING_BEST_FIT);
160                 ev_previewer_window_set_view_size (window);
161         } else {
162                 ev_view_set_sizing_mode (window->view, EV_SIZING_FREE);
163         }
164 }
165
166 static void
167 ev_previewer_window_zoom_page_width (GtkToggleAction   *action,
168                                      EvPreviewerWindow *window)
169 {
170         if (gtk_toggle_action_get_active (action)) {
171                 ev_view_set_sizing_mode (window->view, EV_SIZING_FIT_WIDTH);
172                 ev_previewer_window_set_view_size (window);
173         } else {
174                 ev_view_set_sizing_mode (window->view, EV_SIZING_FREE);
175         }
176 }
177
178 static void
179 ev_previewer_window_action_page_activated (GtkAction         *action,
180                                            EvLink            *link,
181                                            EvPreviewerWindow *window)
182 {
183         ev_view_handle_link (window->view, link);
184         gtk_widget_grab_focus (GTK_WIDGET (window->view));
185 }
186
187 static void
188 ev_previewer_window_print_finished (GtkPrintJob       *print_job,
189                                     EvPreviewerWindow *window,
190                                     GError            *error)
191 {
192         if (error) {
193                 ev_previewer_window_error_dialog_run (window, error);
194         }
195
196         g_object_unref (print_job);
197         gtk_widget_destroy (GTK_WIDGET (window));
198 }
199
200 static void
201 ev_previewer_window_do_print (EvPreviewerWindow *window)
202 {
203         GtkPrintJob *job;
204         GError      *error = NULL;
205
206         job = gtk_print_job_new (window->print_job_title ?
207                                  window->print_job_title :
208                                  window->source_file,
209                                  window->printer,
210                                  window->print_settings,
211                                  window->print_page_setup);
212         if (gtk_print_job_set_source_file (job, window->source_file, &error)) {
213                 gtk_print_job_send (job,
214                                     (GtkPrintJobCompleteFunc)ev_previewer_window_print_finished,
215                                     window, NULL);
216         } else {
217                 ev_previewer_window_error_dialog_run (window, error);
218                 g_error_free (error);
219         }
220
221         gtk_widget_hide (GTK_WIDGET (window));
222 }
223
224 static void
225 ev_previewer_window_enumerate_finished (EvPreviewerWindow *window)
226 {
227         if (window->printer) {
228                 ev_previewer_window_do_print (window);
229         } else {
230                 GError *error = NULL;
231
232                 g_set_error (&error,
233                              GTK_PRINT_ERROR,
234                              GTK_PRINT_ERROR_GENERAL,
235                              _("The selected printer '%s' could not be found"),
236                              gtk_print_settings_get_printer (window->print_settings));
237                                      
238                 ev_previewer_window_error_dialog_run (window, error);
239                 g_error_free (error);
240         }
241 }
242
243 static gboolean
244 ev_previewer_window_enumerate_printers (GtkPrinter        *printer,
245                                         EvPreviewerWindow *window)
246 {
247         const gchar *printer_name;
248
249         printer_name = gtk_print_settings_get_printer (window->print_settings);
250         if ((printer_name
251              && strcmp (printer_name, gtk_printer_get_name (printer)) == 0) ||
252             (!printer_name && gtk_printer_is_default (printer))) {
253                 if (window->printer)
254                         g_object_unref (window->printer);
255                 window->printer = g_object_ref (printer);
256
257                 return TRUE; /* we're done */
258         }
259
260         return FALSE; /* continue the enumeration */
261 }
262
263 static void
264 ev_previewer_window_print (GtkAction         *action,
265                            EvPreviewerWindow *window)
266 {
267         if (!window->print_settings)
268                 window->print_settings = gtk_print_settings_new ();
269         if (!window->print_page_setup)
270                 window->print_page_setup = gtk_page_setup_new ();
271         gtk_enumerate_printers ((GtkPrinterFunc)ev_previewer_window_enumerate_printers,
272                                 window,
273                                 (GDestroyNotify)ev_previewer_window_enumerate_finished,
274                                 FALSE);
275 }
276
277 static const GtkActionEntry action_entries[] = {
278         { "GoPreviousPage", GTK_STOCK_GO_UP, N_("_Previous Page"), "<control>Page_Up",
279           N_("Go to the previous page"),
280           G_CALLBACK (ev_previewer_window_previous_page) },
281         { "GoNextPage", GTK_STOCK_GO_DOWN, N_("_Next Page"), "<control>Page_Down",
282           N_("Go to the next page"),
283           G_CALLBACK (ev_previewer_window_next_page) },
284         { "ViewZoomIn", GTK_STOCK_ZOOM_IN, NULL, "<control>plus",
285           N_("Enlarge the document"),
286           G_CALLBACK (ev_previewer_window_zoom_in) },
287         { "ViewZoomOut", GTK_STOCK_ZOOM_OUT, NULL, "<control>minus",
288           N_("Shrink the document"),
289           G_CALLBACK (ev_previewer_window_zoom_out) },
290         { "PreviewPrint", GTK_STOCK_PRINT, N_("Print"), NULL,
291           N_("Print this document"),
292           G_CALLBACK (ev_previewer_window_print) }
293 };
294
295 static const GtkToggleActionEntry toggle_action_entries[] = {
296         { "ViewBestFit", EV_STOCK_ZOOM_PAGE, N_("_Best Fit"), NULL,
297           N_("Make the current document fill the window"),
298           G_CALLBACK (ev_previewer_window_zoom_best_fit) },
299         { "ViewPageWidth", EV_STOCK_ZOOM_WIDTH, N_("Fit Page _Width"), NULL,
300           N_("Make the current document fill the window width"),
301           G_CALLBACK (ev_previewer_window_zoom_page_width) }
302 };
303
304 /* EvView callbacks */
305 static void
306 view_sizing_mode_changed (EvView            *view,
307                           GParamSpec        *pspec,
308                           EvPreviewerWindow *window)
309 {
310         EvSizingMode sizing_mode;
311         GtkAction   *action;
312
313         if (!window->view)
314                 return;
315
316         g_object_get (window->view,
317                       "sizing_mode", &sizing_mode,
318                       NULL);
319
320         action = gtk_action_group_get_action (window->action_group, "ViewBestFit");
321         g_signal_handlers_block_by_func (action,
322                                          G_CALLBACK (ev_previewer_window_zoom_best_fit),
323                                          window);
324         gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action),
325                                       sizing_mode == EV_SIZING_BEST_FIT);
326         g_signal_handlers_unblock_by_func (action,
327                                            G_CALLBACK (ev_previewer_window_zoom_best_fit),
328                                            window);
329
330         action = gtk_action_group_get_action (window->action_group, "ViewPageWidth");
331         g_signal_handlers_block_by_func (action,
332                                          G_CALLBACK (ev_previewer_window_zoom_page_width),
333                                          window);
334         gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action),
335                                       sizing_mode == EV_SIZING_FIT_WIDTH);
336         g_signal_handlers_unblock_by_func (action,
337                                            G_CALLBACK (ev_previewer_window_zoom_page_width),
338                                            window);
339 }
340
341 static void
342 ev_previewer_window_dispose (GObject *object)
343 {
344         EvPreviewerWindow *window = EV_PREVIEWER_WINDOW (object);
345
346         if (window->document) {
347                 g_object_unref (window->document);
348                 window->document = NULL;
349         }
350
351         if (window->action_group) {
352                 g_object_unref (window->action_group);
353                 window->action_group = NULL;
354         }
355
356         if (window->ui_manager) {
357                 g_object_unref (window->ui_manager);
358                 window->ui_manager = NULL;
359         }
360
361         if (window->print_settings) {
362                 g_object_unref (window->print_settings);
363                 window->print_settings = NULL;
364         }
365
366         if (window->print_page_setup) {
367                 g_object_unref (window->print_page_setup);
368                 window->print_page_setup = NULL;
369         }
370
371         if (window->printer) {
372                 g_object_unref (window->printer);
373                 window->printer = NULL;
374         }
375
376         if (window->print_job_title) {
377                 g_free (window->print_job_title);
378                 window->print_job_title = NULL;
379         }
380
381         if (window->source_file) {
382                 g_free (window->source_file);
383                 window->source_file = NULL;
384         }
385
386         G_OBJECT_CLASS (ev_previewer_window_parent_class)->dispose (object);
387 }
388
389 static gchar*
390 data_dir (void)
391 {
392         gchar *datadir;
393 #ifdef G_OS_WIN32
394         gchar *dir;
395
396         dir = g_win32_get_package_installation_directory_of_module (NULL);
397         datadir = g_build_filename (dir, "share", "evince", NULL);
398         g_free (dir);
399 #else
400         datadir = g_strdup (DATADIR);
401 #endif
402
403        return datadir;
404 }
405
406 static void
407 ev_previewer_window_init (EvPreviewerWindow *window)
408 {
409         GtkWidget *vbox;
410         GtkWidget *toolbar;
411         GtkAction *action;
412         GError    *error = NULL;
413         gchar     *datadir, *ui_path;
414
415         gtk_window_set_default_size (GTK_WINDOW (window), 600, 600);
416         
417         window->action_group = gtk_action_group_new ("PreviewerActions");
418         gtk_action_group_set_translation_domain (window->action_group, NULL);
419         gtk_action_group_add_actions (window->action_group, action_entries,
420                                       G_N_ELEMENTS (action_entries),
421                                       window);
422         gtk_action_group_add_toggle_actions (window->action_group, toggle_action_entries,
423                                              G_N_ELEMENTS (toggle_action_entries),
424                                              window);
425         gtk_action_group_set_sensitive (window->action_group, FALSE);
426
427         action = g_object_new (EV_TYPE_PAGE_ACTION,
428                                "name", "PageSelector",
429                                "label", _("Page"),
430                                "tooltip", _("Select Page"),
431                                "icon_name", "text-x-generic",
432                                "visible_overflown", FALSE,
433                                NULL);
434         g_signal_connect (action, "activate_link",
435                           G_CALLBACK (ev_previewer_window_action_page_activated),
436                           window);
437         gtk_action_group_add_action (window->action_group, action);
438         g_object_unref (action);
439
440         window->ui_manager = gtk_ui_manager_new ();
441         gtk_ui_manager_insert_action_group (window->ui_manager,
442                                             window->action_group, 0);
443         gtk_window_add_accel_group (GTK_WINDOW (window),
444                                     gtk_ui_manager_get_accel_group (window->ui_manager));
445         datadir = data_dir ();
446         ui_path = g_build_filename (datadir, "evince-previewer-ui.xml", NULL);
447         if (!gtk_ui_manager_add_ui_from_file (window->ui_manager, ui_path, &error)) {
448                 g_warning ("Failed to load ui from evince-previewer-ui.xml: %s", error->message);
449                 g_error_free (error);
450         }
451         g_free (ui_path);
452         g_free (datadir);
453
454         vbox = gtk_vbox_new (FALSE, 0);
455
456         toolbar = gtk_ui_manager_get_widget (window->ui_manager, "/PreviewToolbar");
457         gtk_box_pack_start (GTK_BOX (vbox), toolbar, FALSE, FALSE, 0);
458         gtk_widget_show (toolbar);
459                 
460         window->swindow = gtk_scrolled_window_new (NULL, NULL);
461         gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (window->swindow),
462                                         GTK_POLICY_AUTOMATIC,
463                                         GTK_POLICY_AUTOMATIC);
464         
465         window->view = EV_VIEW (ev_view_new ());
466         g_signal_connect (window->view, "notify::sizing-mode",
467                           G_CALLBACK (view_sizing_mode_changed),
468                           window);
469         g_signal_connect_swapped (window->view, "zoom_invalid",
470                                   G_CALLBACK (ev_previewer_window_set_view_size),
471                                   window);
472         
473         ev_view_set_screen_dpi (window->view, get_screen_dpi (GTK_WINDOW (window)));
474         ev_view_set_continuous (window->view, FALSE);
475         ev_view_set_sizing_mode (window->view, EV_SIZING_FIT_WIDTH);
476         ev_view_set_loading (window->view, TRUE);
477         view_sizing_mode_changed (window->view, NULL, window);
478
479         gtk_container_add (GTK_CONTAINER (window->swindow), GTK_WIDGET (window->view));
480         gtk_widget_show (GTK_WIDGET (window->view));
481
482         gtk_box_pack_start (GTK_BOX (vbox), window->swindow, TRUE, TRUE, 0);
483         gtk_widget_show (window->swindow);
484         
485         gtk_container_add (GTK_CONTAINER (window), vbox);
486         gtk_widget_show (vbox);
487 }
488
489 static void
490 ev_previewer_window_class_init (EvPreviewerWindowClass *klass)
491 {
492         GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
493
494         gobject_class->dispose = ev_previewer_window_dispose;
495 }
496
497 /* Public methods */
498 GtkWidget *
499 ev_previewer_window_new (void)
500 {
501         return GTK_WIDGET (g_object_new (EV_TYPE_PREVIEWER_WINDOW, NULL));
502 }
503
504 void
505 ev_previewer_window_set_document (EvPreviewerWindow *window,
506                                   EvDocument        *document)
507 {
508         GtkAction *action;
509         
510         g_return_if_fail (EV_IS_PREVIEWER_WINDOW (window));
511         g_return_if_fail (EV_IS_DOCUMENT (document));
512         
513         if (window->document)
514                 return;
515
516         action = gtk_action_group_get_action (window->action_group, "PageSelector");
517         ev_page_action_set_document (EV_PAGE_ACTION (action), document);
518         gtk_action_group_set_sensitive (window->action_group, TRUE);
519         
520         window->document = g_object_ref (document);
521         ev_view_set_document (window->view, document);
522         ev_view_set_zoom (window->view,
523                           get_screen_dpi (GTK_WINDOW (window)) / 72.0,
524                           FALSE);
525         ev_view_set_loading (window->view, FALSE);
526 }
527
528 void
529 ev_previewer_window_set_print_settings (EvPreviewerWindow *window,
530                                         const gchar       *print_settings)
531 {
532         if (window->print_settings)
533                 g_object_unref (window->print_settings);
534         if (window->print_page_setup)
535                 g_object_unref (window->print_page_setup);
536         if (window->print_job_title)
537                 g_free (window->print_job_title);
538
539         if (print_settings && g_file_test (print_settings, G_FILE_TEST_IS_REGULAR)) {
540                 GKeyFile *key_file;
541                 GError   *error = NULL;
542
543                 key_file = g_key_file_new ();
544                 g_key_file_load_from_file (key_file,
545                                            print_settings,
546                                            G_KEY_FILE_KEEP_COMMENTS |
547                                            G_KEY_FILE_KEEP_TRANSLATIONS,
548                                            &error);
549                 if (!error) {
550                         GtkPrintSettings *psettings;
551                         GtkPageSetup     *psetup;
552                         gchar            *job_name;
553
554                         psettings = gtk_print_settings_new_from_key_file (key_file,
555                                                                           "Print Settings",
556                                                                           NULL);
557                         window->print_settings = psettings ? psettings : gtk_print_settings_new ();
558
559                         psetup = gtk_page_setup_new_from_key_file (key_file,
560                                                                    "Page Setup",
561                                                                    NULL);
562                         window->print_page_setup = psetup ? psetup : gtk_page_setup_new ();
563
564                         job_name = g_key_file_get_string (key_file,
565                                                           "Print Job", "title",
566                                                           NULL);
567                         if (job_name) {
568                                 window->print_job_title = job_name;
569                                 gtk_window_set_title (GTK_WINDOW (window), job_name);
570                         }
571                 } else {
572                         window->print_settings = gtk_print_settings_new ();
573                         window->print_page_setup = gtk_page_setup_new ();
574                         g_error_free (error);
575                 }
576
577                 g_key_file_free (key_file);
578         } else {
579                 window->print_settings = gtk_print_settings_new ();
580                 window->print_page_setup = gtk_page_setup_new ();
581         }
582 }
583
584 void
585 ev_previewer_window_set_source_file (EvPreviewerWindow *window,
586                                      const gchar       *source_file)
587 {
588         if (window->source_file)
589                 g_free (window->source_file);
590         window->source_file = g_strdup (source_file);
591 }