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