]> www.fi.muni.cz Git - evince.git/blobdiff - shell/ev-window.c
shell: It's 2010 already!
[evince.git] / shell / ev-window.c
index 2d69097069cee0eb1489f7dafe323074bfbaadf5..e5acd4089c2dbd64f5850e6746220383bc3fed80 100644 (file)
@@ -56,7 +56,6 @@
 #include "ev-document-fonts.h"
 #include "ev-document-images.h"
 #include "ev-document-links.h"
-#include "ev-document-thumbnails.h"
 #include "ev-document-annotations.h"
 #include "ev-document-type-builtins.h"
 #include "ev-document-misc.h"
@@ -344,6 +343,7 @@ static void     ev_window_media_player_key_pressed      (EvWindow         *windo
 static void     ev_window_update_max_min_scale          (EvWindow         *window);
 #ifdef ENABLE_DBUS
 static void    ev_window_emit_closed                   (EvWindow         *window);
+static void    ev_window_emit_doc_loaded               (EvWindow         *window);
 #endif
 
 static guint ev_window_n_copies = 0;
@@ -895,6 +895,13 @@ view_selection_changed_cb (EvView   *view,
                                        ev_view_get_has_selection (view));
 }
 
+static void
+view_layers_changed_cb (EvView   *view,
+                       EvWindow *window)
+{
+       ev_sidebar_layers_update_layers_state (EV_SIDEBAR_LAYERS (window->priv->sidebar_layers));
+}
+
 static void
 ev_window_page_changed_cb (EvWindow        *ev_window,
                           gint             old_page,
@@ -1310,8 +1317,7 @@ ev_window_refresh_window_thumbnail (EvWindow *ev_window)
        gint rotation;
        EvDocument *document = ev_window->priv->document;
 
-       if (!EV_IS_DOCUMENT_THUMBNAILS (document) ||
-           ev_document_get_n_pages (document) <= 0 ||
+       if (ev_document_get_n_pages (document) <= 0 ||
            !ev_document_check_dimensions (document)) {
                return;
        }
@@ -1531,6 +1537,9 @@ ev_window_load_job_cb (EvJob *job,
        if (!ev_job_is_failed (job)) {
                ev_document_model_set_document (ev_window->priv->model, document);
 
+#ifdef ENABLE_DBUS
+               ev_window_emit_doc_loaded (ev_window);
+#endif
                setup_chrome_from_metadata (ev_window);
                update_chrome_actions (ev_window);
                setup_document_from_metadata (ev_window);
@@ -2864,6 +2873,48 @@ ev_window_cmd_save_as (GtkAction *action, EvWindow *ev_window)
        gtk_widget_show (fc);
 }
 
+static void
+ev_window_cmd_open_containing_folder (GtkAction *action, EvWindow *ev_window)
+{
+       GtkWidget *ev_window_widget;
+       GFile *file;
+       GFile *parent;
+
+       ev_window_widget = GTK_WIDGET (ev_window);
+
+       file = g_file_new_for_uri (ev_window->priv->uri);
+       parent = g_file_get_parent (file);
+
+       if (parent) {
+               char *parent_uri;
+
+               parent_uri = g_file_get_uri (parent);
+               if (parent_uri) {
+                       GdkScreen *screen;
+                       guint32 timestamp;
+                       GError *error;
+
+                       screen = gtk_widget_get_screen (ev_window_widget);
+                       timestamp = gtk_get_current_event_time ();
+
+                       error = NULL;
+                       if (!gtk_show_uri (screen, parent_uri, timestamp, &error)) {
+                               ev_window_error_message (ev_window, error, _("Could not open the containing folder"));
+                               g_error_free (error);
+                       }
+
+                       g_free (parent_uri);
+               }
+       }
+
+       if (file)
+               g_object_unref (file);
+
+       if (parent)
+               g_object_unref (parent);
+       
+}
+
 static GKeyFile *
 get_print_settings_file (void)
 {
@@ -3366,6 +3417,91 @@ ev_window_cmd_file_properties (GtkAction *action, EvWindow *ev_window)
        ev_document_fc_mutex_unlock ();
 }
 
+static void
+document_modified_confirmation_dialog_response (GtkDialog *dialog,
+                                               gint       response,
+                                               EvWindow  *ev_window)
+{
+       gtk_widget_destroy (GTK_WIDGET (dialog));
+
+       switch (response) {
+       case GTK_RESPONSE_YES:
+               ev_window_cmd_save_as (NULL, ev_window);
+               break;
+       case GTK_RESPONSE_NO:
+               gtk_widget_destroy (GTK_WIDGET (ev_window));
+               break;
+       case GTK_RESPONSE_CANCEL:
+       default:
+               break;
+       }
+}
+
+static gboolean
+ev_window_check_document_modified (EvWindow *ev_window)
+{
+       EvDocument  *document = ev_window->priv->document;
+       GtkWidget   *dialog;
+       gchar       *text, *markup;
+       const gchar *secondary_text;
+
+       if (!document)
+               return FALSE;
+
+       if (EV_IS_DOCUMENT_FORMS (document) &&
+           ev_document_forms_document_is_modified (EV_DOCUMENT_FORMS (document))) {
+               secondary_text = _("Document contains form fields that have been filled out. "
+                                  "If you don't save a copy, changes will be permanently lost.");
+       } else if (EV_IS_DOCUMENT_ANNOTATIONS (document) &&
+                  ev_document_annotations_document_is_modified (EV_DOCUMENT_ANNOTATIONS (document))) {
+               secondary_text = _("Document contains new or modified annotations. "
+                                  "If you don't save a copy, changes will be permanently lost.");
+       } else {
+               return FALSE;
+       }
+
+
+       text = g_markup_printf_escaped (_("Save a copy of document “%s” before closing?"),
+                                       gtk_window_get_title (GTK_WINDOW (ev_window)));
+
+       dialog = gtk_message_dialog_new (GTK_WINDOW (ev_window),
+                                        GTK_DIALOG_MODAL,
+                                        GTK_MESSAGE_QUESTION,
+                                        GTK_BUTTONS_NONE,
+                                        NULL);
+
+       markup = g_strdup_printf ("<b>%s</b>", text);
+       g_free (text);
+
+       gtk_message_dialog_set_markup (GTK_MESSAGE_DIALOG (dialog), markup);
+       g_free (markup);
+
+       gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog),
+                                                 "%s", secondary_text);
+
+       gtk_dialog_add_buttons (GTK_DIALOG (dialog),
+                               _("Close _without Saving"),
+                               GTK_RESPONSE_NO,
+                               GTK_STOCK_CANCEL,
+                               GTK_RESPONSE_CANCEL,
+                               _("Save a _Copy"),
+                               GTK_RESPONSE_YES,
+                               NULL);
+       gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_YES);
+        gtk_dialog_set_alternative_button_order (GTK_DIALOG (dialog),
+                                                 GTK_RESPONSE_YES,
+                                                 GTK_RESPONSE_NO,
+                                                 GTK_RESPONSE_CANCEL,
+                                                 -1);
+
+       g_signal_connect (dialog, "response",
+                         G_CALLBACK (document_modified_confirmation_dialog_response),
+                         ev_window);
+       gtk_widget_show (dialog);
+
+       return TRUE;
+}
+
 static void
 print_jobs_confirmation_dialog_response (GtkDialog *dialog,
                                         gint       response,
@@ -3397,31 +3533,18 @@ print_jobs_confirmation_dialog_response (GtkDialog *dialog,
        }
 }
 
