Merge lp:~tintou/scratch/scratch-backup-changes into lp:~elementary-apps/scratch/scratch

Proposed by Corentin Noël
Status: Needs review
Proposed branch: lp:~tintou/scratch/scratch-backup-changes
Merge into: lp:~elementary-apps/scratch/scratch
Diff against target: 628 lines (+206/-165)
4 files modified
plugins/outline/CMakeLists.txt (+9/-5)
src/MainWindow.vala (+1/-1)
src/Services/Document.vala (+195/-158)
src/Services/FileHandler.vala (+1/-1)
To merge this branch: bzr merge lp:~tintou/scratch/scratch-backup-changes
Reviewer Review Type Date Requested Status
Zisu Andrei (community) Needs Information
xapantu (community) Needs Fixing
Review via email: mp+271337@code.launchpad.net

Description of the change

The restoration point isn't kept in memory but in the backup file.
Don't check for file existence at focus but creates a FileMonitor to have every events on real-time.

With this the file loading process is much faster.

To post a comment you must log in.
Revision history for this message
xapantu (xapantu) wrote :
Download full text (4.8 KiB)

Some in-line comments, maybe more to come.

Here is a crash, after using the "save as" button (maybe not related, I don't have a backtrace yet).

xapantu@ntu /t/s/build> src/scratch-text-editor
[INFO 02:22:03.881206] Application.vala:155: Scratch version: 2.2.1
[INFO 02:22:03.881260] Application.vala:157: Kernel version: 4.1.4-1-ARCH
[DEBUG 02:22:03.882757] Settings.vala:163: Loading settings from schema 'org.pantheon.scratch.saved-state'
[DEBUG 02:22:03.883261] Settings.vala:163: Loading settings from schema 'org.pantheon.scratch.settings'
[DEBUG 02:22:03.884352] Settings.vala:163: Loading settings from schema 'org.pantheon.scratch.services'
[DEBUG 02:22:03.959510] [Gtk] Connecting to session manager
[WARNING 02:22:03.965308] [Gtk] Attempting to add a widget with type GtkScrolledWindow to a GtkDialog, but as a GtkBin subclass a GtkDialog can only contain one widget at a time; it already contains a widget of type GtkBox
[WARNING 02:22:03.965550] [libpeas] Failed to enable unknown plugin loader 'gjs'
[DEBUG 02:22:03.991315] Settings.vala:163: Loading settings from schema 'org.pantheon.scratch.plugins.terminal'
[WARNING 02:22:04.011552] [libpeas] Failed to enable unknown plugin loader 'gjs'
[WARNING 02:22:04.045298] [GLib-GObject] The property GtkSettings:gtk-menu-images is deprecated and shouldn't be used anymore. It will be removed in a future version.
[FATAL 02:22:04.051353] [Gtk] gtk_header_bar_pack: assertion 'gtk_widget_get_parent (widget) == NULL' failed
[FATAL 02:22:04.157390] [Gtk] gtk_action_set_visible: assertion 'GTK_IS_ACTION (action)' failed
[DEBUG 02:22:04.157634] MainWindow.vala:673: open temporary file: Fichier texte à partir de 2015-09-24 01:28:31
[DEBUG 02:22:04.162284] sql-schema.vala:204: schema_version is 10
[INFO 02:22:04.206977] Document.vala:171: Opening "Nouveau document"
[DEBUG 02:22:04.312185] SplitView.vala:124: View added successfully
[WARNING 02:22:04.501706] [GLib-GObject] The property GtkCellRendererPixbuf:follow-state is deprecated and shouldn't be used anymore. It will be removed in a future version.
[DEBUG 02:22:04.502441] Settings.vala:163: Loading settings from schema 'org.pantheon.scratch.plugins.folder-manager'
[DEBUG 02:22:04.596172] sql-schema.vala:204: schema_version is 10
[INFO 02:22:04.606347] Document.vala:171: Opening "Nouveau document"
[WARNING 02:22:04.616528] DocumentView.vala:142: This Document was already opened! Not opening a duplicate!
[DEBUG 02:22:04.618693] sql-schema.vala:204: schema_version is 10
[INFO 02:22:04.625701] Document.vala:171: Opening "40_39.diff"
[FATAL 02:22:04.712490] [Gtk] gtk_text_view_get_editable: assertion 'GTK_IS_TEXT_VIEW (text_view)' failed
[FATAL 02:22:04.718433] [Gtk] gtk_text_view_get_editable: assertion 'GTK_IS_TEXT_VIEW (text_view)' failed
[FATAL 02:22:04.722147] [Gtk] gtk_text_view_get_editable: assertion 'GTK_IS_TEXT_VIEW (text_view)' failed
[FATAL 02:22:04.727046] [Gtk] gtk_text_view_get_editable: assertion 'GTK_IS_TEXT_VIEW (text_view)' failed
[FATAL 02:22:04.730144] [Gtk] gtk_text_view_get_editable: assertion 'GTK_IS_TEXT_VIEW (text_view)' failed
[FATAL 02:22:04.732916] [Gtk] gtk_text_view_get_editable: assertion 'GTK_IS_TEXT_VIEW (text_view)' failed
[FAT...

Read more...

review: Needs Fixing
1559. By Corentin Noël

Don't save the file while restoring it.

Revision history for this message
Corentin Noël (tintou) wrote :

Lucas: I fixed most inline comment you did, but most of the code is just copy/paste from older functions so it's not the scope of this branch to change all the behavior and strings :)

1560. By Corentin Noël

Fix save as.
Fixed Outline plugin cmake.

Revision history for this message
xapantu (xapantu) wrote :

Ok, nice, I will check that as soon as possible!

On 21/10/2015 22:31, Corentin Noël wrote:
> Lucas: I fixed most inline comment you did, but most of the code is just copy/paste from older functions so it's not the scope of this branch to change all the behavior and strings :)
>

Revision history for this message
Zisu Andrei (matzipan) wrote :

How do I test this?

review: Needs Information
Revision history for this message
Zisu Andrei (matzipan) wrote :

From tintou:

I think you have to open a document, and delete it, and see if scratch shows the infobar without even focusing it. Also see if the file~ is created and removed as it should be.

Unmerged revisions

1560. By Corentin Noël

Fix save as.
Fixed Outline plugin cmake.

1559. By Corentin Noël

Don't save the file while restoring it.

1558. By Corentin Noël

Fixed reverting sensitivity not being per-document.

1557. By Corentin Noël

More efficient document loading and changes handling.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'plugins/outline/CMakeLists.txt'
2--- plugins/outline/CMakeLists.txt 2015-03-19 14:49:48 +0000
3+++ plugins/outline/CMakeLists.txt 2015-10-21 20:31:41 +0000
4@@ -21,6 +21,11 @@
5 set(VALA_SHORTVER "${maj_ver}.${min_ver}" CACHE INTERNAL "")
6
7
8+pkg_check_modules (LIBVALA "libvala-${VALA_SHORTVER}")
9+
10+if (${LIBVALA_FOUND})
11+link_directories(${LIBVALA_LIBRARY_DIRS})
12+add_definitions(${LIBVALA_CFLAGS})
13
14 vala_precompile(VALA_C ${PLUGIN_NAME}
15 CtagsSymbolResolver.vala
16@@ -49,15 +54,14 @@
17 include (GResource)
18 glib_compile_resources (GLIB_RESOURCES_OUTLINE SOURCE icons/outline.gresource.xml)
19
20-pkg_check_modules(OUTLINE_DEPS libvala-${VALA_SHORTVER})
21-link_directories(${OUTLINE_DEPS_LIBRARY_DRIS})
22-add_definitions(${OUTLINE_DEPS_CFLAGS})
23-
24 add_library(${PLUGIN_NAME} MODULE ${VALA_C} ${GLIB_RESOURCES_OUTLINE})
25 add_dependencies(${PLUGIN_NAME} ${LIBNAME} scratch)
26-target_link_libraries(${PLUGIN_NAME} ${NORMAL_LIBRARIES} ${OUTLINE_DEPS_LIBRARIES})
27+target_link_libraries(${PLUGIN_NAME} ${NORMAL_LIBRARIES} ${LIBVALA_LIBRARIES})
28
29 install(TARGETS ${PLUGIN_NAME} DESTINATION ${PLUGINDIR}/${PLUGIN_NAME})
30 install(FILES ${PLUGIN_NAME}.plugin DESTINATION ${PLUGINDIR}/${PLUGIN_NAME})
31
32 message("-- Outline plugin will be compiled")
33+else()
34+message("-- Outline plugin will NOT be compiled")
35+endif()
36
37=== modified file 'src/MainWindow.vala'
38--- src/MainWindow.vala 2015-10-01 10:42:31 +0000
39+++ src/MainWindow.vala 2015-10-21 20:31:41 +0000
40@@ -322,7 +322,7 @@
41 main_actions.get_action ("SaveFileAs").sensitive = val;
42 main_actions.get_action ("Undo").sensitive = val;
43 main_actions.get_action ("Redo").sensitive = val;
44- main_actions.get_action ("Revert").sensitive = val;
45+ main_actions.get_action ("Revert").sensitive = val && main_actions.get_action ("Revert").sensitive;
46 this.toolbar.share_app_menu.sensitive = val;
47
48 // Zoom button
49
50=== modified file 'src/Services/Document.vala'
51--- src/Services/Document.vala 2015-09-16 01:11:55 +0000
52+++ src/Services/Document.vala 2015-10-21 20:31:41 +0000
53@@ -20,7 +20,6 @@
54 ***/
55
56 namespace Scratch.Services {
57-
58 public enum DocumentStates {
59 NORMAL,
60 READONLY
61@@ -45,22 +44,38 @@
62 public signal void doc_saved ();
63 public signal void doc_closed ();
64
65+ public bool can_revert = false;
66+
67 // Widgets
68 public Scratch.Widgets.SourceView source_view;
69 private Gtk.InfoBar info_bar;
70
71 // Objects
72 private Gtk.SourceFile source_file;
73+ private FileMonitor file_monitor = null;
74+ public File backup_file;
75 public File file {
76 get { return source_file.location; }
77 set {
78 source_file.set_location (value);
79- file_changed ();
80+ backup_file = File.new_for_path ("%s~".printf (value.get_path ()));
81+ attribute_changed ();
82+ if (file_monitor != null) {
83+ file_monitor.changed.disconnect (monitor_changed);
84+ file_monitor.cancel ();
85+ }
86+
87+ try {
88+ file_monitor = value.monitor_file (FileMonitorFlags.WATCH_MOUNTS);
89+ file_monitor.changed.connect (monitor_changed);
90+ } catch (Error e) {
91+ debug (e.message);
92+ }
93 }
94 }
95
96- public string original_content;
97 public bool saved = true;
98+ private bool ignore_next = false;
99 private bool error_shown = false;
100 public bool is_file_temporary {
101 get {
102@@ -84,7 +99,7 @@
103
104 // Mount state of the file
105 private bool mounted = true;
106- private Mount mount;
107+ private bool read_only = false;
108
109 public Document (Gtk.ActionGroup actions, File? file = null) {
110 this.main_actions = actions;
111@@ -123,14 +138,15 @@
112 Source.remove (timeout_saving);
113 timeout_saving = 0;
114 }
115+
116 timeout_saving = Timeout.add (1000, () => {
117 save.begin ();
118 timeout_saving = 0;
119 return false;
120 });
121- }
122- else
123+ } else {
124 this.set_saved_status (false);
125+ }
126 });
127 });
128 } else if (onchange_handler_id != 0) {
129@@ -159,9 +175,7 @@
130 // Focus in event for SourceView
131 this.source_view.focus_in_event.connect (() => {
132 main_actions.get_action ("SaveFile").visible = !(settings.autosave);
133- check_file_status ();
134 check_undoable_actions ();
135-
136 return false;
137 });
138
139@@ -197,9 +211,10 @@
140 return false;
141 }
142
143+ can_revert = false;
144 source_view.buffer.set_modified (false);
145- original_content = source_view.buffer.text;
146 loaded = true;
147+ check_undoable_actions ();
148
149 doc_opened ();
150
151@@ -286,6 +301,7 @@
152 save_cancellable = new GLib.Cancellable ();
153 var source_file_saver = new Gtk.SourceFileSaver (source_view.buffer, source_file);
154 try {
155+ ignore_next = true;
156 yield source_file_saver.save_async (GLib.Priority.DEFAULT, save_cancellable, null);
157 } catch (Error e) {
158 // We don't need to send an error message at cancellation (corresponding to error code 19)
159@@ -299,9 +315,10 @@
160 // Zeitgeist integration
161 zg_log.save_insert (file.get_uri (), get_mime_type ());
162 #endif
163-
164 doc_saved ();
165+ can_revert = true;
166 this.set_saved_status (true);
167+ check_undoable_actions ();
168
169 message ("File \"%s\" saved succesfully", get_basename ());
170
171@@ -316,12 +333,18 @@
172 bool is_current_file_temporary = this.is_file_temporary;
173
174 if (filech.run () == Gtk.ResponseType.ACCEPT) {
175- this.file = File.new_for_uri (filech.get_file ().get_uri ());
176+ var dest = File.new_for_uri (filech.get_file ().get_uri ());
177+ try {
178+ file.copy (dest, GLib.FileCopyFlags.OVERWRITE);
179+ } catch (Error e) {
180+ critical (e.message);
181+ return false;
182+ }
183+ file = dest;
184 // Update last visited path
185 Utils.last_path = Path.get_dirname (filech.get_file ().get_uri ());
186 filech.destroy ();
187- }
188- else {
189+ } else {
190 filech.destroy ();
191 return false;
192 }
193@@ -338,7 +361,7 @@
194 }
195
196 // Delete backup file
197- delete_backup (current_file + "~");
198+ delete_backup ();
199
200 // Change syntax highlight
201 this.source_view.change_syntax_highlight_from_file (this.file);
202@@ -401,10 +424,11 @@
203
204 // Get file name
205 public string get_basename () {
206- if (is_file_temporary)
207+ if (is_file_temporary) {
208 return _("New Document");
209- else
210+ } else {
211 return file.get_basename ();
212+ }
213 }
214
215 // Set InfoBars message
216@@ -421,6 +445,7 @@
217 if (w != null)
218 w.destroy ();
219 });
220+
221 ((Gtk.Box)info_bar.get_action_area ()).get_children ().foreach ((w) => {
222 if (w != null)
223 w.destroy ();
224@@ -438,17 +463,21 @@
225 var main = info_bar.get_content_area () as Gtk.Box;
226 main.orientation = Gtk.Orientation.HORIZONTAL;
227 main.pack_start (l, false, false, 0);
228- if (button1 != null)
229+ if (button1 != null) {
230 info_bar.add_button (button1, 0);
231- if (button2 != null)
232+ }
233+
234+ if (button2 != null) {
235 info_bar.add_button (button2, 1);
236+ }
237
238 // Response
239 info_bar.response.connect ((id) => {
240- if (id == 0)
241+ if (id == 0) {
242 callback1 ();
243- else if (id == 1)
244+ } else if (id == 1) {
245 callback2 ();
246+ }
247 });
248
249 // Show everything
250@@ -476,7 +505,8 @@
251
252 // Revert
253 public void revert () {
254- this.source_view.set_text (original_content, false);
255+ restore_backup ();
256+ can_revert = false;
257 check_undoable_actions ();
258 }
259
260@@ -493,26 +523,28 @@
261 // Get language name
262 public string get_language_name () {
263 var lang = this.source_view.buffer.language;
264- if (lang != null)
265+ if (lang != null) {
266 return lang.name;
267- else
268+ } else {
269 return "";
270+ }
271 }
272
273 // Get language id
274 public string get_language_id () {
275 var lang = this.source_view.buffer.language;
276- if (lang != null)
277+ if (lang != null) {
278 return lang.id;
279- else
280+ } else {
281 return "";
282+ }
283 }
284
285 // Duplicate selected text
286 public void duplicate_selection () {
287 this.source_view.duplicate_selection ();
288 }
289-
290+
291 // Show an error dialog which says "Hey, I cannot read that file!"
292 private void show_error_dialog () {
293 if (this.error_shown)
294@@ -528,139 +560,76 @@
295 dialog.destroy ();
296 this.close ();
297 }
298-
299- // Check if the file was deleted/changed by an external source
300- public void check_file_status () {
301- // If the file does not exist anymore
302- if (!exists ()) {
303- if (mounted == false) {
304- string message = _("The location containing the file \"%s\" was unmounted. Do you want to save somewhere else?").printf ("<b>%s</b>".printf (get_basename ()));
305-
306- set_message (Gtk.MessageType.WARNING, message, _("Save As…"), () => {
307- this.save_as.begin ();
308- hide_info_bar ();
309- });
310- } else {
311- string message = _("File \"%s\" was deleted. Do you want to save it anyway?").printf ("<b>%s</b>".printf (get_basename ()));
312-
313- set_message (Gtk.MessageType.WARNING, message, _("Save"), () => {
314- this.save.begin ();
315- hide_info_bar ();
316- });
317- }
318- main_actions.get_action ("SaveFile").sensitive = false;
319- this.source_view.editable = false;
320- return;
321- }
322- // If the file can't be written
323- if (!can_write ()) {
324- string message = _("You cannot save changes on file \"%s\". Do you want to save the changes to this file in a different location?").printf ("<b>%s</b>".printf (get_basename ()));
325-
326- set_message (Gtk.MessageType.WARNING, message, _("Save changes elsewhere"), () => {
327- this.save_as.begin ();
328- hide_info_bar ();
329- });
330- main_actions.get_action ("SaveFile").sensitive = false;
331- this.source_view.editable = !settings.autosave;
332- }
333- else {
334- main_actions.get_action ("SaveFile").sensitive = true;
335- this.source_view.editable = true;
336- }
337- // Detect external changes
338- if (loaded) {
339- var new_buffer = new Gtk.SourceBuffer (null);
340- var source_file_loader = new Gtk.SourceFileLoader (new_buffer, source_file);
341- source_file_loader.load_async.begin (GLib.Priority.DEFAULT, null, null, (obj, res) => {
342- try {
343- source_file_loader.load_async.end (res);
344- } catch (Error e) {
345- critical (e.message);
346- show_error_dialog ();
347- return;
348- }
349-
350- if (source_view.buffer.text == new_buffer.text)
351- return;
352-
353- if (!source_view.buffer.get_modified ()) {
354- if (settings.autosave) {
355- source_view.set_text (new_buffer.text, false);
356- } else {
357- string message = _("File \"%s\" was modified by an external application. Do you want to load it again or continue your editing?").printf ("<b>%s</b>".printf (get_basename ()));
358- set_message (Gtk.MessageType.WARNING, message, _("Load"), () => {
359- this.source_view.set_text (new_buffer.text, false);
360- hide_info_bar ();
361- }, _("Continue"), () => {
362- hide_info_bar ();
363- });
364- }
365- }
366- });
367- }
368- }
369
370 // Set Undo/Redo action sensitive property
371 public void check_undoable_actions () {
372 main_actions.get_action ("Undo").sensitive = this.source_view.buffer.can_undo;
373 main_actions.get_action ("Redo").sensitive = this.source_view.buffer.can_redo;
374- main_actions.get_action ("Revert").sensitive = (original_content != source_view.buffer.text);
375+ main_actions.get_action ("Revert").sensitive = can_revert;
376 }
377
378 // Set saved status
379 public void set_saved_status (bool val) {
380 this.saved = val;
381-
382 string unsaved_identifier = "* ";
383-
384 if (!val) {
385- if (!(unsaved_identifier in this.label))
386+ if (!(unsaved_identifier in this.label)) {
387 this.label = unsaved_identifier + this.label;
388- }
389- else
390+ }
391+ } else {
392 this.label = this.label.replace (unsaved_identifier, "");
393+ }
394 }
395
396 // Backup functions
397 private void create_backup () {
398- if (!can_write ())
399+ if (read_only) {
400 return;
401-
402- var backup = File.new_for_path (this.file.get_path () + "~");
403-
404- if (!backup.query_exists ()) {
405+ }
406+
407+ if (!backup_file.query_exists ()) {
408 try {
409- file.copy (backup, FileCopyFlags.NONE);
410+ file.copy (backup_file, FileCopyFlags.NONE);
411 } catch (Error e) {
412 warning ("Cannot create backup copy for file \"%s\": %s", get_basename (), e.message);
413 }
414 }
415 }
416
417- private void delete_backup (string? backup_path = null) {
418-
419- string backup_file = "";
420-
421- if (backup_path == null)
422- backup_file = file.get_path () + "~";
423- else
424- backup_file = backup_path;
425-
426- debug ("Backup file deleting: %s", backup_file);
427-
428- var backup = File.new_for_path (backup_file);
429- if (backup == null || !backup.query_exists ()) {
430- debug ("Backup file doesn't exists: %s", backup.get_path ());
431+ private void delete_backup () {
432+ debug ("Backup file deleting: %s", backup_file.get_path ());
433+ if (backup_file == null || !backup_file.query_exists ()) {
434+ debug ("Backup file doesn't exists: %s", backup_file.get_path ());
435 return;
436 }
437+
438 try {
439- backup.delete ();
440- debug ("Backup file deleted: %s", backup_file);
441+ backup_file.delete ();
442+ debug ("Backup file deleted: %s", backup_file.get_path ());
443 } catch (Error e) {
444 warning ("Cannot delete backup for file \"%s\": %s", get_basename (), e.message);
445 }
446 }
447
448+ private void restore_backup () {
449+ var backup_source = new Gtk.SourceFile ();
450+ backup_source.set_location (backup_file);
451+ var new_buffer = new Gtk.SourceBuffer (null);
452+ var source_file_loader = new Gtk.SourceFileLoader (new_buffer, backup_source);
453+ loaded = false;
454+ source_file_loader.load_async.begin (GLib.Priority.DEFAULT, null, null, (obj, res) => {
455+ try {
456+ source_file_loader.load_async.end (res);
457+ source_view.buffer.text = new_buffer.text;
458+ loaded = true;
459+ } catch (Error e) {
460+ critical (e.message);
461+ show_error_dialog ();
462+ return;
463+ }
464+ });
465+ }
466+
467 private bool delete_temporary_file (bool force = false) {
468 if (!is_file_temporary || (get_text ().length > 0 && !force))
469 return false;
470@@ -674,46 +643,114 @@
471 }
472
473 // Return true if the file is writable
474- public bool can_write () {
475- FileInfo info;
476-
477- bool writable = false;
478-
479- try {
480- info = this.file.query_info (FileAttribute.ACCESS_CAN_WRITE, FileQueryInfoFlags.NONE, null);
481- writable = info.get_attribute_boolean (FileAttribute.ACCESS_CAN_WRITE);
482- return writable;
483- } catch (Error e) {
484- warning ("query_info failed, but filename appears to be correct, allowing as new file");
485- writable = true;
486- return writable;
487- }
488- }
489
490 // Return true if the file exists
491 public bool exists () {
492 return this.file.query_exists ();
493 }
494
495- private void file_changed () {
496- if (mount != null) {
497- mount.unmounted.disconnect (unmounted_cb);
498- mount = null;
499- }
500-
501- try {
502- mount = file.find_enclosing_mount ();
503- mount.unmounted.connect (unmounted_cb);
504- } catch (Error e) {
505- debug ("Could not find mount location");
506- return;
507- }
508- mounted = true;
509- }
510-
511- private void unmounted_cb () {
512- warning ("Folder containing the file was unmounted");
513+ private void monitor_changed (File file, File? other_file, FileMonitorEvent event_type) {
514+ switch (event_type) {
515+ case FileMonitorEvent.CHANGED:
516+ attribute_changed ();
517+ break;
518+ case FileMonitorEvent.DELETED:
519+ deleted ();
520+ break;
521+ case FileMonitorEvent.CREATED:
522+ if (ignore_next == false) {
523+ changed_external ();
524+ }
525+
526+ ignore_next = false;
527+ break;
528+ case FileMonitorEvent.UNMOUNTED:
529+ unmounted ();
530+ break;
531+ case FileMonitorEvent.ATTRIBUTE_CHANGED:
532+ attribute_changed ();
533+ break;
534+ default:
535+ break;
536+ }
537+ }
538+
539+ private void changed_external () {
540+ var new_buffer = new Gtk.SourceBuffer (null);
541+ var source_file_loader = new Gtk.SourceFileLoader (new_buffer, source_file);
542+ source_file_loader.load_async.begin (GLib.Priority.DEFAULT, null, null, (obj, res) => {
543+ try {
544+ source_file_loader.load_async.end (res);
545+ } catch (Error e) {
546+ critical (e.message);
547+ show_error_dialog ();
548+ return;
549+ }
550+
551+ if (source_view.buffer.text == new_buffer.text)
552+ return;
553+
554+ if (!source_view.buffer.get_modified ()) {
555+ if (settings.autosave) {
556+ source_view.set_text (new_buffer.text, false);
557+ attribute_changed ();
558+ } else {
559+ string message = _("File \"%s\" was modified by an external application. Do you want to load it again or continue your editing?").printf ("<b>%s</b>".printf (get_basename ()));
560+ set_message (Gtk.MessageType.WARNING, message, _("Load"), () => {
561+ this.source_view.set_text (new_buffer.text, false);
562+ attribute_changed ();
563+ hide_info_bar ();
564+ }, _("Continue"), () => {
565+ hide_info_bar ();
566+ });
567+ }
568+ }
569+ });
570+ }
571+
572+ private void deleted () {
573+ string message = _("File \"%s\" was deleted. Do you want recreate it?").printf ("<b>%s</b>".printf (get_basename ()));
574+
575+ set_message (Gtk.MessageType.WARNING, message, _("Save"), () => {
576+ this.save.begin ();
577+ hide_info_bar ();
578+ });
579+ }
580+
581+ private void unmounted () {
582 mounted = false;
583+ main_actions.get_action ("SaveFile").sensitive = false;
584+ source_view.editable = false;
585+ string message = _("The location containing the file \"%s\" was unmounted. Do you want to save somewhere else?").printf ("<b>%s</b>".printf (get_basename ()));
586+
587+ set_message (Gtk.MessageType.WARNING, message, _("Save As…"), () => {
588+ this.save_as.begin ();
589+ hide_info_bar ();
590+ });
591+ }
592+
593+ public void attribute_changed () {
594+ FileInfo info;
595+ try {
596+ info = file.query_info (FileAttribute.ACCESS_CAN_WRITE, FileQueryInfoFlags.NONE, null);
597+ read_only = !info.get_attribute_boolean (FileAttribute.ACCESS_CAN_WRITE);
598+ if (read_only) {
599+ string message = _("You cannot save changes on file \"%s\". Do you want to save the changes to this file in a different location?").printf ("<b>%s</b>".printf (get_basename ()));
600+
601+ set_message (Gtk.MessageType.WARNING, message, _("Save changes elsewhere"), () => {
602+ this.save_as.begin ();
603+ hide_info_bar ();
604+ });
605+ main_actions.get_action ("SaveFile").sensitive = false;
606+ this.source_view.editable = !settings.autosave;
607+ } else {
608+ main_actions.get_action ("SaveFile").sensitive = true;
609+ this.source_view.editable = true;
610+ }
611+ } catch (Error e) {
612+ warning ("query_info failed, but filename appears to be correct, allowing as new file");
613+ read_only = false;
614+ }
615 }
616 }
617 }
618
619=== modified file 'src/Services/FileHandler.vala'
620--- src/Services/FileHandler.vala 2015-03-19 21:34:20 +0000
621+++ src/Services/FileHandler.vala 2015-10-21 20:31:41 +0000
622@@ -130,4 +130,4 @@
623
624 }
625
626-}
627\ No newline at end of file
628+}

Subscribers

People subscribed via source and target branches