]> www.fi.muni.cz Git - evince.git/blobdiff - shell/ev-window.c
Add mnemonic for edit toolbar. ctrl+l focus the page entry.
[evince.git] / shell / ev-window.c
index 475cb5ddc1e4a44016068dd27c5eef569d17c8b1..fe1c2263a049c44c68051d1b328ce5e80a6ec040 100644 (file)
 #include "egg-recent-view-gtk.h"
 #include "egg-recent-view.h"
 #include "egg-recent-model.h"
+#include "egg-toolbar-editor.h"
+#include "egg-toolbars-model.h"
+#include "egg-editable-toolbar.h"
+#include "ephy-zoom.h"
+#include "ephy-zoom-action.h"
+#include "ev-application.h"
+#include "ev-stock-icons.h"
+#include "ev-file-helpers.h"
 
 #include <glib/gi18n.h>
 #include <gtk/gtk.h>
 #include <gnome.h>
 
-#include <libgnomevfs/gnome-vfs-mime-utils.h>
 #include <libgnomevfs/gnome-vfs-uri.h>
 #include <libgnomevfs/gnome-vfs-utils.h>
+#include <libgnomevfs/gnome-vfs-ops.h>
 #include <libgnomeprintui/gnome-print-dialog.h>
 
 #include <gconf/gconf-client.h>
 
 #include <string.h>
 
-#include "ev-application.h"
-#include "ev-stock-icons.h"
-
 typedef enum {
        PAGE_MODE_SINGLE_PAGE,
        PAGE_MODE_CONTINUOUS_PAGE,
@@ -91,8 +96,13 @@ struct _EvWindowPrivate {
        GtkWidget *view;
        GtkWidget *page_view;
        GtkWidget *password_view;
+
        GtkActionGroup *action_group;
        GtkUIManager *ui_manager;
+
+       gchar *toolbar_file;
+       EggToolbarsModel *toolbar_model;
+
        GtkWidget *statusbar;
        guint help_message_cid;
        guint view_message_cid;
@@ -126,6 +136,7 @@ static const GtkTargetEntry ev_drop_types[] = {
        (G_TYPE_INSTANCE_GET_PRIVATE ((object), EV_TYPE_WINDOW, EvWindowPrivate))
 
 #define PAGE_SELECTOR_ACTION   "PageSelector"
+#define ZOOM_CONTROL_ACTION    "ViewZoom"
 
 #define GCONF_CHROME_TOOLBAR   "/apps/evince/show_toolbar"
 #define GCONF_CHROME_SIDEBAR   "/apps/evince/show_sidebar"
@@ -203,6 +214,8 @@ update_action_sensitivity (EvWindow *ev_window)
        set_action_sensitive (ev_window, "EditSelectAll", sensitive);
        set_action_sensitive (ev_window, "EditFind",
                              has_pages && EV_IS_DOCUMENT_FIND (document));
+       set_action_sensitive (ev_window, "Slash",
+                             has_pages && EV_IS_DOCUMENT_FIND (document));
        set_action_sensitive (ev_window, "EditFindNext",
                              ev_view_can_find_next (view));
 
@@ -239,12 +252,24 @@ update_action_sensitivity (EvWindow *ev_window)
                set_action_sensitive (ev_window, "SinglePage", FALSE);
                set_action_sensitive (ev_window, "ContinuousPage", FALSE);
        }
-       /* Help menu */
-       /* "HelpContents": always sensitive */
-       /* "HelpAbout": always sensitive */
 
        /* Toolbar-specific actions: */
        set_action_sensitive (ev_window, PAGE_SELECTOR_ACTION, has_pages);
+       set_action_sensitive (ev_window, ZOOM_CONTROL_ACTION,  has_pages);
+
+       if (has_pages && ev_view_get_sizing_mode (view) == EV_SIZING_FREE) {
+               GtkAction *action;
+               float      zoom;
+               float      real_zoom;
+
+               action = gtk_action_group_get_action (ev_window->priv->action_group, 
+                                                     ZOOM_CONTROL_ACTION);
+
+               real_zoom = ev_view_get_zoom (EV_VIEW (ev_window->priv->view));
+               zoom = ephy_zoom_get_nearest_zoom_level (real_zoom);
+
+               ephy_zoom_action_set_zoom_level (EPHY_ZOOM_ACTION (action), zoom);
+       }
 }
 
 static void
@@ -277,7 +302,10 @@ update_chrome_visibility (EvWindow *window)
        findbar = (priv->chrome & EV_CHROME_FINDBAR) != 0;
 
        set_widget_visibility (priv->menubar, menubar);
+       
        set_widget_visibility (priv->toolbar_dock, toolbar);
+       set_action_sensitive (window, "EditToolbar", toolbar);
+
        set_widget_visibility (priv->sidebar, sidebar);
        set_widget_visibility (priv->find_bar, findbar);
        set_widget_visibility (priv->statusbar, statusbar);
@@ -310,6 +338,28 @@ update_chrome_flag (EvWindow *window, EvChrome flag, const char *pref, gboolean
        update_chrome_visibility (window);
 }
 
+static void
+ev_window_cmd_focus_page_selector (GtkAction *act, EvWindow *window)
+{
+       GtkAction *action;
+       
+       action = gtk_action_group_get_action (window->priv->action_group,
+                                             PAGE_SELECTOR_ACTION);
+       ev_page_action_grab_focus (EV_PAGE_ACTION (action));
+}
+
+static void
+ev_window_cmd_scroll_forward (GtkAction *action, EvWindow *window)
+{
+       ev_view_scroll (EV_VIEW (window->priv->view), EV_SCROLL_PAGE_FORWARD);
+}
+
+static void
+ev_window_cmd_scroll_backward (GtkAction *action, EvWindow *window)
+{
+       ev_view_scroll (EV_VIEW (window->priv->view), EV_SCROLL_PAGE_BACKWARD);
+}
+
 static void
 ev_window_cmd_continuous (GtkAction *action, EvWindow *ev_window)
 {
@@ -405,6 +455,16 @@ update_sizing_buttons (EvWindow *window)
        gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action), page_width);
        g_signal_handlers_unblock_by_func
                (action, G_CALLBACK (ev_window_cmd_view_page_width), window);