-static void
-ev_window_cmd_file_close_window (GtkAction *action, EvWindow *ev_window)
+static gboolean
+ev_window_check_print_queue (EvWindow *ev_window)
 {
        GtkWidget *dialog;
        gchar     *text, *markup;
        gint       n_print_jobs;
 
-       if (EV_WINDOW_IS_PRESENTATION (ev_window)) {
-               gint current_page;
-
-               /* Save current page */
-               current_page = ev_view_presentation_get_current_page (
-                       EV_VIEW_PRESENTATION (ev_window->priv->presentation_view));
-               ev_document_model_set_page (ev_window->priv->model, current_page);
-       }
-
-       /* TODO: warn about form fields, and annots not saved */
-
        n_print_jobs = ev_window->priv->print_queue ?
                g_queue_get_length (ev_window->priv->print_queue) : 0;
-       
-       if (n_print_jobs == 0) {
-               gtk_widget_destroy (GTK_WIDGET (ev_window));
-               return;
-       }
+
+       if (n_print_jobs == 0)
+               return FALSE;
 
        dialog = gtk_message_dialog_new (GTK_WINDOW (ev_window),
                                         GTK_DIALOG_MODAL,
@@ -3452,7 +3575,7 @@ ev_window_cmd_file_close_window (GtkAction *action, EvWindow *ev_window)
        gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog), "%s",
                                                  _("If you close the window, pending print "
                                                    "jobs will not be printed."));
