Clone in a terminal:
Commit d2eae9c
Johan Mattsson - 2019-07-13T20:51:40+00:00
d2eae9c41ad2afcf3edbcf5550f902a332a06571johan.mattsson.m@gmail.com

Create a backup every time a font is saved

Changed files (16)

Diff

diff --git a/birdfont/GtkWindow.vala b/birdfont/GtkWindow.valaindex 1cf8fb4..ffeb03c 100644--- a/birdfont/GtkWindow.vala+++ b/birdfont/GtkWindow.vala@@ -531,11 +531,6 @@ public class GtkWindow : Gtk.Window, NativeWindow { 	} 	 	public void set_cursor (int visible) {-		if (visible != NativeWindow.VISIBLE) {-			get_window ().set_cursor (new Cursor (CursorType.BLANK_CURSOR));-		} else {-			get_window ().set_cursor (new Cursor (CursorType.ARROW));-		} 	} 	 	public double get_screen_scale () {@@ -583,7 +578,7 @@ class TabbarCanvas : DrawingArea { 			Gtk.Allocation alloc; 			Context cr;						 									-			cr = cairo_create (get_window ());+			cr = cairo_create ((!) get_window ()); 			get_allocation (out alloc); 						 			tabbar.draw (cr, alloc.width, alloc.height);@@ -647,7 +642,7 @@ class ToolboxCanvas : DrawingArea { 			Gtk.Allocation allocation; 			get_allocation (out allocation); 			-			Context cw = cairo_create(get_window());+			Context cw = cairo_create((!) get_window()); 			Toolbox.allocation_width = allocation.width; 			Toolbox.allocation_height = allocation.height; 			tb.draw (allocation.width, allocation.height, cw);@@ -712,7 +707,7 @@ public class GlyphCanvasArea : DrawingArea  { 			alloc.x = allocation.x; 			alloc.y = allocation.y; 			-			Context cw = cairo_create (get_window());+			Context cw = cairo_create ((!) get_window()); 			 			Surface s = new Surface.similar (cw.get_target (), Cairo.Content.COLOR_ALPHA, alloc.width, alloc.height); 			Context c = new Context (s); diff --git a/libbirdfont/BackupDir.vala b/libbirdfont/BackupDir.valanew file mode 100644index 0000000..08e85b5--- /dev/null+++ b/libbirdfont/BackupDir.vala@@ -0,0 +1,30 @@+/*+	Copyright (C) 2019 Johan Mattsson+	+	This library is free software; you can redistribute it and/or modify +	it under the terms of the GNU Lesser General Public License as +	published by the Free Software Foundation; either version 3 of the +	License, or (at your option) any later version.++	This library is distributed in the hope that it will be useful, but +	WITHOUT ANY WARRANTY; without even the implied warranty of +	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +	Lesser General Public License for more details.+*/++using Cairo;+using Math;++namespace BirdFont {++public class BackupDir : GLib.Object {+	public string folder_name;+	public string modification_time;+	+	public BackupDir (string folder_name, string modification_time) {+		this.folder_name = folder_name;+		this.modification_time = modification_time;+	}+}++}diff --git a/libbirdfont/BackupTab.vala b/libbirdfont/BackupTab.valanew file mode 100644index 0000000..97ca84c--- /dev/null+++ b/libbirdfont/BackupTab.vala@@ -0,0 +1,186 @@+/*+	Copyright (C) 2019 Johan Mattsson++	This library is free software; you can redistribute it and/or modify +	it under the terms of the GNU Lesser General Public License as +	published by the Free Software Foundation; either version 3 of the +	License, or (at your option) any later version.++	This library is distributed in the hope that it will be useful, but +	WITHOUT ANY WARRANTY; without even the implied warranty of +	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +	Lesser General Public License for more details.+*/++using Cairo;+using Math;++namespace BirdFont {++public class BackupTab : Table {+	Gee.ArrayList<Row> rows = new Gee.ArrayList<Row> ();+	+	const int FONT_FOLDER = -2;+	const int FONT_FILE = -1;+	+	private BackupDir? backup_folder = null;+	+	public BackupTab () {+	}++	public override Gee.ArrayList<Row> get_rows () {+		return rows;+	}++	public override void selected_row (Row row, int column, bool delete_button) {	+		if (row.get_index () == FONT_FOLDER) {+			return_if_fail (row.get_row_data () is BackupDir);+			backup_folder = (BackupDir) row.get_row_data ();+			MainWindow.scrollbar.set_size (0);+			update_rows ();+		} else if (row.get_index () == FONT_FILE) {+			return_if_fail (row.get_row_data () is String);+			String backup_file = (String) row.get_row_data ();+			RecentFiles.load_font (backup_file.c_str);+			MainWindow.scrollbar.set_size (0);+		}++		GlyphCanvas.redraw ();+	}++	public override void update_rows () {+		Row row;+				+		rows.clear ();++		if (backup_folder != null) {+			BackupDir folder = (!) backup_folder;+			Gee.ArrayList<string> files = Font.get_sorted_backups (folder.folder_name);++			if (files.size > 0) {+				row = new Row.headline (t_("Backups"));+				rows.add (row);	+			}+			+			if (files.size == 0) {+				row = new Row.headline (t_("No backups for this font."));+				rows.add (row);+			}+			+			foreach (string path in files) {+				string name = Font.get_file_from_full_path (path);+				row = new Row.columns_1 (name, FONT_FILE, false);+				String file_name = new String (path); +				row.set_row_data (file_name);+				rows.add (row);+			}+		} else {		+			Gee.ArrayList<BackupDir> backup_folders = get_backup_folders ();+			+			if (backup_folders.size == 0) {+				row = new Row.headline (t_("No backups found."));+				rows.add (row);+			}++			if (backup_folders.size > 0) {+				row = new Row.headline (t_("Backups"));+				rows.add (row);	+			}+			+			foreach (BackupDir backup_font in backup_folders) {+				row = new Row.columns_2 (backup_font.folder_name, backup_font.modification_time, FONT_FOLDER, false);+				row.set_row_data (backup_font);+				rows.add (row);+			}+		}+		+		GlyphCanvas.redraw ();+	}++	public override string get_label () {+		return t_("Backups");+	}++	public override string get_name () {+		return "Backups";+	}+	+	public string get_time_stamp_from_file_name (string file_name) {+		int dash = file_name.last_index_of ("-");+		+		if (file_name.has_suffix (".bf_backup") && dash > -1) {+			string time_stamp = file_name.substring (dash + "-".length, file_name.length - dash - ".bf_backup".length);+			time_stamp = time_stamp.replace ("_", " ");+			return time_stamp;+		}+		+		warning("Can't obtain timestamp from " + file_name);+		+		return "Unknown time.";+	}+	+	public Gee.ArrayList<BackupDir> get_backup_folders () {+		FileEnumerator enumerator;+		string folder_name;+		FileInfo? file_info;+		Gee.ArrayList<BackupDir> backup_folders = new Gee.ArrayList<BackupDir> ();+		File dir = Preferences.get_backup_directory ();+		+		try {+			printd ("Backup dir: ");+			printd ((!) dir.get_path ());+			printd ("\n");+				+			enumerator = dir.enumerate_children (FileAttribute.STANDARD_NAME, 0);+			while ((file_info = enumerator.next_file ()) != null) {+				FileInfo info = (!) file_info;+				folder_name = info.get_name ();+				string full_path = (!) get_child (dir, folder_name).get_path ();+				+				printd ("In backup dir: ");+				printd (full_path);+				printd ("\n");+				+				if (!FileUtils.test (full_path, FileTest.IS_DIR)) {+					warning (folder_name + " is not a backup directory.");+					continue;+				}+				+				if (!folder_name.has_suffix (".backup")) {+					warning (folder_name + " is not a backup directory, expecting the suffix .backup");+					continue;+				}+				+				folder_name = folder_name.substring (0, folder_name.length - ".backup".length);+				Gee.ArrayList<string> files = Font.get_sorted_backups (folder_name);+				+				if (files.size > 0) {+					string last_file = files.get (files.size - 1);+					string modification_time = get_time_stamp_from_file_name (last_file);+					BackupDir backup = new BackupDir (folder_name, modification_time);+					backup_folders.add (backup);+				}+			}+		} catch (Error e) {+			warning (e.message);+		}+	+		backup_folders.sort ((a, b) => {+			BackupDir first, next;++			first = (BackupDir) a;+			next = (BackupDir) b;+			+			return Posix.strcmp (b.modification_time, a.modification_time); // descending+		});+		+		return backup_folders;	+	}++	public override void draw (WidgetAllocation allocation, Context cr) {+		MainWindow.get_overview ().allocation = allocation;+		base.draw (allocation, cr);+	}+}++}diff --git a/libbirdfont/BirdFont.vala b/libbirdfont/BirdFont.valaindex c4cce11..c520246 100644--- a/libbirdfont/BirdFont.vala+++ b/libbirdfont/BirdFont.vala@@ -406,17 +406,6 @@ public class BirdFont { 		return settings; 	} -	internal static File get_backup_directory () {-		File settings = get_settings_directory ();-		File backup = get_child (settings, "backup");--		if (!backup.query_exists ()) {-			DirUtils.create ((!) backup.get_path (), 0755);-		}--		return backup;-	}- 	public static bool has_argument (string param) { 		if (is_null (args)) { 			return false;diff --git a/libbirdfont/Font.vala b/libbirdfont/Font.valaindex 43c5af2..83a7b47 100644--- a/libbirdfont/Font.vala+++ b/libbirdfont/Font.vala@@ -356,8 +356,8 @@ public class Font : GLib.Object { 		return sb.str; 	} -	public string get_file_name () {-		string p = get_path ();+	public static string get_file_from_full_path (string path) {+		string p = path; 		int i = p.last_index_of ("/"); 		 		if (i == -1) {@@ -365,10 +365,13 @@ public class Font : GLib.Object { 		} 		 		p = p.substring (i + 1);-		 		return p; 	} 	+	public string get_file_name () {+		return get_file_from_full_path (get_path ());+	}+	 	/** @return an absolute path to the font folder. */ 	public File get_folder () { 		string p = get_folder_path ();@@ -723,47 +726,6 @@ public class Font : GLib.Object { 		background_images.add (image); 	} 	-	/** Delete temporary rescue files. */-	public void delete_backup () {-		File dir = BirdFont.get_backup_directory ();-		File? new_file = null;-		File file;-		string backup_file;-		-		new_file = get_child (dir, @"$(name).birdfont");-		backup_file = (!) ((!) new_file).get_path ();-		-		try {-			file = File.new_for_path (backup_file);-			if (file.query_exists ()) {-				file.delete ();	-			}-		} catch (GLib.Error e) {-			stderr.printf (@"Failed to delete backup\n");-			warning (@"$(e.message) \n");-		}-	}-	-	/** Returns path to backup file. */-	public string save_backup () {-		File dir = BirdFont.get_backup_directory ();-		File? temp_file = null;-		string backup_file;-		BirdFontFile birdfont_file = new BirdFontFile (this);--		temp_file = get_child (dir, @"$(name).birdfont");-		backup_file = (!) ((!) temp_file).get_path ();-		backup_file = backup_file.replace (" ", "_");-		-		if (get_path () == backup_file) {-			warning ("Refusing to write backup of a backup.");-			return backup_file;-		}-		-		birdfont_file.write_font_file (backup_file, true);-		return backup_file;-	}-	 	public void init_bfp (string directory) { 		try { 			bfp_file = new BirdFontPart (this);@@ -794,12 +756,124 @@ public class Font : GLib.Object { 		settings.save (get_file_name ()); 	} 	-	public bool save_bfp () {+	private void save_backups () throws GLib.Error {+		string num_backups = Preferences.get ("num_backups");+		+		if (num_backups == "") {+			num_backups = "20";+		}+		+		int backups = int.parse (num_backups);+		+		if (backups == 0) {+			printd ("No backups according to settings. Skipping it.");+			delete_old_backups (backups);+			return;+		}+		+		if (backups > 0) {+			string path = (!) font_file;+			string bf_data = "";++			if (FileUtils.get_contents (path, out bf_data)) {+				DateTime now = new DateTime.now_local ();+				string time_stamp = now.to_string ();+				+				time_stamp = time_stamp.replace (":", "_");+				time_stamp = time_stamp.replace ("-", "_");+				+				string fn = get_file_name ();+				File backup_directory_for_font = Preferences.get_backup_directory_for_font (fn);+				+				if (!backup_directory_for_font.query_exists ()) {+					int error = DirUtils.create ((!) backup_directory_for_font.get_path (), 0766);+					+					if (error == -1) {+						stderr.printf (@"Failed to create backup directory: $((!) backup_directory_for_font.get_path ())\n");+					}+				}+				+				string file_name = get_file_name ();+				+				if (file_name.has_suffix (".bf")) {+					file_name = file_name.substring (0, file_name.length - ".bf".length);+				}+				+				if (file_name.has_suffix (".birdfont")) {+					file_name = file_name.substring (0, file_name.length - ".birdfont".length);+				}+				+				string backup_file_name = file_name + @"-$(time_stamp).bf_backup";+				File backup_file = get_child (backup_directory_for_font, backup_file_name);+				printd (@"Saving backup to: $((!) backup_file.get_path ())\n");+				+				FileUtils.set_contents ((!) backup_file.get_path (), bf_data);+			} 			+		}+		+		delete_old_backups (backups);+	}+	+	public static Gee.ArrayList<string> get_sorted_backups (string font_file_name) {+		Gee.ArrayList<string> backups = new Gee.ArrayList<string> ();++		try {+			File backup_directory_for_font = Preferences.get_backup_directory_for_font (font_file_name);+			Dir dir = Dir.open ((!) backup_directory_for_font.get_path (), 0);+			+			string? name = null;+			while ((name = dir.read_name ()) != null) {+				string file_name = (!) name;+				+				printd (@"backup_directory_for_font: $((!) backup_directory_for_font.get_path ())\n");+				printd (@"file_name $file_name\n");++				File backup_file = get_child (backup_directory_for_font, file_name);+				+				if (FileUtils.test ((!) backup_file.get_path (), FileTest.IS_REGULAR)+						&& file_name.has_suffix (".bf_backup")) {+					backups.add ((!) backup_file.get_path ());+				} else {+					warning (@"$file_name does not seem to be a backup file.");+				}+			}+		} catch (GLib.Error error) {+			warning (error.message);+			warning("Can't fetch backup files.");+		}+		+		backups.sort ();+		+		return backups;+	}+	+	public void delete_old_backups (int keep) {+		try {+			string file_name = get_file_name ();+			Gee.ArrayList<string> backups = get_sorted_backups (file_name);+			Gee.ArrayList<string> old_backups = new Gee.ArrayList<string> ();+			+			for (int i = 0; i < backups.size - keep; i++) {+				string b = backups.get (i);+				old_backups.add (b);+			}+			+			foreach (string path in old_backups) {+				printd (@"Deleting backup: $(path)\n");+				File file = File.new_for_path (path);+				file.delete ();+			}+		} catch (GLib.Error error) {+			warning (error.message);+			warning("Can't delet backup.");+		}		+	}+	+	private bool save_bfp () { 		return bfp_file.save (); 	} 	-	public void save_bf () {-		Font font;+	private void save_bf () { 		BirdFontFile birdfont_file = new BirdFontFile (this); 		string path; 		bool file_written;@@ -822,10 +896,11 @@ public class Font : GLib.Object { 			return; 		} 		-		if (file_written) {-			// delete the backup when the font is saved-			font = BirdFont.get_current_font ();-			font.delete_backup ();+		try {+			save_backups ();+		} catch (GLib.Error	 e) {+			warning (e.message);+			warning ("Can't save backup."); 		} 		 		modified = false;@@ -889,10 +964,15 @@ public class Font : GLib.Object { 		if (path.has_suffix (".bf") 			|| path.has_suffix (".BF") 			|| path.has_suffix (".BIRDFONT")-			|| path.has_suffix (".birdfont")) {+			|| path.has_suffix (".birdfont")+			|| path.has_suffix (".bf_backup")) { 			 			loaded = parse_bf_file (path); 			format = FontFormat.BIRDFONT;+			+			if (path.has_suffix (".bf_backup")) {+				font_file = null;+			} 		}  		if (path.has_suffix (".bfp") || path.has_suffix (".BFP")) {diff --git a/libbirdfont/ImportUtils.vala b/libbirdfont/ImportUtils.valaindex cf85337..dbe1abe 100644--- a/libbirdfont/ImportUtils.vala+++ b/libbirdfont/ImportUtils.vala@@ -75,8 +75,6 @@ public static int run_import (string[] arg) { 		} 	} -	font.save_backup ();- 	foreach (string f in svg_files) { 		svg = File.new_for_path (f); 		imported = import_svg_file (font, svg);@@ -88,7 +86,7 @@ public static int run_import (string[] arg) { 		} 	} 	-	font.save_bf ();+	font.save (); 	 	return 0; }diff --git a/libbirdfont/LoadCallback.vala b/libbirdfont/LoadCallback.valaindex 22b1e35..075f0f2 100644--- a/libbirdfont/LoadCallback.vala+++ b/libbirdfont/LoadCallback.vala@@ -87,8 +87,6 @@ public class LoadCallback : GLib.Object { 			Font f = BirdFont.get_current_font (); 			 			if (fn != null) {-				f.delete_backup ();-				 				f = BirdFont.new_font (); 				 				f.set_file ((!) fn);diff --git a/libbirdfont/MenuTab.vala b/libbirdfont/MenuTab.valaindex 2571312..55aa1cf 100644--- a/libbirdfont/MenuTab.vala+++ b/libbirdfont/MenuTab.vala@@ -217,6 +217,10 @@ public class MenuTab : FontDisplay { 		} 	} 	+	public static void clear_font_settings () {+		Toolbox.background_tools = new BackgroundTools (); // clear toolbox selection of images+	}+		 	public static void signal_file_exported () { 		IdleSource idle = new IdleSource (); 		idle.set_callback (() => {@@ -230,7 +234,7 @@ public class MenuTab : FontDisplay { 		}); 		idle.attach (null); 	}-	+ 	public static void signal_file_saved () { 		IdleSource idle = new IdleSource (); 		idle.set_callback (() => {diff --git a/libbirdfont/OtfFeatureTable.vala b/libbirdfont/OtfFeatureTable.valaindex 37cbc7a..9c1e8bb 100644--- a/libbirdfont/OtfFeatureTable.vala+++ b/libbirdfont/OtfFeatureTable.vala@@ -94,7 +94,7 @@ public class OtfFeatureTable : Table { 			o = (!) row.get_row_data (); 			return_if_fail (o is String); 			s = (String) o;-			add_new_alternate (s.data);+			add_new_alternate (s.c_str); 		} else if (row_index == ALTERNATE_ENTRY) { 			if (delete_button) { 				return_if_fail (row.has_row_data ());diff --git a/libbirdfont/Preferences.vala b/libbirdfont/Preferences.valaindex d4d5f37..d22e315 100644--- a/libbirdfont/Preferences.vala+++ b/libbirdfont/Preferences.vala@@ -60,6 +60,56 @@ public class Preferences { 		 		return files; 	}+	+	public static File get_backup_directory () {+		File config_directory = BirdFont.get_settings_directory ();+		File backup_directory = get_child (config_directory, "backup");+		+		if (!backup_directory.query_exists ()) {+			int error = DirUtils.create ((!) backup_directory.get_path (), 0766);+			+			if (error == -1) {+				warning (@"Failed to create backup directory: $((!) backup_directory.get_path ())\n");+			}+		}+		+		return backup_directory;+	}+	+	public static File get_backup_directory_for_font (string bf_file_name) {+		if (bf_file_name == "") {+			warning ("no filename.");+		}+		+		if (bf_file_name.index_of ("/") > -1) {+			warning ("Expecting a file and not a folder got: " + bf_file_name);+		}+		+		File backup_directory = get_backup_directory ();+		string subdir_name = bf_file_name;+			+		if (subdir_name.has_suffix (".bf")) {+			subdir_name = subdir_name.substring (0, subdir_name.length - ".bf".length);+		}+		+		if (subdir_name.has_suffix (".birdfont")) {+			subdir_name = subdir_name.substring (0, subdir_name.length - ".birdfont".length);+		}+		+		subdir_name += ".backup";+				+		File backup_subdir = get_child (backup_directory, subdir_name);+		+		if (!backup_subdir.query_exists ()) {+			int error = DirUtils.create ((!) backup_subdir.get_path (), 0766);+			+			if (error == -1) {+				warning (@"Failed to create backup directory: $((!) backup_subdir.get_path ())\n");+			}+		}++		return backup_subdir;+	}  	public static void add_recent_files (string file) { 		string escaped_string = file.replace ("\t", "\\t");diff --git a/libbirdfont/RecentFiles.vala b/libbirdfont/RecentFiles.valaindex b6e051c..860d5c6 100644--- a/libbirdfont/RecentFiles.vala+++ b/libbirdfont/RecentFiles.vala@@ -1,5 +1,5 @@ /*-	Copyright (C) 2015 Johan Mattsson+	Copyright (C) 2015 2019 Johan Mattsson  	This library is free software; you can redistribute it and/or modify  	it under the terms of the GNU Lesser General Public License as @@ -24,8 +24,7 @@ public class RecentFiles : Table { 	const int NEW_FONT = -5; 	const int CURRENT_FONT = -4; 	const int RECENT_FONT = -3;-	const int BACKUP = -2;-	+ 	public RecentFiles () { 	} @@ -34,21 +33,15 @@ public class RecentFiles : Table { 	}  	public override void selected_row (Row row, int column, bool delete_button) {	-		Font f;-		 		if (row.get_index () == NEW_FONT) { 			MenuTab.new_file (); 			MenuTab.select_overview (); 		} else if (row.get_index () == RECENT_FONT) { 			return_if_fail (row.get_row_data () is Font);-			f = (Font) row.get_row_data ();+			Font f = (Font) row.get_row_data (); 			MainWindow.scrollbar.set_size (0); 			GlyphCanvas.redraw (); 			load_font (f.get_path ());-		} else if (row.get_index () == BACKUP) {-			return_if_fail (row.get_row_data () is Font);-			f = (Font) row.get_row_data ();-			delete_backup (f.get_file_name ()); 		}  		GlyphCanvas.redraw ();@@ -57,7 +50,6 @@ public class RecentFiles : Table { 	public override void update_rows () { 		Row row; 		Gee.ArrayList<Font> recent_fonts = get_recent_font_files ();-		Gee.ArrayList<Font> backups = get_backups (); 		Font current_font = BirdFont.get_current_font (); 		 		rows.clear ();@@ -65,7 +57,7 @@ public class RecentFiles : Table { 		if (recent_fonts.size == 0) { 			row = new Row.headline (t_("No fonts created yet")); 			rows.add (row);-+			 			row = new Row.columns_1 (t_("Create a New Font"), NEW_FONT, false); 			rows.add (row);	 		}@@ -91,17 +83,6 @@ public class RecentFiles : Table { 			row.set_row_data (font); 			rows.add (row); 		}--		if (backups.size > 0) {			-			row = new Row.headline (t_("Backups"));-			rows.add (row);	-		}-		-		foreach (Font font in backups) {-			row = new Row.columns_1 (font.get_file_name (), BACKUP, true);-			row.set_row_data (font);-			rows.add (row);-		} 		 		GlyphCanvas.redraw (); 	}@@ -144,52 +125,6 @@ public class RecentFiles : Table { 		 		return fonts;	 	}--	public Gee.ArrayList<Font> get_backups () {-		FileEnumerator enumerator;-		string file_name;-		FileInfo? file_info;-		Gee.ArrayList<Font> backups = new Gee.ArrayList<Font> ();-		File dir = BirdFont.get_backup_directory ();-		Font font = BirdFont.get_current_font ();-		Font backup_font;--		try {-			enumerator = dir.enumerate_children (FileAttribute.STANDARD_NAME, 0);-			while ((file_info = enumerator.next_file ()) != null) {-				file_name = ((!) file_info).get_name ();-				-				// ignore old backup files-				if (file_name.has_prefix ("current_font_")) {-					continue;-				}-				-				backup_font = new Font ();-				backup_font.set_font_file ((!) get_child (dir, file_name).get_path ());-				backups.insert (0, backup_font);-			}-		} catch (Error e) {-			warning (e.message);-		}-	-		return backups;	-	}--	public void delete_backup (string file_name) {-		File backup_file;-		-		try {-			backup_file = BirdFont.get_backup_directory ();-			backup_file = get_child (backup_file, file_name);-			if (backup_file.query_exists ()) {-				backup_file.delete ();	-			}-		} catch (GLib.Error e) {-			warning (e.message);-		}-		-		selected_canvas ();-	} 	 	public override void draw (WidgetAllocation allocation, Context cr) { 		MainWindow.get_overview ().allocation = allocation;@@ -236,13 +171,17 @@ public class RecentFiles : Table { 			if (MenuTab.has_suppress_event ()) { 				return; 			}-			+ 			f = BirdFont.new_font ();-			+						 			MainWindow.close_all_tabs ();-			+			MenuTab.clear_font_settings ();+ 			f.set_file (fn);-			Preferences.add_recent_files (fn);++			if (!fn.has_suffix (".bf_backup")) {	+				Preferences.add_recent_files (fn);+			} 			 			MainWindow.native_window.load (); // background thread 		});diff --git a/libbirdfont/SaveCallback.vala b/libbirdfont/SaveCallback.valaindex 659cdda..b83badc 100644--- a/libbirdfont/SaveCallback.vala+++ b/libbirdfont/SaveCallback.vala@@ -92,7 +92,6 @@ public class SaveCallback : GLib.Object { 		if (f.is_bfp ()) { 			MainWindow.native_window.save (); 		} else {-			f.delete_backup (); 			fn = f.get_path (); 			 			if (f.font_file != nulldiff --git a/libbirdfont/SettingsTab.vala b/libbirdfont/SettingsTab.valaindex ede71cd..03266ec 100644--- a/libbirdfont/SettingsTab.vala+++ b/libbirdfont/SettingsTab.vala@@ -169,6 +169,32 @@ public class SettingsTab : SettingsDisplay { 		}); 		tools.add (new SettingsItem (themes, t_("Color theme"))); 		+		SpinButton num_backups = new SpinButton ("num_backups");+		tools.add (new SettingsItem (num_backups, t_("Number of backups per font")));+		+		num_backups.set_integers (true);+		+		num_backups.set_max (100);+		num_backups.set_min (0);+		num_backups.set_value ("20");++		if (Preferences.get ("num_backups") != "") {+			Preferences.set ("num_backups", num_backups.get_short_display_value ());+		}++		num_backups.new_value_action.connect ((self) => {+			Preferences.set ("num_backups", num_backups.get_short_display_value ());+		});+		+		Tool load_backups = new Tool ("load_backups");+		load_backups.select_action.connect((self) => {+			BackupTab backups = new BackupTab ();+			MainWindow.tabs.add_unique_tab (backups);+			MainWindow.tabs.select_tab_name ("Backups");+			load_backups.selected = false;+		});+		tools.add (new SettingsItem (load_backups, t_("Load a backup font")));+		 		tools.add (new SettingsItem.head_line (t_("Key Bindings"))); 		 		foreach (MenuItem menu_item in MainWindow.get_menu ().sorted_menu_items) {diff --git a/libbirdfont/SpinButton.vala b/libbirdfont/SpinButton.valaindex 2a3864b..859d99b 100644--- a/libbirdfont/SpinButton.vala+++ b/libbirdfont/SpinButton.vala@@ -37,6 +37,7 @@ public class SpinButton : Tool { 	int step = 1; 	 	bool big_number = false;+	bool integers = false; 	 	double last_active_time = 0; 	bool waiting_for_icon_switch = false;@@ -192,6 +193,11 @@ public class SpinButton : Tool { 		big_number = b; 	} 	+	public void set_integers (bool i) {+		integers = i;+		big_number = i;+	}+ 	public static string convert_to_string (double val) { 		SpinButton sb = new SpinButton (); 		sb.set_value_round (val);@@ -357,6 +363,11 @@ public class SpinButton : Tool { 			separator = v.substring (v.index_of_nth_char (3), 1); 			n3 = (int8) int.parse (v.substring (v.index_of_nth_char (4), 1)); 			n4 = (int8) int.parse (v.substring (v.index_of_nth_char (5), 1));+			+			if (integers) {+				n3 = 0;+				n4 = 0;+			} 		} 		 		if (separator != ".") {@@ -406,6 +417,18 @@ public class SpinButton : Tool { 	}  	public string get_short_display_value () {	+		if (integers) {+			if (n0 == 0 && n1 == 0) {+				return @"$n2";+			}+			+			if (n0 == 0) {+				return @"$n1$n2";+			}+			+			return @"$n0$n1$n2";+		}+			 		if (!big_number) { 			return @"$n0.$n1$n2$n3"; 		}@@ -436,6 +459,10 @@ public class SpinButton : Tool { 	public string get_display_value () { 		string v; 		+		if (integers) {+			return get_short_display_value ();+		}+		 		if (!big_number) { 			return @"$n0.$n1$n2$n3$n4"; 		}diff --git a/libbirdfont/String.vala b/libbirdfont/String.valaindex b90fa45..17a01b6 100644--- a/libbirdfont/String.vala+++ b/libbirdfont/String.vala@@ -16,10 +16,10 @@ namespace BirdFont {  /** Boxed string class. */ public class String : GLib.Object {-	public string data;+	public string c_str; 	 	public String (string data) {-		this.data = data;+		this.c_str = data; 	} } diff --git a/libbirdfont/Task.vala b/libbirdfont/Task.valaindex 6f63810..bc860f2 100644--- a/libbirdfont/Task.vala+++ b/libbirdfont/Task.vala@@ -1,5 +1,5 @@ /*-	Copyright (C) 2014 2015 Johan Mattsson+	Copyright (C) 2014 2015 2019 Johan Mattsson  	This library is free software; you can redistribute it and/or modify  	it under the terms of the GNU Lesser General Public License as @@ -17,10 +17,11 @@ namespace BirdFont { public class Task : GLib.Object { 	 	public delegate void Runnable ();+	public signal void done (); 	Runnable task; 	bool cancelled = false; 	bool cancelable = false;-+	 	public Task.empty () { 	} 		@@ -63,14 +64,14 @@ public class Task : GLib.Object { 	} 		 	public virtual void run () {-		if (task == null) {-			warning ("No task set.");-			return;-		}-		 		task (); 		-		warning ("Task is done.");+		IdleSource idle = new IdleSource ();+		idle.set_callback (() => {+			done ();+			return false;+		});+		idle.attach (null); 	}  	public void* perform_task() {

Contact

Email: johan.mattsson.m@gmail.com
Mastodon: typo.social/@birdfont
GitHub: johanmattssonm
LinkedIn: johan-mattsson-2ab324112