+
+       action = gtk_action_group_get_action (window->priv->action_group, 
+                                             ZOOM_CONTROL_ACTION);     
+       if (best_fit) {
+               ephy_zoom_action_set_zoom_level (EPHY_ZOOM_ACTION (action), 
+                                                EPHY_ZOOM_BEST_FIT);
+       } else if (page_width) {
+               ephy_zoom_action_set_zoom_level (EPHY_ZOOM_ACTION (action), 
+                                                EPHY_ZOOM_FIT_WIDTH);
+       }
 }
 
 void
@@ -711,25 +771,46 @@ start_loading_document (EvWindow   *ev_window,
        return FALSE;
 }
 
+static gboolean
+sanity_check_uri (EvWindow *window, const char *uri)
+{
+       gboolean result = FALSE;
+       GnomeVFSURI *vfs_uri;
+       char *err;
+
+       vfs_uri = gnome_vfs_uri_new (uri);
+       if (vfs_uri) {
+               if (gnome_vfs_uri_exists (vfs_uri)) {
+                       result = TRUE;
+               }
+       }
+
+       if (!result) {
+               err = g_strdup_printf (_("The file %s does not exist."), uri);
+               unable_to_load (window, err);
+               g_free (err);
+       }
+
+       return result;
+}
+
 void
 ev_window_open (EvWindow *ev_window, const char *uri)
 {
        EvDocument *document = NULL;
-       char *mime_type;
+       GType document_type;
+       char *mime_type = NULL;
+
+       if (!sanity_check_uri (ev_window, uri)) {
+               return;
+       }
 
        g_free (ev_window->priv->uri);
        ev_window->priv->uri = g_strdup (uri);
 
-       mime_type = gnome_vfs_get_mime_type (uri);
-
-       if (mime_type == NULL)
-               document = NULL;
-       else {
-               GType document_type = ev_document_type_lookup (mime_type);
-
-               if (document_type!=G_TYPE_INVALID) {
-                       document = g_object_new (document_type, NULL);
-               }
+       document_type = ev_document_type_lookup (uri, &mime_type);
+       if (document_type != G_TYPE_INVALID) {
+               document = g_object_new (document_type, NULL);
        }
 
        if (document) {
@@ -754,16 +835,15 @@ static void
 ev_window_open_uri_list (EvWindow *ev_window, GList *uri_list)
 {
        GList *list;
-       gchar *uri, *mime_type;
+       gchar *uri;
        
        g_return_if_fail (uri_list != NULL);
        
        list = uri_list;
        while (list) {
                uri = gnome_vfs_uri_to_string (list->data, GNOME_VFS_URI_HIDE_NONE);
-               mime_type = gnome_vfs_get_mime_type (uri);
                
-               if (ev_document_type_lookup (mime_type)!=G_TYPE_INVALID) {
+               if (ev_document_type_lookup (uri, NULL) != G_TYPE_INVALID) {
                        if (ev_window_is_empty (EV_WINDOW (ev_window))) {
                                ev_window_open (ev_window, uri);
                                
@@ -778,7 +858,6 @@ ev_window_open_uri_list (EvWindow *ev_window, GList *uri_list)
                        }
                }
 
-               g_free (mime_type);
                g_free (uri);
 
                list = g_list_next (list);
@@ -992,6 +1071,8 @@ using_postscript_printer (GnomePrintConfig *config)
        } else  if (transport) {
                if (!strcmp ((const gchar *)transport, "CUPS"))
                        return TRUE;
+               else if (!strcmp ((const gchar *)transport, "LPD"))
+                       return TRUE;
        }
 
        return FALSE;
@@ -1003,6 +1084,8 @@ ev_window_print (EvWindow *ev_window)
        GnomePrintConfig *config;
        GnomePrintJob *job;
        GtkWidget *print_dialog;
+       EvPageCache *page_cache;
+       gchar *pages_label;
        EvPrintJob *print_job = NULL;
 
         g_return_if_fail (EV_IS_WINDOW (ev_window));
@@ -1011,9 +1094,21 @@ ev_window_print (EvWindow *ev_window)
        config = gnome_print_config_default ();
        job = gnome_print_job_new (config);
 
+       page_cache = ev_document_get_page_cache (ev_window->priv->document);
+
        print_dialog = gnome_print_dialog_new (job, (guchar *) _("Print"),
                                               (GNOME_PRINT_DIALOG_RANGE |
                                                GNOME_PRINT_DIALOG_COPIES));
+
+       pages_label = g_strconcat (_("Pages"), " ", NULL);
+       gnome_print_dialog_construct_range_page (GNOME_PRINT_DIALOG (print_dialog),
+                                                GNOME_PRINT_RANGE_ALL |
+                                                GNOME_PRINT_RANGE_RANGE,
+                                                1,
+                                                ev_page_cache_get_n_pages (page_cache),
+                                                NULL, (const guchar *)pages_label);
+       g_free (pages_label);
+                                                
        gtk_dialog_set_response_sensitive (GTK_DIALOG (print_dialog),
                                           GNOME_PRINT_DIALOG_RESPONSE_PREVIEW,
                                           FALSE);
@@ -1577,6 +1672,51 @@ ev_window_set_page_mode (EvWindow         *window,
        update_action_sensitivity (window);
 }
 
+static void
+ev_window_cmd_edit_toolbar_cb (GtkDialog *dialog, gint response, gpointer data)
+{
+       EvWindow *ev_window = EV_WINDOW (data);
+        egg_editable_toolbar_set_edit_mode
+                       (EGG_EDITABLE_TOOLBAR (ev_window->priv->toolbar), FALSE);
+        egg_toolbars_model_save (ev_window->priv->toolbar_model,
+                                ev_window->priv->toolbar_file, "1.0");
+        gtk_widget_destroy (GTK_WIDGET (dialog));
+}
+
+static void
+ev_window_cmd_edit_toolbar (GtkAction *action, EvWindow *ev_window)
+{
+       GtkWidget *dialog;
+       GtkWidget *editor;
+       g_return_if_fail (EV_IS_WINDOW (ev_window));
+    
+       dialog = gtk_dialog_new_with_buttons (_("Toolbar editor"), GTK_WINDOW (ev_window), 
+                                             GTK_DIALOG_DESTROY_WITH_PARENT, 
+                                             GTK_STOCK_CLOSE,
+                                             GTK_RESPONSE_CANCEL, 
+                                             NULL);
+       gtk_dialog_set_has_separator (GTK_DIALOG (dialog), FALSE);
+       gtk_window_set_default_size (GTK_WINDOW (dialog), 500, 400);
+         
+       editor = egg_toolbar_editor_new (ev_window->priv->ui_manager,
+                                        ev_window->priv->toolbar_model);
+       gtk_container_set_border_width (GTK_CONTAINER (editor), 5);
+       gtk_box_set_spacing (GTK_BOX (EGG_TOOLBAR_EDITOR (editor)), 5);
+                    
+       gtk_container_add (GTK_CONTAINER (GTK_DIALOG (dialog)->vbox), editor);
+       egg_toolbar_editor_load_actions (EGG_TOOLBAR_EDITOR (editor),
+                                     DATADIR"/evince-toolbar.xml");
+
+       egg_editable_toolbar_set_edit_mode
+               (EGG_EDITABLE_TOOLBAR (ev_window->priv->toolbar), TRUE);
+
+       gtk_widget_show_all (dialog);
+      
+       g_signal_connect (G_OBJECT (dialog), "response",
+                         G_CALLBACK (ev_window_cmd_edit_toolbar_cb),
+                         ev_window);
+}
+
 static void
 ev_window_cmd_view_zoom_in (GtkAction *action, EvWindow *ev_window)
 {
@@ -2067,12 +2207,41 @@ find_bar_search_changed_cb (EggFindBar *find_bar,
        }
 }
 
+static void
+zoom_control_changed_cb (EphyZoomAction *action,
+                        float           zoom,
+                        EvWindow       *ev_window)
+{
+       EvSizingMode mode;
+       
+       g_return_if_fail (EV_IS_WINDOW (ev_window));
+
+       if (zoom == EPHY_ZOOM_BEST_FIT) {
+               mode = EV_SIZING_BEST_FIT;
+       } else if (zoom == EPHY_ZOOM_FIT_WIDTH) {
+               mode = EV_SIZING_FIT_WIDTH;
+       } else {
+               mode = EV_SIZING_FREE;
+               ev_view_set_zoom (EV_VIEW (ev_window->priv->view), zoom, FALSE);
+       }
+       
+       ev_view_set_sizing_mode (EV_VIEW (ev_window->priv->view), mode);
+       update_action_sensitivity (ev_window);
+}
+
 static void
 ev_window_dispose (GObject *object)
 {
        EvWindow *window = EV_WINDOW (object);
        EvWindowPrivate *priv = window->priv;
 
+       if (priv->toolbar_model) {
+               g_object_unref (priv->toolbar_model);
+               g_free (priv->toolbar_file);
+               priv->toolbar_model = NULL;
+               priv->toolbar_file = NULL;
+       }
+
        if (priv->ui_manager) {
                g_object_unref (priv->ui_manager);
                priv->ui_manager = NULL;
@@ -2176,6 +2345,9 @@ static const GtkActionEntry entries[] = {
        { "EditFindNext", NULL, N_("Find Ne_xt"), "<control>G",
          N_("Find next occurrence of the word or phrase"),
          G_CALLBACK (ev_window_cmd_edit_find_next) },
+        { "EditToolbar", NULL, N_("T_oolbar"), NULL,
+          N_("Customize the toolbar"),
+          G_CALLBACK (ev_window_cmd_edit_toolbar) },
 
         /* View menu */
         { "ViewZoomIn", GTK_STOCK_ZOOM_IN, NULL, "<control>plus",
@@ -2219,8 +2391,27 @@ static const GtkActionEntry entries[] = {
          N_("Leave fullscreen mode"),
          G_CALLBACK (ev_window_cmd_leave_fullscreen) },
 
-       { "Escape", NULL, N_("Selection Caret"), "Escape", "",
-         G_CALLBACK (ev_window_cmd_escape) }
+       /* Accellerators */
+       { "Escape", NULL, "", "Escape", "",
+         G_CALLBACK (ev_window_cmd_escape) },
+        { "Slash", GTK_STOCK_FIND, NULL, "slash",
+          N_("Find a word or phrase in the document"),
+          G_CALLBACK (ev_window_cmd_edit_find) },
+        { "Space", NULL, "", "space",
+          N_("Scroll one page forward"),
+          G_CALLBACK (ev_window_cmd_scroll_forward) },
+        { "ShiftSpace", NULL, "", "<shift>space",
+          N_("Scroll one page backward"),
+          G_CALLBACK (ev_window_cmd_scroll_backward) },
+        { "BackSpace", NULL, "", "BackSpace",
+          N_("Scroll one page backward"),
+          G_CALLBACK (ev_window_cmd_scroll_backward) },
+        { "ShiftBackSpace", NULL, "", "<shift>BackSpace",
+          N_("Scroll one page forward"),
+          G_CALLBACK (ev_window_cmd_scroll_forward) },
+        { "FocusPageSelector", NULL, "", "<control>l",
+          N_("Focus the page selector"),
+          G_CALLBACK (ev_window_cmd_focus_page_selector) }
 };
 
 /* Toggle items */
@@ -2291,7 +2482,20 @@ register_custom_actions (EvWindow *window, GtkActionGroup *group)
                               "name", PAGE_SELECTOR_ACTION,
                               "label", _("Page"),
                               "tooltip", _("Select Page"),
+                              "visible_overflown", FALSE,
+                              NULL);
+       gtk_action_group_add_action (group, action);
+       g_object_unref (action);
+
+       action = g_object_new (EPHY_TYPE_ZOOM_ACTION,
+                              "name", ZOOM_CONTROL_ACTION,
+                              "label", _("Zoom"),
+                              "stock_id", GTK_STOCK_ZOOM_IN,
+                              "tooltip", _("Adjust the zoom level"),
+                              "zoom", 1.0,
                               NULL);
+       g_signal_connect (action, "zoom_to_level",
+                         G_CALLBACK (zoom_control_changed_cb), window);
        gtk_action_group_add_action (group, action);
        g_object_unref (action);
 }
@@ -2421,13 +2625,48 @@ sidebar_widget_model_set (EvSidebarLinks *ev_sidebar_links,
        ev_page_action_set_model (EV_PAGE_ACTION (action), model);
 }
 
+
+static void
+set_view_actions_sensitivity (EvWindow *window, gboolean sensitive)
+{
+       if (window->priv->action_group) {
+               set_action_sensitive (window, "Space", sensitive);
+               set_action_sensitive (window, "ShiftSpace", sensitive);
+               set_action_sensitive (window, "BackSpace", sensitive);
+               set_action_sensitive (window, "ShiftBackSpace", sensitive);
+       }
+}
+
+static void
+view_actions_focus_in_cb (GtkWidget *widget, GdkEventFocus *event, EvWindow *window)
+{
+       set_view_actions_sensitivity (window, TRUE);
+}
+
+static void
+view_actions_focus_out_cb (GtkWidget *widget, GdkEventFocus *event, EvWindow *window)
+{
+       set_view_actions_sensitivity (window, FALSE);
+}
+
+static void
+enable_view_actions_for_widget (EvWindow *window, GtkWidget *widget)
+{
+       g_signal_connect_object (widget, "focus_in_event",
+                                G_CALLBACK (view_actions_focus_in_cb),
+                                window, 0);
+       g_signal_connect_object (widget, "focus_out_event",
+                                G_CALLBACK (view_actions_focus_out_cb),
+                                window, 0);
+}
+
 static void
 ev_window_init (EvWindow *ev_window)
 {
        GtkActionGroup *action_group;
        GtkAccelGroup *accel_group;
        GError *error = NULL;
-       GtkWidget *sidebar_widget, *toolbar_dock;
+       GtkWidget *sidebar_widget, *toolbar_dock, *tree_view;
        GConfValue *value;
        GConfClient *client;
        int sidebar_size;
@@ -2465,6 +2704,8 @@ ev_window_init (EvWindow *ev_window)
                gtk_ui_manager_get_accel_group (ev_window->priv->ui_manager);
        gtk_window_add_accel_group (GTK_WINDOW (ev_window), accel_group);
 
+       set_view_actions_sensitivity (ev_window, FALSE);
+
        g_signal_connect (ev_window->priv->ui_manager, "connect_proxy",
                          G_CALLBACK (connect_proxy_cb), ev_window);
        g_signal_connect (ev_window->priv->ui_manager, "disconnect_proxy",
@@ -2484,6 +2725,23 @@ ev_window_init (EvWindow *ev_window)
                            ev_window->priv->menubar,
                            FALSE, FALSE, 0);
 
+       /* Toolbar editor */
+       ev_window->priv->toolbar_model = egg_toolbars_model_new ();
+       
+       ev_window->priv->toolbar_file = g_build_filename
+                       (ev_dot_dir (), "evince_toolbar.xml", NULL);
+
+       if (!g_file_test (ev_window->priv->toolbar_file, G_FILE_TEST_EXISTS)) {
+               egg_toolbars_model_load (ev_window->priv->toolbar_model,
+                                        DATADIR"/evince-toolbar.xml");
+       } else {
+               egg_toolbars_model_load (ev_window->priv->toolbar_model,
+                                        ev_window->priv->toolbar_file);
+       }
+
+       egg_toolbars_model_set_flags (ev_window->priv->toolbar_model, 0,
+                                     EGG_TB_MODEL_NOT_REMOVABLE); 
+       
        /* This sucks, but there is no way to have a draw=no, expand=true separator
         * in a GtkUIManager-built toolbar. So, just add another toolbar.
         * See gtk+ bug 166489.
@@ -2493,9 +2751,10 @@ ev_window_init (EvWindow *ev_window)
                            FALSE, FALSE, 0);
        gtk_widget_show (toolbar_dock);
 
-       ev_window->priv->toolbar =
-               gtk_ui_manager_get_widget (ev_window->priv->ui_manager,
-                                          "/ToolBar");
+       ev_window->priv->toolbar = egg_editable_toolbar_new_with_model
+                               (ev_window->priv->ui_manager, ev_window->priv->toolbar_model);
+       egg_editable_toolbar_show (EGG_EDITABLE_TOOLBAR (ev_window->priv->toolbar),
+                                  "DefaultToolBar");
        gtk_box_pack_start (GTK_BOX (toolbar_dock), ev_window->priv->toolbar,
                            TRUE, TRUE, 0);
        gtk_widget_show (ev_window->priv->toolbar);
@@ -2503,6 +2762,7 @@ ev_window_init (EvWindow *ev_window)
        ev_window->priv->fullscreen_toolbar =
                gtk_ui_manager_get_widget (ev_window->priv->ui_manager, "/LeaveFullscreenToolbar");
        gtk_toolbar_set_show_arrow (GTK_TOOLBAR (ev_window->priv->fullscreen_toolbar), TRUE);
+       
 
        /* Add the main area */
        ev_window->priv->hpaned = gtk_hpaned_new ();
@@ -2537,11 +2797,17 @@ ev_window_init (EvWindow *ev_window)
                          "notify::model",
                          G_CALLBACK (sidebar_widget_model_set),
                          ev_window);
+       tree_view = ev_sidebar_links_get_treeview
+                       (EV_SIDEBAR_LINKS (sidebar_widget));
+       enable_view_actions_for_widget (ev_window, tree_view);
        gtk_widget_show (sidebar_widget);
        ev_sidebar_add_page (EV_SIDEBAR (ev_window->priv->sidebar),
                             sidebar_widget);
 
        sidebar_widget = ev_sidebar_thumbnails_new ();
+       tree_view = ev_sidebar_thumbnails_get_treeview
+                       (EV_SIDEBAR_THUMBNAILS (sidebar_widget));
+       enable_view_actions_for_widget (ev_window, tree_view);
        gtk_widget_show (sidebar_widget);
        ev_sidebar_add_page (EV_SIDEBAR (ev_window->priv->sidebar),
                             sidebar_widget);
@@ -2561,8 +2827,8 @@ ev_window_init (EvWindow *ev_window)
                                  "unlock",
                                  G_CALLBACK (ev_window_popup_password_dialog),
                                  ev_window);
+       enable_view_actions_for_widget (ev_window, ev_window->priv->view);
        gtk_widget_show (ev_window->priv->view);
-       //gtk_widget_show (ev_window->priv->page_view);
        gtk_widget_show (ev_window->priv->password_view);
 
        /* We own a ref on these widgets, as we can swap them in and out */