-       
+
        gtk_dialog_add_buttons (GTK_DIALOG (dialog),
                                _("Cancel _print and Close"),
                                GTK_RESPONSE_NO,
@@ -3472,6 +3595,36 @@ ev_window_cmd_file_close_window (GtkAction *action, EvWindow *ev_window)
                          G_CALLBACK (print_jobs_confirmation_dialog_response),
                          ev_window);
        gtk_widget_show (dialog);
+
+       return TRUE;
+}
+
+static gboolean
+ev_window_close (EvWindow *ev_window)
+{
+       if (EV_WINDOW_IS_PRESENTATION (ev_window)) {
+               gint current_page;
+
+               /* Save current page */
+               current_page = ev_view_presentation_get_current_page (
+                       EV_VIEW_PRESENTATION (ev_window->priv->presentation_view));
+               ev_document_model_set_page (ev_window->priv->model, current_page);
+       }
+
+       if (ev_window_check_document_modified (ev_window))
+               return FALSE;
+
+       if (ev_window_check_print_queue (ev_window))
+               return FALSE;
+
+       return TRUE;
+}
+
+static void
+ev_window_cmd_file_close_window (GtkAction *action, EvWindow *ev_window)
+{
+       if (ev_window_close (ev_window))
+               gtk_widget_destroy (GTK_WIDGET (ev_window));
 }
 
 static void
@@ -4058,7 +4211,6 @@ ev_window_cmd_edit_toolbar (GtkAction *action, EvWindow *ev_window)
        gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_CLOSE);
        gtk_container_set_border_width (GTK_CONTAINER (GTK_DIALOG (dialog)), 5);
        gtk_box_set_spacing (GTK_BOX (content_area), 2);
-       gtk_dialog_set_has_separator (GTK_DIALOG (dialog), FALSE);
        gtk_window_set_default_size (GTK_WINDOW (dialog), 500, 400);
 
        toolbar = EGG_EDITABLE_TOOLBAR (ev_window->priv->toolbar);
@@ -4494,7 +4646,7 @@ ev_window_cmd_help_about (GtkAction *action, EvWindow *ev_window)
                "name", _("Evince"),
                "version", VERSION,
                "copyright",
-               _("© 1996–2009 The Evince authors"),
+               _("© 1996–2010 The Evince authors"),
                "license", license_trans,
                "website", "http://www.gnome.org/projects/evince",
                "comments", comments,
