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 c6069d9900..6f4651996b 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 inhibit_autosave = false;
private Gtk.ScrolledWindow scroll;
private Gtk.InfoBar info_bar;
@@ -183,17 +184,27 @@ 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 ();
}
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;
- if (!Scratch.settings.get_boolean ("autosave")) {
+ if (inhibit_autosave || !Scratch.settings.get_boolean ("autosave")) {
set_saved_status (false);
}
} else {
@@ -227,13 +238,14 @@ 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;
}
timeout_saving = Timeout.add (1000, () => {
- save.begin ();
+ check_file_status ();
+ save.begin (); // Not forced
timeout_saving = 0;
return false;
});
@@ -251,6 +263,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;
+ inhibit_autosave = false;
+
if (load_cancellable != null) { /* just in case */
load_cancellable.cancel ();
}
@@ -341,14 +355,6 @@ namespace Scratch.Services {
}
}
- // Focus in event for SourceView
- this.source_view.focus_in_event.connect (() => {
- check_file_status ();
- check_undoable_actions ();
-
- return false;
- });
-
// Change syntax highlight
this.source_view.change_syntax_highlight_from_file (this.file);
@@ -436,6 +442,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
@@ -510,6 +523,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 ());
@@ -555,9 +573,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
@@ -830,8 +848,11 @@ 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 && !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) => {
@@ -843,26 +864,37 @@ namespace Scratch.Services {
return;
}
- if (source_view.buffer.text == new_buffer.text) {
+ if (last_save_content == new_buffer.text) {
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?"
+ string message;
+ 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. \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, _("Load"), () => {
- this.source_view.set_text (new_buffer.text, false);
- hide_info_bar ();
- }, _("Continue"), () => {
- hide_info_bar ();
- });
+ 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);
}
- }
+ );
});
}
}