From 0987e69b440b010e687612bf1965748aaa290c6f Mon Sep 17 00:00:00 2001 From: Jeremy Wootten Date: Thu, 23 Mar 2023 18:23:40 +0000 Subject: [PATCH 1/7] Ignore external changes after "Continue" --- src/Services/Document.vala | 49 ++++++++++++++++++++++++-------------- 1 file changed, 31 insertions(+), 18 deletions(-) diff --git a/src/Services/Document.vala b/src/Services/Document.vala index 9496d73446..1e9120359c 100644 --- a/src/Services/Document.vala +++ b/src/Services/Document.vala @@ -93,6 +93,7 @@ namespace Scratch.Services { private string last_save_content; public bool saved = true; private bool completion_shown = false; + private bool ignore_external_changes = false; private Gtk.ScrolledWindow scroll; private Gtk.InfoBar info_bar; @@ -251,6 +252,8 @@ namespace Scratch.Services { /* 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. */ loaded = false; + ignore_external_changes = false; + if (load_cancellable != null) { /* just in case */ load_cancellable.cancel (); } @@ -557,9 +560,9 @@ namespace Scratch.Services { var is_saved = false; if (success) { - source_view.buffer.set_modified (true); is_saved = yield save (true, true); if (is_saved) { + source_view.buffer.set_modified (false); if (is_current_file_temporary) { try { // Delete temporary file @@ -806,8 +809,14 @@ namespace Scratch.Services { this.source_view.editable = true; } - // Detect external changes - if (loaded) { + // Detect external changes by comparing file content with buffer content. + // Only done when no unsaved internal changes else difference from saved + // file are to be expected. If user selects to continue regardless then no further + // check made for this document - external changes will be overwritten on next (auto) save + if (loaded && + !source_view.buffer.get_modified () && + !ignore_external_changes) { + 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) => { @@ -823,22 +832,26 @@ namespace Scratch.Services { return; } - 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 (); - }); - } + string message; + if (Scratch.settings.get_boolean ("autosave")) { + message = _( + "File \"%s\" was modified by an external application. Do you want to reload the document? \nOtherwise, if you continue, the external changes will be overwritten by your next edit and any further external changes will be ignored." + ).printf ("%s".printf (get_basename ())); + } else { + message = _( + "File \"%s\" was modified by an external application. Do you want to reload the document? \nOtherwise, if you continue, the external changes will be overwritten by your next save and any further external changes will be ignored." + ).printf ("%s".printf (get_basename ())); } + + set_message (Gtk.MessageType.WARNING, message, _("Reload"), () => { + // this.source_view.set_text (new_buffer.text, false); + // set_modified (false); + hide_info_bar (); + this.open.begin (true); + }, _("Continue"), () => { + hide_info_bar (); + ignore_external_changes = true; + }); }); } } From 3cc29cf07a5c0e8fe86014d92198ebce4ea24f61 Mon Sep 17 00:00:00 2001 From: Jeremy Wootten Date: Fri, 24 Mar 2023 11:18:26 +0000 Subject: [PATCH 2/7] Reload or Overwrite options --- src/Services/Document.vala | 59 ++++++++++++++++++++++---------------- 1 file changed, 34 insertions(+), 25 deletions(-) diff --git a/src/Services/Document.vala b/src/Services/Document.vala index 1e9120359c..09e9900839 100644 --- a/src/Services/Document.vala +++ b/src/Services/Document.vala @@ -93,7 +93,7 @@ namespace Scratch.Services { private string last_save_content; public bool saved = true; private bool completion_shown = false; - private bool ignore_external_changes = false; + private bool inhibit_autosave = false; private Gtk.ScrolledWindow scroll; private Gtk.InfoBar info_bar; @@ -184,7 +184,7 @@ namespace Scratch.Services { // Focus out event for SourceView this.source_view.focus_out_event.connect (() => { - if (Scratch.settings.get_boolean ("autosave")) { + if (Scratch.settings.get_boolean ("autosave") && !inhibit_autosave) { save.begin (); } @@ -228,7 +228,7 @@ namespace Scratch.Services { onchange_handler_id = source_view.buffer.changed.connect (() => { check_undoable_actions (); // Save if autosave is ON - if (Scratch.settings.get_boolean ("autosave")) { + if (Scratch.settings.get_boolean ("autosave") && !inhibit_autosave) { if (timeout_saving > 0) { Source.remove (timeout_saving); timeout_saving = 0; @@ -252,7 +252,7 @@ namespace Scratch.Services { /* 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. */ loaded = false; - ignore_external_changes = false; + inhibit_autosave = false; if (load_cancellable != null) { /* just in case */ load_cancellable.cancel (); @@ -515,6 +515,11 @@ namespace Scratch.Services { this.set_saved_status (true); last_save_content = source_view.buffer.text; + // If saving in response to external changes hide the infobar now. + if (inhibit_autosave) { + inhibit_autosave = false; + hide_info_bar (); + } debug ("File \"%s\" saved successfully", get_basename ()); @@ -813,10 +818,7 @@ namespace Scratch.Services { // Only done when no unsaved internal changes else difference from saved // file are to be expected. If user selects to continue regardless then no further // check made for this document - external changes will be overwritten on next (auto) save - if (loaded && - !source_view.buffer.get_modified () && - !ignore_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) => { @@ -828,30 +830,37 @@ namespace Scratch.Services { return; } - if (source_view.buffer.text == new_buffer.text) { + if (last_save_content == new_buffer.text) { return; } string message; - if (Scratch.settings.get_boolean ("autosave")) { - message = _( - "File \"%s\" was modified by an external application. Do you want to reload the document? \nOtherwise, if you continue, the external changes will be overwritten by your next edit and any further external changes will be ignored." - ).printf ("%s".printf (get_basename ())); + if (source_view.buffer.get_modified ()) { + message = _( + "File \"%s\" was modified by an external application. \nThere are also unsaved changes. \nReload the document and lose the unsaved changes? \nOtherwise, overwrite the external changes or save with a different name." + ).printf ("%s".printf (get_basename ())); } else { - message = _( - "File \"%s\" was modified by an external application. Do you want to reload the document? \nOtherwise, if you continue, the external changes will be overwritten by your next save and any further external changes will be ignored." - ).printf ("%s".printf (get_basename ())); + message = _( + "File \"%s\" was modified by an external application. \nReload the document? \nOtherwise, overwrite the external changes or save with a different name." + ).printf ("%s".printf (get_basename ())); } - set_message (Gtk.MessageType.WARNING, message, _("Reload"), () => { - // this.source_view.set_text (new_buffer.text, false); - // set_modified (false); - hide_info_bar (); - this.open.begin (true); - }, _("Continue"), () => { - hide_info_bar (); - ignore_external_changes = true; - }); + inhibit_autosave = true; + set_message ( + Gtk.MessageType.WARNING, + message, + _("Reload"), () => { + source_view.buffer.text = new_buffer.text; + source_view.buffer.set_modified (false); + last_save_content = source_view.buffer.text; + set_saved_status (true); + inhibit_autosave = false; + hide_info_bar (); + }, + _("Overwrite"), () => { + save_with_hold.begin (true, false); + } + ); }); } } From a7f731022f2407d9e5158e3c564a7d0c2c68f8cc Mon Sep 17 00:00:00 2001 From: Jeremy Wootten Date: Mon, 17 Apr 2023 10:21:59 +0100 Subject: [PATCH 3/7] Check file status on save request --- src/MainWindow.vala | 2 +- src/Services/Document.vala | 7 +++++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/src/MainWindow.vala b/src/MainWindow.vala index 57ded41e28..a74d13c3f6 100644 --- a/src/MainWindow.vala +++ b/src/MainWindow.vala @@ -896,7 +896,7 @@ namespace Scratch { if (doc.is_file_temporary == true) { action_save_as (); } else { - doc.save_with_hold.begin (true); + doc.save_request (); } } } diff --git a/src/Services/Document.vala b/src/Services/Document.vala index a35cbe12fa..591f9dbb42 100644 --- a/src/Services/Document.vala +++ b/src/Services/Document.vala @@ -439,6 +439,13 @@ namespace Scratch.Services { return ret_value; } + // Handle save action (only use for user interaction) + public void save_request () { + check_undoable_actions (); + check_file_status (); // Need to check for external changes before forcing save + save_with_hold.begin (true); + } + 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 From 540d576129588568848dd95a82742696c58c9b73 Mon Sep 17 00:00:00 2001 From: Jeremy Wootten Date: Mon, 17 Apr 2023 10:22:34 +0100 Subject: [PATCH 4/7] Check status on autosave --- src/Services/Document.vala | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Services/Document.vala b/src/Services/Document.vala index 591f9dbb42..1cab5866dd 100644 --- a/src/Services/Document.vala +++ b/src/Services/Document.vala @@ -234,7 +234,8 @@ namespace Scratch.Services { timeout_saving = 0; } timeout_saving = Timeout.add (1000, () => { - save.begin (); + check_file_status (); + save.begin (); // Not forced timeout_saving = 0; return false; }); From 79bbcee275aca36131f074aec4e7a05c75a2ad5c Mon Sep 17 00:00:00 2001 From: Jeremy Wootten Date: Mon, 17 Apr 2023 10:23:16 +0100 Subject: [PATCH 5/7] Do not check for external changes while is_saving true --- 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 1cab5866dd..337c33b6c2 100644 --- a/src/Services/Document.vala +++ b/src/Services/Document.vala @@ -850,7 +850,7 @@ namespace Scratch.Services { // Only done when no unsaved internal changes else difference from saved // file are to be expected. If user selects to continue regardless then no further // check made for this document - external changes will be overwritten on next (auto) save - if (loaded) { + if (loaded && !is_saving) { 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) => { From 5b5014b66304252cd43e722f2d1447c7e01a0846 Mon Sep 17 00:00:00 2001 From: Jeremy Wootten Date: Mon, 17 Apr 2023 10:39:36 +0100 Subject: [PATCH 6/7] Block focus actions when inhibit_autosave true --- src/Services/Document.vala | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/Services/Document.vala b/src/Services/Document.vala index 337c33b6c2..9ca8be5567 100644 --- a/src/Services/Document.vala +++ b/src/Services/Document.vala @@ -194,7 +194,7 @@ namespace Scratch.Services { source_view.buffer.changed.connect (() => { if (source_view.buffer.text != last_save_content) { saved = false; - if (!Scratch.settings.get_boolean ("autosave")) { + if (inhibit_autosave || !Scratch.settings.get_boolean ("autosave")) { set_saved_status (false); } } else { @@ -347,8 +347,10 @@ namespace Scratch.Services { // Focus in event for SourceView this.source_view.focus_in_event.connect (() => { - check_file_status (); - check_undoable_actions (); + if (!inhibit_autosave) { + check_file_status (); + check_undoable_actions (); + } return false; }); From 3b8b758bd349250ba3747c941fa2114393c0f665 Mon Sep 17 00:00:00 2001 From: Jeremy Wootten Date: Mon, 17 Apr 2023 11:04:07 +0100 Subject: [PATCH 7/7] Connect focus in for new document --- src/Services/Document.vala | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/Services/Document.vala b/src/Services/Document.vala index 9ca8be5567..6f4651996b 100644 --- a/src/Services/Document.vala +++ b/src/Services/Document.vala @@ -191,6 +191,16 @@ namespace Scratch.Services { return false; }); + // Focus in event for SourceView + this.source_view.focus_in_event.connect (() => { + if (!inhibit_autosave && !is_file_temporary) { + check_file_status (); + check_undoable_actions (); + } + + return false; + }); + source_view.buffer.changed.connect (() => { if (source_view.buffer.text != last_save_content) { saved = false; @@ -345,16 +355,6 @@ namespace Scratch.Services { } } - // Focus in event for SourceView - this.source_view.focus_in_event.connect (() => { - if (!inhibit_autosave) { - check_file_status (); - check_undoable_actions (); - } - - return false; - }); - // Change syntax highlight this.source_view.change_syntax_highlight_from_file (this.file);