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