+static void
+update_window_title (EvDocument *document, GParamSpec *pspec, EvWindow *ev_window)
+{
+ char *title = NULL;
+ char *doc_title = NULL;
+ gboolean password_needed;
+
+ password_needed = (ev_window->priv->password_document != NULL);
+ if (document && ev_window->priv->page_cache) {
+ doc_title = ev_page_cache_get_title (ev_window->priv->page_cache);
+
+ /* Make sure we get a valid title back */
+ if (doc_title) {
+ if (doc_title[0] == '\000' ||
+ !g_utf8_validate (doc_title, -1, NULL)) {
+ g_free (doc_title);
+ doc_title = NULL;
+ }
+ }
+ }
+
+ if (doc_title) {
+ char *p;
+
+ for (p = doc_title; *p; ++p) {
+ /* an '\n' byte is always ASCII, no need for UTF-8 special casing */
+ if (*p == '\n')
+ *p = ' ';
+ }
+ }
+
+ if (doc_title == NULL && ev_window->priv->uri) {
+ char *basename;
+
+ basename = g_path_get_basename (ev_window->priv->uri);
+ doc_title = gnome_vfs_unescape_string_for_display (basename);
+ g_free (basename);
+ }
+
+ if (password_needed) {
+ if (doc_title == NULL) {
+ title = g_strdup (_("Document Viewer - Password Required"));
+ } else {
+ title = g_strdup_printf (_("%s - Password Required"), doc_title);
+ }
+ } else {
+ if (doc_title == NULL) {
+ title = g_strdup (_("Document Viewer"));
+ } else {
+ title = g_strdup (doc_title);
+ }
+ }
+
+ gtk_window_set_title (GTK_WINDOW (ev_window), title);
+
+ g_free (doc_title);
+ g_free (title);
+}
+
+static void
+find_changed_cb (EvDocument *document, int page, EvWindow *ev_window)
+{
+ update_action_sensitivity (ev_window);
+}
+
+static void
+page_changed_cb (EvPageCache *page_cache,
+ gint page,
+ EvWindow *ev_window)
+{
+ update_action_sensitivity (ev_window);
+}
+
+static void
+update_document_mode (EvWindow *window, EvDocumentMode mode)
+{
+ if (mode == EV_DOCUMENT_MODE_FULL_SCREEN) {
+ ev_window_fullscreen (window);
+ } else if (mode == EV_DOCUMENT_MODE_PRESENTATION) {
+ ev_window_run_presentation (window);
+ }
+}
+
+static void
+ev_window_setup_document (EvWindow *ev_window)
+{
+ EvDocumentInfo *info;
+ EvDocument *document;
+ EvView *view = EV_VIEW (ev_window->priv->view);
+ EvSidebar *sidebar = EV_SIDEBAR (ev_window->priv->sidebar);
+ GtkAction *action;
+
+ document = ev_window->priv->document;
+ ev_window->priv->page_cache = ev_document_get_page_cache (ev_window->priv->document);
+ g_signal_connect (ev_window->priv->page_cache, "page-changed", G_CALLBACK (page_changed_cb), ev_window);
+
+ g_signal_connect_object (G_OBJECT (document),
+ "notify::title",
+ G_CALLBACK (update_window_title),
+ ev_window, 0);
+ if (EV_IS_DOCUMENT_FIND (document)) {
+ g_signal_connect_object (G_OBJECT (document),
+ "find_changed",
+ G_CALLBACK (find_changed_cb),
+ ev_window, 0);
+ }
+
+ ev_window_set_page_mode (ev_window, PAGE_MODE_DOCUMENT);
+
+ ev_sidebar_set_document (sidebar, document);
+
+ if (ev_page_cache_get_n_pages (ev_window->priv->page_cache) > 0) {
+ ev_view_set_document (view, document);
+ }
+
+ update_window_title (document, NULL, ev_window);
+ action = gtk_action_group_get_action (ev_window->priv->action_group, PAGE_SELECTOR_ACTION);
+ ev_page_action_set_document (EV_PAGE_ACTION (action), document);
+ update_action_sensitivity (ev_window);
+
+ info = ev_document_get_info (document);
+ update_document_mode (ev_window, info->mode);
+ ev_document_info_free (info);
+}
+
+static void
+password_dialog_response (GtkWidget *password_dialog,
+ gint response_id,
+ EvWindow *ev_window)
+{
+ char *password;
+
+ if (response_id == GTK_RESPONSE_OK) {
+ EvDocument *document;
+ gchar *uri;
+
+ password = ev_password_dialog_get_password (password_dialog);
+ if (password) {
+ ev_document_doc_mutex_lock ();
+ ev_document_security_set_password (EV_DOCUMENT_SECURITY (ev_window->priv->password_document),
+ password);
+ ev_document_doc_mutex_unlock ();
+ }
+ g_free (password);
+
+ document = ev_window->priv->password_document;
+ uri = ev_window->priv->password_uri;
+
+ ev_window->priv->password_document = NULL;
+ ev_window->priv->password_uri = NULL;
+
+ if (start_loading_document (ev_window, document, uri)) {
+ gtk_widget_destroy (password_dialog);
+ }
+
+ g_object_unref (document);
+ g_free (uri);
+
+ return;
+ }
+
+ gtk_widget_set_sensitive (ev_window->priv->password_view, TRUE);
+ gtk_widget_destroy (password_dialog);
+}
+
+/* Called either by start_loading_document or by the "unlock" callback on the
+ * password_view page. It assumes that ev_window->priv->password_* has been set
+ * correctly. These are cleared by password_dialog_response() */
+
+static void
+ev_window_popup_password_dialog (EvWindow *ev_window)
+{
+ g_assert (ev_window->priv->password_document);
+ g_assert (ev_window->priv->password_uri);
+
+ gtk_widget_set_sensitive (ev_window->priv->password_view, FALSE);
+
+ update_window_title (ev_window->priv->password_document, NULL, ev_window);
+ if (ev_window->priv->password_dialog == NULL) {
+ gchar *basename, *file_name;
+
+ basename = g_path_get_basename (ev_window->priv->password_uri);
+ file_name = gnome_vfs_unescape_string_for_display (basename);
+ ev_window->priv->password_dialog =
+ ev_password_dialog_new (GTK_WIDGET (ev_window), file_name);
+ g_object_add_weak_pointer (G_OBJECT (ev_window->priv->password_dialog),
+ (gpointer *) &(ev_window->priv->password_dialog));
+ g_signal_connect (ev_window->priv->password_dialog,
+ "response",
+ G_CALLBACK (password_dialog_response),
+ ev_window);
+ g_free (basename);
+ g_free (file_name);
+ gtk_widget_show (ev_window->priv->password_dialog);
+ } else {
+ ev_password_dialog_set_bad_pass (ev_window->priv->password_dialog);
+ }
+}
+
+/* This wil try to load the document. It might be called multiple times on the
+ * same document by the password dialog.
+ *
+ * Since the flow of the error dialog is very confusing, we assume that both
+ * document and uri will go away after this function is called, and thus we need
+ * to ref/dup them. Additionally, it needs to clear
+ * ev_window->priv->password_{uri,document}, and thus people who call this
+ * function should _not_ necessarily expect those to exist after being
+ * called. */
+static gboolean
+start_loading_document (EvWindow *ev_window,
+ EvDocument *document,
+ const char *uri)
+{
+ gboolean result;
+ GError *error = NULL;
+
+ g_assert (document);
+ g_assert (document != ev_window->priv->document);
+ g_assert (uri);
+ if (ev_window->priv->password_document) {
+ g_object_unref (ev_window->priv->password_document);
+ ev_window->priv->password_document = NULL;
+ }
+ if (ev_window->priv->password_uri) {
+ g_free (ev_window->priv->password_uri);
+ ev_window->priv->password_uri = NULL;
+ }
+
+ result = ev_document_load (document, uri, &error);
+
+ /* Success! */
+ if (result) {
+ if (ev_window->priv->document)
+ g_object_unref (ev_window->priv->document);
+ ev_window->priv->document = g_object_ref (document);
+ ev_window_setup_document (ev_window);
+
+ ev_window_add_recent (ev_window, uri);
+
+ return TRUE;
+ }
+
+ /* unable to load the document */
+ g_assert (error != NULL);
+
+ if (error->domain == EV_DOCUMENT_ERROR &&
+ error->code == EV_DOCUMENT_ERROR_ENCRYPTED) {
+ gchar *base_name, *file_name;
+
+ ev_window->priv->password_document = g_object_ref (document);
+ ev_window->priv->password_uri = g_strdup (uri);
+
+ base_name = g_path_get_basename (uri);
+ file_name = gnome_vfs_unescape_string_for_display (base_name);
+
+ ev_password_view_set_file_name (EV_PASSWORD_VIEW (ev_window->priv->password_view),
+ file_name);
+ g_free (file_name);
+ g_free (base_name);
+ ev_window_set_page_mode (ev_window, PAGE_MODE_PASSWORD);
+
+ ev_window_popup_password_dialog (ev_window);
+ } else {
+ unable_to_load (ev_window, error->message);
+ }
+ g_error_free (error);
+
+ 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;
+ 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);
+
+ document_type = ev_document_type_lookup (uri, &mime_type);
+ if (document_type != G_TYPE_INVALID) {
+ document = g_object_new (document_type, NULL);
+ }
+
+ if (document) {
+ start_loading_document (ev_window, document, uri);
+ /* See the comment on start_loading_document on ref counting.
+ * As the password dialog flow is confusing, we're very explicit
+ * on ref counting. */
+ g_object_unref (document);
+ } else {
+ char *error_message;
+
+ error_message = g_strdup_printf (_("Unhandled MIME type: '%s'"),
+ mime_type?mime_type:"<Unknown MIME Type>");
+ unable_to_load (ev_window, error_message);
+ g_free (error_message);
+ }
+
+ g_free (mime_type);
+}
+
+static void
+ev_window_open_uri_list (EvWindow *ev_window, GList *uri_list)
+{
+ GList *list;
+ 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);
+
+ 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);
+
+ gtk_widget_show (GTK_WIDGET (ev_window));
+ } else {
+ EvWindow *new_window;
+
+ new_window = ev_application_new_window (EV_APP);
+ ev_window_open (new_window, uri);
+
+ gtk_widget_show (GTK_WIDGET (new_window));
+ }
+ }
+
+ g_free (uri);
+
+ list = g_list_next (list);
+ }
+}
+
+static void
+ev_window_cmd_file_open (GtkAction *action, EvWindow *ev_window)
+{
+ ev_application_open (EV_APP, NULL);
+}
+
+static void
+ev_window_cmd_recent_file_activate (EggRecentViewGtk *view, EggRecentItem *item,
+ EvWindow *ev_window)
+{
+ char *uri;
+ GtkWidget *window;
+
+ uri = egg_recent_item_get_uri (item);
+
+ window = GTK_WIDGET (ev_application_get_empty_window (EV_APP));
+ gtk_widget_show (window);
+ ev_window_open (EV_WINDOW (window), uri);
+
+ g_free (uri);
+}
+
+static void
+ev_window_add_recent (EvWindow *window, const char *filename)
+{
+ EggRecentItem *item;
+
+ if (strstr (filename, "file:///") == NULL)
+ return;
+
+ item = egg_recent_item_new_from_uri (filename);
+ egg_recent_item_add_group (item, "Evince");
+ egg_recent_model_add_full (window->priv->recent_model, item);
+}
+
+static void
+ev_window_setup_recent (EvWindow *ev_window)
+{
+ GtkWidget *menu_item;
+ GtkWidget *menu;
+
+ menu_item = gtk_ui_manager_get_widget (ev_window->priv->ui_manager, "/MainMenu/FileMenu");
+ menu = gtk_menu_item_get_submenu (GTK_MENU_ITEM (menu_item));
+ menu_item = gtk_ui_manager_get_widget (ev_window->priv->ui_manager, "/MainMenu/FileMenu/RecentFilesMenu");
+
+ g_return_if_fail (menu != NULL);
+ g_return_if_fail (menu_item != NULL);
+
+ /* it would be better if we just filtered by mime-type, but there
+ * doesn't seem to be an easy way to figure out which mime-types we
+ * can handle */
+ ev_window->priv->recent_model = egg_recent_model_new (EGG_RECENT_MODEL_SORT_MRU);
+
+ ev_window->priv->recent_view = egg_recent_view_gtk_new (menu, menu_item);
+ egg_recent_view_gtk_show_icons (EGG_RECENT_VIEW_GTK (ev_window->priv->recent_view), FALSE);
+ egg_recent_model_set_limit (ev_window->priv->recent_model, 5);
+
+ egg_recent_view_set_model (EGG_RECENT_VIEW (ev_window->priv->recent_view),
+ ev_window->priv->recent_model);
+
+ egg_recent_model_set_filter_groups (ev_window->priv->recent_model,
+ "Evince", NULL);
+
+ egg_recent_view_gtk_set_trailing_sep (ev_window->priv->recent_view, TRUE);
+
+ g_signal_connect (ev_window->priv->recent_view, "activate",
+ G_CALLBACK (ev_window_cmd_recent_file_activate), ev_window);
+}
+
+/* FIXME
+static gboolean
+overwrite_existing_file (GtkWindow *window, const gchar *file_name)
+{
+ GtkWidget *msgbox;
+ gchar *utf8_file_name;
+ AtkObject *obj;
+ gint ret;
+
+ utf8_file_name = g_filename_to_utf8 (file_name, -1, NULL, NULL, NULL);
+ msgbox = gtk_message_dialog_new (
+ window,
+ (GtkDialogFlags)GTK_DIALOG_DESTROY_WITH_PARENT,
+ GTK_MESSAGE_QUESTION,
+ GTK_BUTTONS_NONE,
+ _("A file named \"%s\" already exists."),
+ utf8_file_name);
+ g_free (utf8_file_name);
+
+ gtk_message_dialog_format_secondary_text (
+ GTK_MESSAGE_DIALOG (msgbox),
+ _("Do you want to replace it with the one you are saving?"));
+
+ gtk_dialog_add_button (GTK_DIALOG (msgbox),
+ GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL);
+
+ gtk_dialog_add_button (GTK_DIALOG (msgbox),
+ _("_Replace"), GTK_RESPONSE_YES);
+
+ gtk_dialog_set_default_response (GTK_DIALOG (msgbox),
+ GTK_RESPONSE_CANCEL);
+
+ obj = gtk_widget_get_accessible (msgbox);
+
+ if (GTK_IS_ACCESSIBLE (obj))
+ atk_object_set_name (obj, _("Question"));
+
+ ret = gtk_dialog_run (GTK_DIALOG (msgbox));
+ gtk_widget_destroy (msgbox);
+
+ return (ret == GTK_RESPONSE_YES);
+}
+*/
+
+static void
+save_error_dialog (GtkWindow *window, const gchar *file_name)
+{
+ GtkWidget *error_dialog;
+
+ error_dialog = gtk_message_dialog_new (
+ window,
+ (GtkDialogFlags)GTK_DIALOG_DESTROY_WITH_PARENT,
+ GTK_MESSAGE_ERROR,
+ GTK_BUTTONS_CLOSE,
+ _("The file could not be saved as \"%s\"."),
+ file_name);
+
+ /* Easy way to make the text bold while keeping the string
+ * above free from pango markup (FIXME ?) */
+ gtk_message_dialog_format_secondary_text (
+ GTK_MESSAGE_DIALOG (error_dialog), " ");
+
+ gtk_dialog_run (GTK_DIALOG (error_dialog));
+ gtk_widget_destroy (error_dialog);
+}
+
+static void
+ev_window_cmd_save_as (GtkAction *action, EvWindow *ev_window)
+{
+ GtkWidget *fc;
+ GtkFileFilter *pdf_filter, *all_filter;
+ gchar *uri = NULL;
+ gboolean success;
+
+ fc = gtk_file_chooser_dialog_new (
+ _("Save a Copy"),
+ NULL, GTK_FILE_CHOOSER_ACTION_SAVE,
+ GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
+ GTK_STOCK_SAVE, GTK_RESPONSE_OK,
+ NULL);
+ gtk_window_set_modal (GTK_WINDOW (fc), TRUE);
+
+ pdf_filter = gtk_file_filter_new ();
+ gtk_file_filter_set_name (pdf_filter, _("PDF Documents"));
+ gtk_file_filter_add_mime_type (pdf_filter, "application/pdf");
+ gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (fc), pdf_filter);
+
+ all_filter = gtk_file_filter_new ();
+ gtk_file_filter_set_name (all_filter, _("All Files"));
+ gtk_file_filter_add_pattern (all_filter, "*");
+ gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (fc), all_filter);
+ gtk_file_chooser_set_filter (GTK_FILE_CHOOSER (fc), pdf_filter);
+
+ gtk_dialog_set_default_response (GTK_DIALOG (fc), GTK_RESPONSE_OK);
+
+ gtk_widget_show (fc);
+
+ while (gtk_dialog_run (GTK_DIALOG (fc)) == GTK_RESPONSE_OK) {
+ uri = gtk_file_chooser_get_uri (GTK_FILE_CHOOSER (fc));
+
+/* FIXME
+ if (g_file_test (uri, G_FILE_TEST_EXISTS) &&
+ !overwrite_existing_file (GTK_WINDOW (fc), uri))
+ continue;
+*/
+
+ ev_document_doc_mutex_lock ();
+ success = ev_document_save (ev_window->priv->document, uri, NULL);
+ ev_document_doc_mutex_unlock ();
+
+ if (success)
+ break;
+ else
+ save_error_dialog (GTK_WINDOW (fc), uri);
+ }
+ gtk_widget_destroy (fc);
+}
+