From d6d16f450c02e29b7e06b7e70f0575528646d601 Mon Sep 17 00:00:00 2001 From: Jeremy Wootten Date: Tue, 11 Apr 2023 16:27:35 +0100 Subject: [PATCH 01/22] Add AskSaveDialog.vala --- src/Dialogs/AskSaveLocationDialog.vala | 28 ++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) create mode 100644 src/Dialogs/AskSaveLocationDialog.vala diff --git a/src/Dialogs/AskSaveLocationDialog.vala b/src/Dialogs/AskSaveLocationDialog.vala new file mode 100644 index 0000000000..66fbf9c5f0 --- /dev/null +++ b/src/Dialogs/AskSaveLocationDialog.vala @@ -0,0 +1,28 @@ +/* Copyright 2023 elementary, Inc. + * SPDX-License-Identifier: GPL-3.0-or-later + */ +public class Scratch.Dialogs.AskSaveLocationDialog : Granite.MessageDialog { + + public AskSaveLocationDialog (string primary_text, string secondary_text, string error_message = "") { + Object ( + buttons: Gtk.ButtonsType.NONE, + primary_text: primary_text, + secondary_text: secondary_text + ); + + if (error_message != "") { + show_error_details (error_message); + } + } + + construct { + var app_instance = (Gtk.Application) GLib.Application.get_default (); + transient_for = app_instance.active_window; + image_icon = new ThemedIcon ("dialog-warning"); + + add_button (_("Ignore"), Gtk.ResponseType.REJECT); + + var saveas_button = (Gtk.Button) add_button (_("Save Document elsewhere"), Gtk.ResponseType.ACCEPT); + saveas_button.get_style_context ().add_class (Gtk.STYLE_CLASS_SUGGESTED_ACTION); + } +} From e9f3e3a0b8324d63f303538d7120a38285289a87 Mon Sep 17 00:00:00 2001 From: Jeremy Wootten Date: Tue, 11 Apr 2023 19:50:35 +0100 Subject: [PATCH 02/22] Introduce "locked" document state --- src/Services/Document.vala | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/src/Services/Document.vala b/src/Services/Document.vala index c6069d9900..9cf99e7c08 100644 --- a/src/Services/Document.vala +++ b/src/Services/Document.vala @@ -86,6 +86,26 @@ namespace Scratch.Services { } } + // Locked documents can be edited but cannot be (auto)saved to the current file. + // Locked documents can be saved to a different file (when they will be unlocked) + private bool _locked = true; + public bool locked { + get { + return _locked; + } + + set { + _locked = value; + Utils.action_from_group (MainWindow.ACTION_SAVE, actions).set_enabled (!value); + toggle_changed_handlers (!value); //Do not autosave locked documents + if (locked) { + icon = locked_icon; + } else { + icon = null; + } + } + } + public Gtk.Stack main_stack; public Scratch.Widgets.SourceView source_view; private Scratch.Services.SymbolOutline? outline = null; @@ -105,6 +125,7 @@ namespace Scratch.Services { private bool loaded = false; private bool mounted = true; // Mount state of the file private Mount mount; + private Icon locked_icon; private static Pango.FontDescription? builder_blocks_font = null; private static Pango.FontMap? builder_font_map = null; @@ -132,6 +153,7 @@ namespace Scratch.Services { } construct { + locked_icon = new ThemedIcon ("locked"); main_stack = new Gtk.Stack (); source_view = new Scratch.Widgets.SourceView (); @@ -211,6 +233,7 @@ namespace Scratch.Services { // /* Create as loaded - could be new document */ loaded = file == null; + locked = false; ellipsize_mode = Pango.EllipsizeMode.MIDDLE; } From 3cedc1fa9687cdef2921f320c8eef1b07aa93c25 Mon Sep 17 00:00:00 2001 From: Jeremy Wootten Date: Tue, 11 Apr 2023 19:55:10 +0100 Subject: [PATCH 03/22] Lock document during loading; unlock after if writable --- src/Services/Document.vala | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/Services/Document.vala b/src/Services/Document.vala index 9cf99e7c08..658eff553c 100644 --- a/src/Services/Document.vala +++ b/src/Services/Document.vala @@ -231,7 +231,7 @@ namespace Scratch.Services { completion_shown = false; }); - // /* Create as loaded - could be new document */ + // /* Create as loaded and unlocked - could be new document */ loaded = file == null; locked = false; ellipsize_mode = Pango.EllipsizeMode.MIDDLE; @@ -273,6 +273,7 @@ namespace Scratch.Services { public async void open (bool force = false) { /* Loading improper files may hang so we cancel after a certain time as a fallback. * In most cases, an error will be thrown and caught. */ + locked = true; loaded = false; if (load_cancellable != null) { /* just in case */ load_cancellable.cancel (); @@ -366,8 +367,10 @@ namespace Scratch.Services { // Focus in event for SourceView this.source_view.focus_in_event.connect (() => { - check_file_status (); - check_undoable_actions (); + if (!locked) { + check_file_status (); + check_undoable_actions (); + } return false; }); @@ -388,6 +391,7 @@ namespace Scratch.Services { Idle.add (() => { working = false; loaded = true; + check_file_status (); return false; }); From 88c2bbf217f5ef406f44f38504ff47247a910f4d Mon Sep 17 00:00:00 2001 From: Jeremy Wootten Date: Tue, 11 Apr 2023 20:00:39 +0100 Subject: [PATCH 04/22] Stop some functions if locked --- src/Services/Document.vala | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/src/Services/Document.vala b/src/Services/Document.vala index 658eff553c..bd2a9e88d3 100644 --- a/src/Services/Document.vala +++ b/src/Services/Document.vala @@ -201,11 +201,9 @@ namespace Scratch.Services { this.source_view.buffer.create_tag ("highlight_search_all", "background", "yellow", null); - toggle_changed_handlers (true); - // Focus out event for SourceView this.source_view.focus_out_event.connect (() => { - if (Scratch.settings.get_boolean ("autosave")) { + if (!locked && Scratch.settings.get_boolean ("autosave")) { save.begin (); } @@ -215,7 +213,8 @@ namespace Scratch.Services { source_view.buffer.changed.connect (() => { if (source_view.buffer.text != last_save_content) { saved = false; - if (!Scratch.settings.get_boolean ("autosave")) { + // Autosave does not work on locked document + if (locked || !Scratch.settings.get_boolean ("autosave")) { set_saved_status (false); } } else { @@ -401,7 +400,7 @@ namespace Scratch.Services { public async bool do_close (bool app_closing = false) { debug ("Closing \"%s\"", get_basename ()); - if (!loaded) { + if (!loaded || locked) { load_cancellable.cancel (); return true; } @@ -466,7 +465,7 @@ namespace Scratch.Services { private bool is_saving = false; public async bool save_with_hold (bool force = false, bool saving_as = false) { // Prevent reentry which could result in mismatched holds on Application - if (is_saving) { + if (is_saving || locked) { return true; } else { is_saving = true; @@ -485,20 +484,24 @@ namespace Scratch.Services { is_saving = false; } + return result; } public async bool save_as_with_hold () { var old_uri = file.get_uri (); + var old_locked = locked; + locked = false; // Can always try to save as a different file var result = yield save_with_hold (true, true); if (!result) { file = File.new_for_uri (old_uri); + locked = old_locked; } return result; } - private async bool save (bool force = false, bool saving_as = false) { + private async bool save (bool force = false, bool saving_as = false) requires (!locked) { if (completion_shown || !force && (source_view.buffer.get_modified () == false || !loaded)) { @@ -543,7 +546,7 @@ namespace Scratch.Services { return true; } - public async bool save_as () { + private async bool save_as () requires (!locked) { // New file if (!loaded) { return false; From bad0f37b9cc55dc347fb277bfb6800e26966c11a Mon Sep 17 00:00:00 2001 From: Jeremy Wootten Date: Tue, 11 Apr 2023 20:02:19 +0100 Subject: [PATCH 05/22] Modify save and save as functions for locked --- src/Services/Document.vala | 39 +++++++++++++++++++++++++------------- 1 file changed, 26 insertions(+), 13 deletions(-) diff --git a/src/Services/Document.vala b/src/Services/Document.vala index bd2a9e88d3..e65e5271a3 100644 --- a/src/Services/Document.vala +++ b/src/Services/Document.vala @@ -516,19 +516,35 @@ namespace Scratch.Services { save_cancellable.cancel (); save_cancellable = new GLib.Cancellable (); var source_file_saver = new Gtk.SourceFileSaver ((Gtk.SourceBuffer) source_view.buffer, source_file); + var success = false; + var error = ""; try { - yield source_file_saver.save_async (GLib.Priority.DEFAULT, save_cancellable, null); + success = yield source_file_saver.save_async (GLib.Priority.DEFAULT, save_cancellable, null); // Only create backup once save successful - this.create_backup (); + if (success) { + create_backup (); + } } catch (Error e) { - // We don't need to send an error message at cancellation (corresponding to error code 19) - if (e.code != 19) { - warning ("Cannot save “%s”: %s", get_basename (), e.message); - // If called by `save_as ()` then that function will show infobar - if (!saving_as) { - ask_save_location (false); - } + if (e.code != 19) { // Not cancelled + error = e.message; + } else { + return false; } + } + + if (!success) { + warning ("Cannot save “%s”: %s", get_uri (), error); + locked = true; + // Allow save process to complete before showing dialog + Idle.add (() => { + ask_save_location ( + _("Saving to “%s” failed.").printf (get_uri ()), + error + ); + + return Source.REMOVE; + }); + return false; } @@ -599,11 +615,8 @@ namespace Scratch.Services { delete_backup (current_file.get_uri () + "~"); this.source_view.change_syntax_highlight_from_file (this.file); - } else { - // Restore original file - file = current_file; - ask_save_location (true); } + // Calling function responsible for restoring original } /* We delay destruction of file chooser dialog til to avoid the document focussing in, From 3c821f27ac49cb8393b122be20cfcbb9ef6ff5c8 Mon Sep 17 00:00:00 2001 From: Jeremy Wootten Date: Tue, 11 Apr 2023 20:03:05 +0100 Subject: [PATCH 06/22] Make some funcs private --- src/Services/Document.vala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Services/Document.vala b/src/Services/Document.vala index e65e5271a3..2af6f66bf6 100644 --- a/src/Services/Document.vala +++ b/src/Services/Document.vala @@ -686,7 +686,7 @@ namespace Scratch.Services { } // Set InfoBars message - public void set_message (Gtk.MessageType type, string label, + private void set_message (Gtk.MessageType type, string label, string? button1 = null, owned VoidFunc? callback1 = null, string? button2 = null, owned VoidFunc? callback2 = null) { From 0d3509375e9890e64270d6172689f47794b04b93 Mon Sep 17 00:00:00 2001 From: Jeremy Wootten Date: Tue, 11 Apr 2023 20:05:42 +0100 Subject: [PATCH 07/22] Modify check file status function for locked --- src/Services/Document.vala | 87 ++++++++++++++++++++++++++++---------- 1 file changed, 65 insertions(+), 22 deletions(-) diff --git a/src/Services/Document.vala b/src/Services/Document.vala index 2af6f66bf6..da5204b722 100644 --- a/src/Services/Document.vala +++ b/src/Services/Document.vala @@ -837,37 +837,80 @@ namespace Scratch.Services { } // Check if the file was deleted/changed by an external source - public void check_file_status () { + private void check_file_status () { // If the file does not exist anymore if (!exists ()) { + locked = true; + string details; if (mounted == false) { - string message = _( - "The location containing the file “%s” was unmounted. Do you want to save somewhere else?" - ).printf ("%s".printf (get_basename ())); + details = _("The location containing the file “%s” was unmounted."); + } else { + details = _("File “%s” was deleted."); + } - set_message (Gtk.MessageType.WARNING, message, _("Save As…"), () => { - this.save_as.begin (); - hide_info_bar (); - }); + ask_save_location (details.printf ("%s".printf (get_basename ()))); + } else if (loaded) { // Check external changes after loading + if (!locked && !can_write () && source_view.buffer.get_modified ()) { + // The file has become unwritable while changes are pending + locked = true; + var details = _("File “%s” was does not have write permission."); + ask_save_location (details.printf ("%s".printf (get_basename ()))); } else { - string message = _( - "File “%s” was deleted. Do you want to save it anyway?" - ).printf ("%s".printf (get_basename ())); + // Check for external changes (can load even if locked or unwritable) + var new_buffer = new Gtk.SourceBuffer (null); + var source_file_loader = new Gtk.SourceFileLoader ( + new_buffer, + source_file + ); + source_file_loader.load_async.begin ( + GLib.Priority.DEFAULT, + null, + null, + (obj, res) => { + try { + source_file_loader.load_async.end (res); + } catch (Error e) { + critical (e.message); + show_default_load_error_view (); + return; + } - set_message (Gtk.MessageType.WARNING, message, _("Save"), () => { - this.save.begin (); - hide_info_bar (); - }); - } + if (source_view.buffer.text == new_buffer.text) { + return; + } - Utils.action_from_group (MainWindow.ACTION_SAVE, actions).set_enabled (false); - this.source_view.editable = false; - return; + if (!source_view.buffer.get_modified ()) { + //FIXME Should block editing until responded? + if (Scratch.settings.get_boolean ("autosave")) { + source_view.set_text (new_buffer.text, false); + } else { + string message = _( + "File “%s” was modified by an external application." + ).printf ("%s".printf (get_uri ())); + + set_message ( + Gtk.MessageType.WARNING, + message, + _("Reload"), () => { + this.source_view.set_text ( + new_buffer.text, false + ); + hide_info_bar (); + }, + _("Continue"), () => { + hide_info_bar (); + }) + ; + } + } else { + //TODO Handle conflicting changes (dialog?) + } + } + ); + } } + } - // If the file can't be written - if (!can_write ()) { - ask_save_location (); } else { Utils.action_from_group (MainWindow.ACTION_SAVE, actions).set_enabled (true); this.source_view.editable = true; From d3e300e7b0fab4cfd43f472420ea57e50054d52d Mon Sep 17 00:00:00 2001 From: Jeremy Wootten Date: Tue, 11 Apr 2023 20:06:32 +0100 Subject: [PATCH 08/22] Rewrite ask save location for dialog and locked --- src/Services/Document.vala | 99 ++++++++++++-------------------------- 1 file changed, 31 insertions(+), 68 deletions(-) diff --git a/src/Services/Document.vala b/src/Services/Document.vala index da5204b722..3427acb4b1 100644 --- a/src/Services/Document.vala +++ b/src/Services/Document.vala @@ -911,83 +911,46 @@ namespace Scratch.Services { } } + private void ask_save_location ( + string details, + string error_text = "" + ) { + locked = true; + string primary_text; + if (source_view.buffer.get_modified ()) { + primary_text = _("The document cannot be saved"); } else { - Utils.action_from_group (MainWindow.ACTION_SAVE, actions).set_enabled (true); - this.source_view.editable = true; + primary_text = _("The changes to the document cannot be saved"); } - // Detect external changes - if (loaded) { - var new_buffer = new Gtk.SourceBuffer (null); - var source_file_loader = new Gtk.SourceFileLoader (new_buffer, source_file); - source_file_loader.load_async.begin (GLib.Priority.DEFAULT, null, null, (obj, res) => { - try { - source_file_loader.load_async.end (res); - } catch (Error e) { - critical (e.message); - show_default_load_error_view (); - return; - } - - if (source_view.buffer.text == new_buffer.text) { - return; - } + var dialog = new Scratch.Dialogs.AskSaveLocationDialog ( + primary_text, + details, + error_text + ); - if (!source_view.buffer.get_modified ()) { - if (Scratch.settings.get_boolean ("autosave")) { - source_view.set_text (new_buffer.text, false); - } else { - string message = _( - "File “%s” was modified by an external application. Do you want to load it again or continue your editing?" - ).printf ("%s".printf (get_basename ())); - - set_message (Gtk.MessageType.WARNING, message, _("Load"), () => { - this.source_view.set_text (new_buffer.text, false); - hide_info_bar (); - }, _("Continue"), () => { - hide_info_bar (); + dialog.response.connect ((id) => { + dialog.destroy (); + Idle.add (() => { + switch (id) { + case Gtk.ResponseType.ACCEPT: + save_as_with_hold.begin ((obj, res) => { + if (save_as_with_hold.end (res)) { + locked = false; + } }); - } + break; + case Gtk.ResponseType.REJECT: + break; + default: + assert_not_reached (); } - }); - } - } - private void save_as_and_hide_infobar () { - save_as.begin ((obj, res) => { - if (save_as.end (res)) { - hide_info_bar (); - } + return false; + }); }); - } - - private void ask_save_location (bool save_as = false) { - // We must assume that already asking for save location if infobar is - // visible. - if (info_bar.visible == true) { - return; - } - - string message; - if (save_as) { - message = _( - "You cannot save the document to “%s”. Do you want to save the file somewhere else?" - ).printf ("%s".printf (get_directory ())); - } else { - message = _( - "You cannot save changes to the file “%s”. Do you want to save the changes somewhere else?" - ).printf ("%s".printf (get_basename ())); - } - - set_message ( - Gtk.MessageType.WARNING, - message, - _("Save the document elsewhere"), - save_as_and_hide_infobar - ); - Utils.action_from_group (MainWindow.ACTION_SAVE, actions).set_enabled (false); - this.source_view.editable = !Scratch.settings.get_boolean ("autosave"); + dialog.present (); } // Set Undo/Redo action sensitive property From eef32abe0914724bb3282a6b67c373b6fea61bf3 Mon Sep 17 00:00:00 2001 From: Jeremy Wootten Date: Tue, 11 Apr 2023 20:07:14 +0100 Subject: [PATCH 09/22] Compile dialog --- src/meson.build | 1 + 1 file changed, 1 insertion(+) diff --git a/src/meson.build b/src/meson.build index 55f6b3510a..47e13c324f 100644 --- a/src/meson.build +++ b/src/meson.build @@ -20,6 +20,7 @@ code_files = files( 'Utils.vala', 'Dialogs/PreferencesDialog.vala', 'Dialogs/RestoreConfirmationDialog.vala', + 'Dialogs/AskSaveLocationDialog.vala', 'Dialogs/GlobalSearchDialog.vala', 'Dialogs/NewBranchDialog.vala', 'FolderManager/ContractMenuItem.vala', From 453ccc45e0f89f9bae6e7870bb1fea3ffafb1f2a Mon Sep 17 00:00:00 2001 From: Jeremy Wootten Date: Tue, 11 Apr 2023 20:07:37 +0100 Subject: [PATCH 10/22] Minor improvements --- src/Dialogs/AskSaveLocationDialog.vala | 2 +- src/Services/Document.vala | 9 ++++----- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/src/Dialogs/AskSaveLocationDialog.vala b/src/Dialogs/AskSaveLocationDialog.vala index 66fbf9c5f0..61d43ee5d5 100644 --- a/src/Dialogs/AskSaveLocationDialog.vala +++ b/src/Dialogs/AskSaveLocationDialog.vala @@ -3,7 +3,7 @@ */ public class Scratch.Dialogs.AskSaveLocationDialog : Granite.MessageDialog { - public AskSaveLocationDialog (string primary_text, string secondary_text, string error_message = "") { + public AskSaveLocationDialog (string primary_text, string secondary_text, string error_message) { Object ( buttons: Gtk.ButtonsType.NONE, primary_text: primary_text, diff --git a/src/Services/Document.vala b/src/Services/Document.vala index 3427acb4b1..1645f88143 100644 --- a/src/Services/Document.vala +++ b/src/Services/Document.vala @@ -179,8 +179,8 @@ namespace Scratch.Services { settings.changed.connect (restore_settings); /* Block user editing while working */ - source_view.key_press_event.connect (() => { - return working; + notify["working"].connect (() => { + source_view.sensitive = !working; }); var source_grid = new Gtk.Grid () { @@ -601,7 +601,7 @@ namespace Scratch.Services { var is_saved = false; if (success) { - source_view.buffer.set_modified (true); + // Should not set "modified" state of the buffer to true - this is automatic is_saved = yield save (true, true); if (is_saved) { if (is_current_file_temporary) { @@ -989,8 +989,7 @@ namespace Scratch.Services { try { file.copy (backup, FileCopyFlags.NONE); } catch (Error e) { - warning ("Cannot create backup copy for file “%s”: %s", get_basename (), e.message); - ask_save_location (); + warning ("Cannot create backup copy for file “%s”: %s", get_uri (), e.message); } } } From 24111241e95cefddabb4f63eacb475792295953b Mon Sep 17 00:00:00 2001 From: Jeremy Wootten Date: Wed, 12 Apr 2023 11:09:45 +0100 Subject: [PATCH 11/22] Start unlocked after loading --- src/Services/Document.vala | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Services/Document.vala b/src/Services/Document.vala index 1645f88143..457989d099 100644 --- a/src/Services/Document.vala +++ b/src/Services/Document.vala @@ -390,6 +390,7 @@ namespace Scratch.Services { Idle.add (() => { working = false; loaded = true; + locked = false; // Assume writable until status checked check_file_status (); return false; }); From 3826760d3a565f4bef5a84b3d7b0015b242119d7 Mon Sep 17 00:00:00 2001 From: Jeremy Wootten Date: Wed, 12 Apr 2023 12:17:01 +0100 Subject: [PATCH 12/22] Handle closing changed locked documents --- src/Services/Document.vala | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/src/Services/Document.vala b/src/Services/Document.vala index 457989d099..ca0ca98c3e 100644 --- a/src/Services/Document.vala +++ b/src/Services/Document.vala @@ -401,19 +401,22 @@ namespace Scratch.Services { public async bool do_close (bool app_closing = false) { debug ("Closing \"%s\"", get_basename ()); - if (!loaded || locked) { + if (!loaded) { load_cancellable.cancel (); return true; } bool ret_value = true; - if (Scratch.settings.get_boolean ("autosave") && !saved) { + // Prevent trying to save locked document to current location + if (!locked && Scratch.settings.get_boolean ("autosave") && !saved) { ret_value = yield save_with_hold (); - } else if (app_closing && is_file_temporary && !delete_temporary_file ()) { + } else if (!locked && app_closing && is_file_temporary && !delete_temporary_file ()) { debug ("Save temporary file!"); ret_value = yield save_with_hold (); - } else if (!this.saved || (!app_closing && is_file_temporary && !delete_temporary_file ())) { - // Check for unsaved changes + } else if (!this.saved || // Even locked documents can be modified + (!app_closing && is_file_temporary && !delete_temporary_file ())) { + + // Ask whether to save changes var parent_window = source_view.get_toplevel () as Gtk.Window; var dialog = new Granite.MessageDialog ( @@ -438,7 +441,8 @@ namespace Scratch.Services { ret_value = false; break; case Gtk.ResponseType.YES: - if (this.is_file_temporary) { + // Must save locked or temporary documents to a different location + if (locked || this.is_file_temporary) { ret_value = yield save_as_with_hold (); } else { ret_value = yield save_with_hold (); From ee5cbdb34bb8b681ff45eb78c1236f2cef7a8f05 Mon Sep 17 00:00:00 2001 From: Jeremy Wootten Date: Wed, 12 Apr 2023 12:25:06 +0100 Subject: [PATCH 13/22] Update saved status when locked status changes --- src/Services/Document.vala | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/Services/Document.vala b/src/Services/Document.vala index ca0ca98c3e..2df1cc5ef8 100644 --- a/src/Services/Document.vala +++ b/src/Services/Document.vala @@ -103,6 +103,8 @@ namespace Scratch.Services { } else { icon = null; } + // Show "unsaved" marker on tab when locked even when autosave is ON + set_saved_status (!source_view.buffer.get_modified ()); } } From a2c3a6d357d257774dc65a06b9318c909ff88f96 Mon Sep 17 00:00:00 2001 From: Jeremy Wootten Date: Wed, 12 Apr 2023 12:31:15 +0100 Subject: [PATCH 14/22] Amend tab tooltip when locked --- src/Services/Document.vala | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/Services/Document.vala b/src/Services/Document.vala index 2df1cc5ef8..181a0fe1f9 100644 --- a/src/Services/Document.vala +++ b/src/Services/Document.vala @@ -687,6 +687,8 @@ namespace Scratch.Services { public string get_tab_tooltip () { if (is_file_temporary) { return _("New Document"); //No path for a new document + } else if (locked) { + return _("Cannot save this document to %s").printf (Scratch.Utils.replace_home_with_tilde (file.get_path ())); } else { return Scratch.Utils.replace_home_with_tilde (file.get_path ()); } From aeb25bd38480d47633f8bef6d645a26a6af33317 Mon Sep 17 00:00:00 2001 From: Jeremy Wootten Date: Tue, 25 Apr 2023 17:21:11 +0100 Subject: [PATCH 15/22] Update src/Dialogs/AskSaveLocationDialog.vala MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Change button text to "Save Duplicate" Co-authored-by: Danielle Foré --- src/Dialogs/AskSaveLocationDialog.vala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Dialogs/AskSaveLocationDialog.vala b/src/Dialogs/AskSaveLocationDialog.vala index 61d43ee5d5..45525b9eda 100644 --- a/src/Dialogs/AskSaveLocationDialog.vala +++ b/src/Dialogs/AskSaveLocationDialog.vala @@ -22,7 +22,7 @@ public class Scratch.Dialogs.AskSaveLocationDialog : Granite.MessageDialog { add_button (_("Ignore"), Gtk.ResponseType.REJECT); - var saveas_button = (Gtk.Button) add_button (_("Save Document elsewhere"), Gtk.ResponseType.ACCEPT); + var saveas_button = (Gtk.Button) add_button (_("Save Duplicate…"), Gtk.ResponseType.ACCEPT); saveas_button.get_style_context ().add_class (Gtk.STYLE_CLASS_SUGGESTED_ACTION); } } From c0d7ccda633869dcd286681159a707b574190162 Mon Sep 17 00:00:00 2001 From: Jeremy Wootten Date: Tue, 25 Apr 2023 17:22:01 +0100 Subject: [PATCH 16/22] Update src/Services/Document.vala MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use emblem-readonly-symbolic for locked document Co-authored-by: Danielle Foré --- src/Services/Document.vala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Services/Document.vala b/src/Services/Document.vala index 181a0fe1f9..fcb5a5dd84 100644 --- a/src/Services/Document.vala +++ b/src/Services/Document.vala @@ -155,7 +155,7 @@ namespace Scratch.Services { } construct { - locked_icon = new ThemedIcon ("locked"); + locked_icon = new ThemedIcon ("emblem-readonly-symbolic"); main_stack = new Gtk.Stack (); source_view = new Scratch.Widgets.SourceView (); From 5e103553aab1b60e1897234dfc3ecd40d9a11016 Mon Sep 17 00:00:00 2001 From: Jeremy Wootten Date: Tue, 25 Apr 2023 17:41:41 +0100 Subject: [PATCH 17/22] Update src/Services/Document.vala MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Better primary text Co-authored-by: Danielle Foré --- src/Services/Document.vala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Services/Document.vala b/src/Services/Document.vala index fcb5a5dd84..9f4c069a4b 100644 --- a/src/Services/Document.vala +++ b/src/Services/Document.vala @@ -927,7 +927,7 @@ namespace Scratch.Services { locked = true; string primary_text; if (source_view.buffer.get_modified ()) { - primary_text = _("The document cannot be saved"); + primary_text = _("“%s” can't be saved here. Save a duplicate somewhere else?"); } else { primary_text = _("The changes to the document cannot be saved"); } From 6e7bcf162c6911b321e88cbe5d9087a3fbcd38fe Mon Sep 17 00:00:00 2001 From: Jeremy Wootten Date: Tue, 25 Apr 2023 18:04:27 +0100 Subject: [PATCH 18/22] Use "document-save" badged with "dialog-question" --- src/Dialogs/AskSaveLocationDialog.vala | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Dialogs/AskSaveLocationDialog.vala b/src/Dialogs/AskSaveLocationDialog.vala index 45525b9eda..81ea5f7691 100644 --- a/src/Dialogs/AskSaveLocationDialog.vala +++ b/src/Dialogs/AskSaveLocationDialog.vala @@ -18,7 +18,8 @@ public class Scratch.Dialogs.AskSaveLocationDialog : Granite.MessageDialog { construct { var app_instance = (Gtk.Application) GLib.Application.get_default (); transient_for = app_instance.active_window; - image_icon = new ThemedIcon ("dialog-warning"); + image_icon = new ThemedIcon ("document-save"); + badge_icon = new ThemedIcon ("dialog-question"); add_button (_("Ignore"), Gtk.ResponseType.REJECT); From 305f9927ddf95e2fa2a374d554461821be8088d3 Mon Sep 17 00:00:00 2001 From: Jeremy Wootten Date: Tue, 25 Apr 2023 18:14:29 +0100 Subject: [PATCH 19/22] Show path not uri in dialog --- src/Services/Document.vala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Services/Document.vala b/src/Services/Document.vala index 9f4c069a4b..9e2db080ed 100644 --- a/src/Services/Document.vala +++ b/src/Services/Document.vala @@ -545,7 +545,7 @@ namespace Scratch.Services { // Allow save process to complete before showing dialog Idle.add (() => { ask_save_location ( - _("Saving to “%s” failed.").printf (get_uri ()), + _("Saving to “%s” failed.").printf (file.get_path ()), error ); From bb4b74ed6bbd4b782641348e9fc8349b4297df53 Mon Sep 17 00:00:00 2001 From: Jeremy Wootten Date: Tue, 25 Apr 2023 18:26:24 +0100 Subject: [PATCH 20/22] Only one dialog primary text. Insert file path --- src/Services/Document.vala | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/src/Services/Document.vala b/src/Services/Document.vala index 9e2db080ed..e245ce2446 100644 --- a/src/Services/Document.vala +++ b/src/Services/Document.vala @@ -925,15 +925,8 @@ namespace Scratch.Services { string error_text = "" ) { locked = true; - string primary_text; - if (source_view.buffer.get_modified ()) { - primary_text = _("“%s” can't be saved here. Save a duplicate somewhere else?"); - } else { - primary_text = _("The changes to the document cannot be saved"); - } - var dialog = new Scratch.Dialogs.AskSaveLocationDialog ( - primary_text, + _("“%s” can't be saved here. Save a duplicate somewhere else?").printf (file.get_path ()), details, error_text ); From 1728a816632cc58f93440925bc4918a124d4a1c7 Mon Sep 17 00:00:00 2001 From: Jeremy Wootten Date: Wed, 26 Apr 2023 17:53:52 +0100 Subject: [PATCH 21/22] Inline the AskSaveLocation dialog --- src/Dialogs/AskSaveLocationDialog.vala | 29 -------------------------- src/Services/Document.vala | 24 ++++++++++++++++----- src/meson.build | 1 - 3 files changed, 19 insertions(+), 35 deletions(-) delete mode 100644 src/Dialogs/AskSaveLocationDialog.vala diff --git a/src/Dialogs/AskSaveLocationDialog.vala b/src/Dialogs/AskSaveLocationDialog.vala deleted file mode 100644 index 81ea5f7691..0000000000 --- a/src/Dialogs/AskSaveLocationDialog.vala +++ /dev/null @@ -1,29 +0,0 @@ -/* Copyright 2023 elementary, Inc. - * SPDX-License-Identifier: GPL-3.0-or-later - */ -public class Scratch.Dialogs.AskSaveLocationDialog : Granite.MessageDialog { - - public AskSaveLocationDialog (string primary_text, string secondary_text, string error_message) { - Object ( - buttons: Gtk.ButtonsType.NONE, - primary_text: primary_text, - secondary_text: secondary_text - ); - - if (error_message != "") { - show_error_details (error_message); - } - } - - construct { - var app_instance = (Gtk.Application) GLib.Application.get_default (); - transient_for = app_instance.active_window; - image_icon = new ThemedIcon ("document-save"); - badge_icon = new ThemedIcon ("dialog-question"); - - add_button (_("Ignore"), Gtk.ResponseType.REJECT); - - var saveas_button = (Gtk.Button) add_button (_("Save Duplicate…"), Gtk.ResponseType.ACCEPT); - saveas_button.get_style_context ().add_class (Gtk.STYLE_CLASS_SUGGESTED_ACTION); - } -} diff --git a/src/Services/Document.vala b/src/Services/Document.vala index e245ce2446..783950b1b1 100644 --- a/src/Services/Document.vala +++ b/src/Services/Document.vala @@ -925,11 +925,25 @@ namespace Scratch.Services { string error_text = "" ) { locked = true; - var dialog = new Scratch.Dialogs.AskSaveLocationDialog ( - _("“%s” can't be saved here. Save a duplicate somewhere else?").printf (file.get_path ()), + var app_instance = (Gtk.Application) GLib.Application.get_default (); + var dialog = new Granite.MessageDialog.with_image_from_icon_name ( + _("“%s” can't be saved here. Save a duplicate somewhere else?").printf (file.get_basename ()), details, - error_text - ); + "document-save", + Gtk.ButtonsType.NONE + ) { + badge_icon = new ThemedIcon ("dialog-question"), + transient_for = app_instance.active_window + }; + + dialog.add_button (_("Ignore"), Gtk.ResponseType.REJECT); + + var saveas_button = (Gtk.Button) dialog.add_button (_("Save Duplicate…"), Gtk.ResponseType.ACCEPT); + saveas_button.get_style_context ().add_class (Gtk.STYLE_CLASS_SUGGESTED_ACTION); + + if (error_text != "") { + dialog.show_error_details (error_text); + } dialog.response.connect ((id) => { dialog.destroy (); @@ -945,7 +959,7 @@ namespace Scratch.Services { case Gtk.ResponseType.REJECT: break; default: - assert_not_reached (); + break; } return false; diff --git a/src/meson.build b/src/meson.build index 47e13c324f..55f6b3510a 100644 --- a/src/meson.build +++ b/src/meson.build @@ -20,7 +20,6 @@ code_files = files( 'Utils.vala', 'Dialogs/PreferencesDialog.vala', 'Dialogs/RestoreConfirmationDialog.vala', - 'Dialogs/AskSaveLocationDialog.vala', 'Dialogs/GlobalSearchDialog.vala', 'Dialogs/NewBranchDialog.vala', 'FolderManager/ContractMenuItem.vala', From ccfc9d5d5ada78c9fe1f0f7b6566d73de79a0734 Mon Sep 17 00:00:00 2001 From: Jeremy Wootten Date: Wed, 26 Apr 2023 18:14:24 +0100 Subject: [PATCH 22/22] Suppress criticals on startup --- src/Services/Document.vala | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/src/Services/Document.vala b/src/Services/Document.vala index 783950b1b1..444bc73976 100644 --- a/src/Services/Document.vala +++ b/src/Services/Document.vala @@ -37,9 +37,13 @@ namespace Scratch.Services { public bool is_file_temporary { get { - return file.get_path ().has_prefix ( - ((Scratch.Application) GLib.Application.get_default ()).data_home_folder_unsaved - ); + if (file != null) { + return file.get_path ().has_prefix ( + ((Scratch.Application) GLib.Application.get_default ()).data_home_folder_unsaved + ); + } else { + return false; + } } } @@ -687,10 +691,12 @@ namespace Scratch.Services { public string get_tab_tooltip () { if (is_file_temporary) { return _("New Document"); //No path for a new document - } else if (locked) { + } else if (file != null && locked) { return _("Cannot save this document to %s").printf (Scratch.Utils.replace_home_with_tilde (file.get_path ())); - } else { + } else if (file != null) { return Scratch.Utils.replace_home_with_tilde (file.get_path ()); + } else { + return ""; } }