@@ -4756,17 +4908,23 @@ ev_window_update_find_status_message (EvWindow *ev_window)
                return;
        
        if (ev_job_is_finished (ev_window->priv->find_job)) {
-               gint n_results;
-
-               n_results = ev_job_find_get_n_results (EV_JOB_FIND (ev_window->priv->find_job),
-                                                      ev_document_model_get_page (ev_window->priv->model));
-               /* TRANS: Sometimes this could be better translated as
-                                     "%d hit(s) on this page".  Therefore this string
-                                     contains plural cases. */
-               message = g_strdup_printf (ngettext ("%d found on this page",
-                                                    "%d found on this page",
-                                                    n_results),
-                                          n_results);
+               EvJobFind *job_find = EV_JOB_FIND (ev_window->priv->find_job);
+
+               if (ev_job_find_has_results (job_find)) {
+                       gint n_results;
+
+                       n_results = ev_job_find_get_n_results (job_find,
+                                                              ev_document_model_get_page (ev_window->priv->model));
+                       /* TRANS: Sometimes this could be better translated as
+                          "%d hit(s) on this page".  Therefore this string
+                          contains plural cases. */
+                       message = g_strdup_printf (ngettext ("%d found on this page",
+                                                            "%d found on this page",
+                                                            n_results),
+                                                  n_results);
+               } else {
+                       message = g_strdup (_("Not found"));
+               }
        } else {
                gdouble percent;
 
@@ -5257,6 +5415,13 @@ ev_window_key_press_event (GtkWidget   *widget,
        return handled;
 }
 
+static gboolean
+ev_window_delete_event (GtkWidget   *widget,
+                       GdkEventAny *event)
+{
+       return !ev_window_close (EV_WINDOW (widget));
+}
+
 static void
 ev_window_class_init (EvWindowClass *ev_window_class)
 {
@@ -5266,6 +5431,7 @@ ev_window_class_init (EvWindowClass *ev_window_class)
        g_object_class->dispose = ev_window_dispose;
        g_object_class->finalize = ev_window_finalize;
 
+       widget_class->delete_event = ev_window_delete_event;
        widget_class->key_press_event = ev_window_key_press_event;
        widget_class->screen_changed = ev_window_screen_changed;
        widget_class->window_state_event = ev_window_state_event;
@@ -5292,6 +5458,9 @@ static const GtkActionEntry entries[] = {
                { "FileSaveAs", GTK_STOCK_SAVE_AS, N_("_Save a Copy…"), "<control>S",
          N_("Save a copy of the current document"),
          G_CALLBACK (ev_window_cmd_save_as) },
+       { "FileOpenContainingFolder", GTK_STOCK_DIRECTORY, N_("Open Containing _Folder"), NULL,
+         N_("Show the folder which contains this file in the file manager"),
+         G_CALLBACK (ev_window_cmd_open_containing_folder) },
        { "FilePrint", GTK_STOCK_PRINT, N_("_Print…"), "<control>P",
          N_("Print this document"),
          G_CALLBACK (ev_window_cmd_file_print) },
@@ -5602,6 +5771,10 @@ set_action_properties (GtkActionGroup *action_group)
 {
        GtkAction *action;
 
+       action = gtk_action_group_get_action (action_group, "FileOpenContainingFolder");
+       /*translators: this is the label for toolbar button*/
+       g_object_set (action, "short_label", _("Open Folder"), NULL);
+
        action = gtk_action_group_get_action (action_group, "GoPreviousPage");
        g_object_set (action, "is-important", TRUE, NULL);
        /*translators: this is the label for toolbar button*/
@@ -6422,6 +6595,9 @@ ev_window_sync_source (EvWindow     *window,
 {
        GDBusConnection *connection;
        GError          *error = NULL;
+       guint32          timestamp;
+       gchar           *uri_input;
+       GFile           *input_gfile;
 
        if (window->priv->dbus_object_id <= 0)
                return;
@@ -6430,16 +6606,41 @@ ev_window_sync_source (EvWindow     *window,
        if (!connection)
                return;
 
+       timestamp = gtk_get_current_event_time ();
+       if (g_path_is_absolute (link->filename)) {
+               input_gfile = g_file_new_for_path (link->filename);
+       } else {
+               GFile *gfile, *parent_gfile;
+
+               gfile = g_file_new_for_uri (window->priv->uri);
+               parent_gfile = g_file_get_parent (gfile);
+
+               /* parent_gfile should never be NULL */
+               if (parent_gfile == NULL) {
+                       g_printerr ("Document URI is '/'\n");
+                       return;
+               }
+
+               input_gfile = g_file_get_child (parent_gfile, link->filename);
+               g_object_unref (parent_gfile);
+               g_object_unref (gfile);
+       }
+
+       uri_input = g_file_get_uri (input_gfile);
+       g_object_unref (input_gfile);
+
        g_dbus_connection_emit_signal (connection,
                                       NULL,
                                       window->priv->dbus_object_path,
                                       EV_WINDOW_DBUS_INTERFACE,
                                       "SyncSource",
-                                      g_variant_new ("(s(ii))",
-                                                     link->filename,
+                                      g_variant_new ("(s(ii)u)",
+                                                     uri_input,
                                                      link->line,
-                                                     link->col),
+                                                     link->col,
+                                                     timestamp),
                                       &error);
+       g_free (uri_input);
        if (error) {
                g_printerr ("Failed to emit DBus signal SyncSource: %s\n",
                            error->message);
@@ -6482,6 +6683,35 @@ ev_window_emit_closed (EvWindow *window)
                g_dbus_connection_flush_sync (connection, NULL, NULL);
 }
 
+static void
+ev_window_emit_doc_loaded (EvWindow *window)
+{
+       GDBusConnection *connection;
+       GError          *error = NULL;
+
+       if (window->priv->dbus_object_id <= 0)
+               return;
+
+       connection = ev_application_get_dbus_connection (EV_APP);
+       if (!connection)
+               return;
+
+       g_dbus_connection_emit_signal (connection,
+                                      NULL,
+                                      window->priv->dbus_object_path,
+                                      EV_WINDOW_DBUS_INTERFACE,
+                                      "DocumentLoaded",
+                                      g_variant_new("(s)", window->priv->uri),
+                                      &error);
+       if (error) {
+               g_printerr ("Failed to emit DBus signal DocumentLoaded: %s\n",
+                           error->message);
+               g_error_free (error);
+
+               return;
+       }
+}
+
 static void
 method_call_cb (GDBusConnection       *connection,
                 const gchar           *sender,
@@ -6499,10 +6729,11 @@ method_call_cb (GDBusConnection       *connection,
 
        if (window->priv->document && ev_document_has_synctex (window->priv->document)) {
                EvSourceLink link;
+               guint32      timestamp;
 
-               g_variant_get (parameters, "(&s(ii))", &link.filename, &link.line, &link.col);
+               g_variant_get (parameters, "(&s(ii)u)", &link.filename, &link.line, &link.col, &timestamp);
                ev_view_highlight_forward_search (EV_VIEW (window->priv->view), &link);
-               gtk_window_present (GTK_WINDOW (window));
+               gtk_window_present_with_time (GTK_WINDOW (window), timestamp);
        }
 
        g_dbus_method_invocation_return_value (invocation, g_variant_new ("()"));
@@ -6514,12 +6745,17 @@ static const char introspection_xml[] =
             "<method name='SyncView'>"
               "<arg type='s' name='source_file' direction='in'/>"
               "<arg type='(ii)' name='source_point' direction='in'/>"
+              "<arg type='u' name='timestamp' direction='in'/>"
             "</method>"
            "<signal name='SyncSource'>"
              "<arg type='s' name='source_file' direction='out'/>"
              "<arg type='(ii)' name='source_point' direction='out'/>"
+             "<arg type='u' name='timestamp' direction='out'/>"
            "</signal>"
             "<signal name='Closed'/>"
+           "<signal name='DocumentLoaded'>"
+             "<arg type='s' name='uri' direction='out'/>"
+           "</signal>"
           "</interface>"
         "</node>";
 
@@ -6680,7 +6916,7 @@ ev_window_init (EvWindow *ev_window)
        gtk_widget_show (ev_window->priv->toolbar);
 
        /* Add the main area */
-       ev_window->priv->hpaned = gtk_hpaned_new ();
+       ev_window->priv->hpaned = gtk_paned_new (GTK_ORIENTATION_HORIZONTAL);
        g_signal_connect (ev_window->priv->hpaned,
                          "notify::position",
                          G_CALLBACK (ev_window_sidebar_position_change_cb),
@@ -6808,6 +7044,9 @@ ev_window_init (EvWindow *ev_window)
        g_signal_connect_object (ev_window->priv->view, "annot-added",
                                 G_CALLBACK (view_annot_added),
                                 ev_window, 0);
+       g_signal_connect_object (ev_window->priv->view, "layers-changed",
+                                G_CALLBACK (view_layers_changed_cb),
+                                ev_window, 0);
 #ifdef ENABLE_DBUS
        g_signal_connect_swapped (ev_window->priv->view, "sync-source",
                                  G_CALLBACK (ev_window_sync_source),