[f-spot/rubenv-gsoc-2009: 66/86] Add proper image deletion.



commit 8bfece78c4f64cadbddc3e47a4d7faf968d9e93a
Author: Ruben Vermeersch <ruben savanne be>
Date:   Tue Aug 11 23:27:23 2009 +0200

    Add proper image deletion.

 extensions/Tools/RawPlusJpeg/RawPlusJpeg.cs |    4 +-
 src/Core/Photo.cs                           |  133 ++++++++++++++++++++-------
 src/Core/PhotoChanges.cs                    |   26 +++++
 src/Db.cs                                   |    1 +
 src/Jobs/CleanHiddenVersionsJob.cs          |   31 ++++++
 src/MainWindow.cs                           |   13 +++-
 src/Makefile.am                             |    1 +
 src/PhotoImageView.cs                       |    2 +-
 src/PhotoStore.cs                           |   52 +++++++++--
 src/PhotoVersionCommands.cs                 |    5 +-
 10 files changed, 222 insertions(+), 46 deletions(-)
---
diff --git a/extensions/Tools/RawPlusJpeg/RawPlusJpeg.cs b/extensions/Tools/RawPlusJpeg/RawPlusJpeg.cs
index 7673e00..4461d7f 100644
--- a/extensions/Tools/RawPlusJpeg/RawPlusJpeg.cs
+++ b/extensions/Tools/RawPlusJpeg/RawPlusJpeg.cs
@@ -96,7 +96,7 @@ namespace RawPlusJpegExtension
 				foreach (uint version_id in jpeg.VersionIds) {
 					string name = jpeg.GetVersion (version_id).Name;
 					try {
-						raw.DefaultVersionId = raw.CreateReparentedVersion (jpeg.GetVersion (version_id) as PhotoVersion, version_id == Photo.OriginalVersionId);
+						raw.DefaultVersionId = raw.CreateReparentedVersion (jpeg.GetVersion (version_id));
 						if (version_id == Photo.OriginalVersionId)
 							raw.RenameVersion (raw.DefaultVersionId, "Jpeg");
 						else
@@ -110,7 +110,7 @@ namespace RawPlusJpegExtension
 				Array.Reverse (version_ids);
 				foreach (uint version_id in version_ids) {
 					try {
-						jpeg.DeleteVersion (version_id, true, true);
+						jpeg.DeleteVersion (version_id, true);
 					} catch (Exception e) {
 						Console.WriteLine (e);
 					}
diff --git a/src/Core/Photo.cs b/src/Core/Photo.cs
index 125d1f2..f0345f3 100644
--- a/src/Core/Photo.cs
+++ b/src/Core/Photo.cs
@@ -18,6 +18,7 @@ using System.Collections.Generic;
 using Mono.Unix;
 
 using FSpot.Utils;
+using FSpot.Jobs;
 using FSpot.Imaging;
 using FSpot.Platform;
 
@@ -131,7 +132,26 @@ namespace FSpot
 	
 		// Version management
 		public const int OriginalVersionId = 1;
-		private uint highest_version_id;
+
+		public uint HighestVersionId {
+			get {
+				uint highest = 0;
+				foreach (uint key in HiddenVersions.Keys)
+					highest = Math.Max (highest, key);
+				foreach (uint key in Versions.Keys)
+					highest = Math.Max (highest, key);
+				return highest;
+			}
+		}
+
+		private Dictionary<uint, PhotoVersion> hidden_versions;
+		private Dictionary<uint, PhotoVersion> HiddenVersions {
+			get {
+				if (hidden_versions == null)
+					hidden_versions = new Dictionary<uint, PhotoVersion> ();
+				return hidden_versions;
+			}
+		}
 	
 		private Dictionary<uint, PhotoVersion> versions = new Dictionary<uint, PhotoVersion> ();
 		public IEnumerable<IBrowsableItemVersion> Versions {
@@ -155,10 +175,18 @@ namespace FSpot
 
 		public PhotoVersion GetVersion (uint version_id)
 		{
-			if (versions == null)
-				return null;
+			return GetVersion (version_id, false);
+		}
+
+		public PhotoVersion GetVersion (uint version_id, bool include_hidden)
+		{
+			if (versions.ContainsKey (version_id))
+				return versions [version_id];
+
+			if (include_hidden && HiddenVersions.ContainsKey (version_id))
+				return HiddenVersions [version_id];
 	
-			return versions [version_id];
+			return null;
 		}
 	
 		private uint default_version_id = OriginalVersionId;
@@ -171,6 +199,11 @@ namespace FSpot
 				changes.DefaultVersionIdChanged = true;
 			}
 		}
+
+		internal void AddHiddenVersion (uint version_id, System.Uri uri, string md5_sum, string name, bool is_protected, PhotoVersionType type, uint parent_version_id)
+		{
+			HiddenVersions [version_id] = new PhotoVersion (this, version_id, uri, md5_sum, name, is_protected, type, parent_version_id);
+		}
 	
 		// This doesn't check if a version of that name already exists, 
 		// it's supposed to be used only within the Photo and PhotoStore classes.
@@ -178,7 +211,6 @@ namespace FSpot
 		{
 			versions [version_id] = new PhotoVersion (this, version_id, uri, md5_sum, name, is_protected, type, parent_version_id);
 	
-			highest_version_id = Math.Max (version_id, highest_version_id);
 			changes.AddVersion (version_id);
 		}
 	
@@ -191,13 +223,13 @@ namespace FSpot
 		{
 			if (VersionNameExists (name))
 				throw new ApplicationException ("A version with that name already exists");
-			highest_version_id ++;
+			uint version_id = HighestVersionId + 1;
 			string md5_sum = GenerateMD5 (uri);
 
-			versions [highest_version_id] = new PhotoVersion (this, highest_version_id, uri, md5_sum, name, is_protected, PhotoVersionType.Simple, 0);
+			versions [version_id] = new PhotoVersion (this, version_id, uri, md5_sum, name, is_protected, PhotoVersionType.Simple, 0);
 
-			changes.AddVersion (highest_version_id);
-			return highest_version_id;
+			changes.AddVersion (version_id);
+			return version_id;
 		}
 	
 		//FIXME: store versions next to originals. will crash on ro locations.
@@ -280,22 +312,37 @@ namespace FSpot
 			return version;
 		}
 
+		uint clean_hidden_versions_timeout = 0;
+
 		public void DeleteVersion (uint version_id)
 		{
-			DeleteVersion (version_id, false, false);
+			DeleteVersion (version_id, false);
 		}
-	
+
 		public void DeleteVersion (uint version_id, bool remove_original)
 		{
-			DeleteVersion (version_id, remove_original, false);
-		}
-	
-		public void DeleteVersion (uint version_id, bool remove_original, bool keep_file)
-		{
 			if (version_id == OriginalVersionId && !remove_original)
 				throw new Exception ("Cannot delete original version");
 	
-			System.Uri uri =  VersionUri (version_id);
+			changes.HideVersion (version_id);
+			Versions.Remove (version_id);
+			ResetDefaultVersion (version_id);
+
+			if (clean_hidden_versions_timeout == 0) {
+				clean_hidden_versions_timeout = GLib.Timeout.Add (5000, delegate () {
+					clean_hidden_versions_timeout = 0;
+
+					Core.Database.Jobs.Create (typeof (CleanHiddenVersionsJob), "");
+					return true;
+				});
+			}
+		}
+
+		// Deletes a version without checking for refs. Use with care!
+		public void FullyDeleteVersion (uint version_id, bool keep_file)
+		{
+			PhotoVersion version = GetVersion (version_id, true) as PhotoVersion;
+			System.Uri uri =  version.Uri;
 	
 			if (!keep_file) {
 				GLib.File file = GLib.FileFactory.NewForUri (uri);
@@ -312,10 +359,27 @@ namespace FSpot
 					//ignore an error here we don't really care.
 				}
 			}
-			versions.Remove (version_id);
 
-			changes.RemoveVersion (version_id);
+			if (versions.ContainsKey (version_id)) {
+				versions.Remove (version_id);
+				changes.RemoveVersion (version_id);
+			} else if (HiddenVersions.ContainsKey (version_id)) {
+				HiddenVersions.Remove (version_id);
+			}
+
+			ResetDefaultVersion (version_id);
+		}
+
+		public void DeleteHiddenVersions ()
+		{
+			foreach (uint version_id in HiddenVersions.Keys)
+			{
+				FullyDeleteVersion (version_id, false);
+			}
+		}
 
+		void ResetDefaultVersion (uint version_id)
+		{
 			do {
 				version_id --;
 				if (versions.ContainsKey (version_id)) {
@@ -356,22 +420,18 @@ namespace FSpot
 	
 				FSpot.ThumbnailGenerator.Create (new_uri).Dispose ();
 			}
-			highest_version_id ++;
 
-			versions [highest_version_id] = new PhotoVersion (this, highest_version_id, new_uri, md5_sum, name, is_protected, PhotoVersionType.Simple, 0);
+			uint version_id = HighestVersionId + 1;
+
+			versions [version_id] = new PhotoVersion (this, version_id, new_uri, md5_sum, name, is_protected, PhotoVersionType.Simple, 0);
 
-			changes.AddVersion (highest_version_id);
+			changes.AddVersion (version_id);
 	
-			return highest_version_id;
+			return version_id;
 		}
 	
 		public uint CreateReparentedVersion (PhotoVersion version)
 		{
-			return CreateReparentedVersion (version, false);
-		}
-	
-		public uint CreateReparentedVersion (PhotoVersion version, bool is_protected)
-		{
 			int num = 0;
 			while (true) {
 				num++;
@@ -381,12 +441,21 @@ namespace FSpot
 				if (VersionNameExists (name))
 					continue;
 	
-				highest_version_id ++;
-				versions [highest_version_id] = new PhotoVersion (this, highest_version_id, version.Uri, version.MD5Sum, name, is_protected, PhotoVersionType.Simple, 0);
+				Uri uri = GetUriForVersionName (name, System.IO.Path.GetExtension (version.Uri.AbsolutePath));
+				uint version_id = HighestVersionId + 1;
+				bool is_protected = version_id == OriginalVersionId;
+				versions [version_id] = new PhotoVersion (this, version_id, uri, version.MD5Sum, name, is_protected, PhotoVersionType.Simple, 0);
+
+				changes.AddVersion (version_id);
+
+				Uri source_uri = version.Uri;
+				Uri dest_uri = VersionUri (version_id);
 
-				changes.AddVersion (highest_version_id);
+				GLib.File source = GLib.FileFactory.NewForUri (source_uri);
+				GLib.File dest = GLib.FileFactory.NewForUri (dest_uri);
+				source.Copy (dest, GLib.FileCopyFlags.None, null, null);
 
-				return highest_version_id;
+				return version_id;
 			}
 		}
 	
diff --git a/src/Core/PhotoChanges.cs b/src/Core/PhotoChanges.cs
index 708fe49..07e2dd1 100644
--- a/src/Core/PhotoChanges.cs
+++ b/src/Core/PhotoChanges.cs
@@ -146,9 +146,35 @@ namespace FSpot
 				return;
 			if (versions_removed != null && versions_removed.Contains (v))
 				return;
+			if (versions_hidden != null && versions_hidden.Contains (v))
+				return;
 			versions_modified.Add (v);
 		}
 
+		List<uint> versions_hidden = null;
+		public uint [] VersionsHidden {
+			get {
+				if (versions_hidden == null)
+					return null;
+				if (versions_hidden.Count == 0)
+					return null;
+				return versions_hidden.ToArray ();
+			}
+			set {
+				foreach (uint u in value)
+					HideVersion (u);
+			}
+		}
+
+		public void HideVersion (uint v)
+		{
+			if (versions_hidden == null)
+				versions_hidden = new List<uint> ();
+			if (versions_modified != null)
+				versions_modified.Remove (v);
+			versions_hidden.Add (v);
+		}
+
 		public PhotoChanges ()
 		{
 		}
diff --git a/src/Db.cs b/src/Db.cs
index 3ddb09b..fd7b211 100644
--- a/src/Db.cs
+++ b/src/Db.cs
@@ -248,6 +248,7 @@ public class Db : IDisposable {
 
 	void HandleDbException (Exception e)
 	{
+		Log.Debug ("DatabaseException: {0}", e.ToString ());
 		if (ExceptionThrown != null)
 			ExceptionThrown (e);
 		else
diff --git a/src/Jobs/CleanHiddenVersionsJob.cs b/src/Jobs/CleanHiddenVersionsJob.cs
new file mode 100644
index 0000000..f594765
--- /dev/null
+++ b/src/Jobs/CleanHiddenVersionsJob.cs
@@ -0,0 +1,31 @@
+//
+// Fspot.Jobs.CleanHiddenVersionsJob.cs
+//
+// Author(s)
+//	Ruben Vermeersch  <ruben savanne be>
+//
+// This is free software. See COPYING for details
+//
+
+using Banshee.Kernel;
+using FSpot.Utils;
+using System;
+
+namespace FSpot.Jobs {
+	public class CleanHiddenVersionsJob : Job
+	{
+		public CleanHiddenVersionsJob (uint id, string job_options, int run_at, JobPriority job_priority, bool persistent) : this (id, job_options, DbUtils.DateTimeFromUnixTime (run_at), job_priority, persistent)
+		{
+		}
+
+		public CleanHiddenVersionsJob (uint id, string job_options, DateTime run_at, JobPriority job_priority, bool persistent) : base (id, job_options, job_priority, run_at, persistent)
+		{
+		}
+
+		protected override bool Execute ()
+		{
+			Core.Database.Photos.CleanHiddenVersions ();
+			return true;
+		}
+	}
+}
diff --git a/src/MainWindow.cs b/src/MainWindow.cs
index 3e30e8b..abe1a87 100644
--- a/src/MainWindow.cs
+++ b/src/MainWindow.cs
@@ -2204,12 +2204,13 @@ namespace FSpot
 				foreach (Photo photo in photos) {
 					foreach (uint id in photo.VersionIds) {
 						try {
-							photo.DeleteVersion (id, true);
+							photo.FullyDeleteVersion (id, false);
 						} catch (Exception e) {
 							DeleteException (e, photo.VersionUri (id).ToString ());
 						}
 					}
 				}
+				photo.DeleteHiddenVersions ();
 				Database.Photos.Remove (photos);
 				
 				UpdateQuery ();
@@ -2238,6 +2239,16 @@ namespace FSpot
 			string ok_caption = Catalog.GetString("_Remove from Catalog");
 			if (ResponseType.Ok == HigMessageDialog.RunHigConfirmation(GetToplevel (sender), DialogFlags.DestroyWithParent, 
 										   MessageType.Warning, header, msg, ok_caption)) {                              
+				foreach (Photo photo in photos) {
+					foreach (uint id in photo.VersionIds) {
+						try {
+							photo.FullyDeleteVersion (id, true);
+						} catch (Exception e) {
+							DeleteException (e, photo.VersionUri (id).ToString ());
+						}
+					}
+					photo.DeleteHiddenVersions ();
+				}
 				Database.Photos.Remove (photos);
 				UpdateQuery ();
 			}
diff --git a/src/Makefile.am b/src/Makefile.am
index 9f3dbcb..35d6e09 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -244,6 +244,7 @@ F_SPOT_CSDISTFILES =				\
 	$(srcdir)/JobStore.cs			\
 	$(srcdir)/Jobs/SyncMetadataJob.cs	\
 	$(srcdir)/Jobs/CalculateHashJob.cs	\
+	$(srcdir)/Jobs/CleanHiddenVersionsJob.cs	\
 	$(srcdir)/Loupe.cs			\
 	$(srcdir)/MainWindow.cs			\
 	$(srcdir)/MemorySurface.cs		\
diff --git a/src/PhotoImageView.cs b/src/PhotoImageView.cs
index ade9fe7..fb0dae9 100644
--- a/src/PhotoImageView.cs
+++ b/src/PhotoImageView.cs
@@ -156,7 +156,7 @@ namespace FSpot.Widgets {
 			if (Loader != null) {
 				Loader.AreaUpdated -= HandlePixbufAreaUpdated;
 				Loader.AreaPrepared -= HandlePixbufPrepared;
-				Loader.Dispose ();
+				DisposeLoader (Loader);
 			}
 			base.OnDestroyed ();
 		}
diff --git a/src/PhotoStore.cs b/src/PhotoStore.cs
index 345249f..ff89ed3 100644
--- a/src/PhotoStore.cs
+++ b/src/PhotoStore.cs
@@ -190,7 +190,11 @@ public class PhotoStore : DbStore<Photo> {
 			PhotoVersionType type = (PhotoVersionType) Enum.ToObject (typeof (PhotoVersionType), reader["type"]);
 			uint parent_version_id = Convert.ToUInt32 (reader ["parent_version_id"]);
 			                              
-			photo.AddVersionUnsafely (version_id, uri, md5_sum, name, is_protected, type, parent_version_id);
+			if (type == PhotoVersionType.Hidden) {
+				photo.AddHiddenVersion (version_id, uri, md5_sum, name, is_protected, type, parent_version_id);
+			} else {
+				photo.AddVersionUnsafely (version_id, uri, md5_sum, name, is_protected, type, parent_version_id);
+			}
 		}
 		reader.Close();
 	}
@@ -233,7 +237,11 @@ public class PhotoStore : DbStore<Photo> {
 				PhotoVersionType type = (PhotoVersionType) Enum.ToObject (typeof (PhotoVersionType), reader["type"]);
 				uint parent_version_id = Convert.ToUInt32 (reader ["parent_version_id"]);
 				
-				photo.AddVersionUnsafely (version_id, uri, md5_sum, name, is_protected, type, parent_version_id);
+				if (type == PhotoVersionType.Hidden) {
+					photo.AddHiddenVersion (version_id, uri, md5_sum, name, is_protected, type, parent_version_id);
+				} else {
+					photo.AddVersionUnsafely (version_id, uri, md5_sum, name, is_protected, type, parent_version_id);
+				}
 			}
 
 			/*
@@ -246,14 +254,33 @@ public class PhotoStore : DbStore<Photo> {
 		reader.Close();
 	}
 
+	public void CleanHiddenVersions ()
+	{
+		bool deleted;
+		do {
+			deleted = false;
+			SqliteDataReader reader = Database.Query(new DbCommand ("SELECT photo_id, version_id FROM photo_versions WHERE type = :type", "type", (uint) PhotoVersionType.Hidden));
+
+			while (reader.Read ()) {
+				uint photo_id = Convert.ToUInt32 (reader ["photo_id"]);
+				uint version_id = Convert.ToUInt32 (reader ["version_id"]);
+
+				Photo photo = Get (photo_id);
+				PhotoVersion version = photo.GetVersion (version_id, true);
+
+				if (VersionRefCount (version) == 0) {
+					photo.FullyDeleteVersion (version_id, false);
+					Database.ExecuteNonQuery (new DbCommand ("DELETE FROM photo_versions WHERE photo_id = :photo_id AND version_id = :version_id", "photo_id", photo_id, "version_id", version_id));
+					deleted = true;
+				}
+			}
+		} while (deleted);
+	}
+
 	public uint VersionRefCount (PhotoVersion version)
 	{
-		SqliteDataReader reader = Database.Query (
-				new DbCommand ("SELECT COUNT (*) as ref_count FROM photo_versions WHERE parent_version_id = :version_id AND photo_id = :photo_id",
-				"version_id", version.VersionId,
-				"photo_id", version.Photo));
-		uint ref_count = Convert.ToUInt32 (reader ["ref_count"]);
-		reader.Close ();
+		string query = String.Format ("SELECT COUNT(*) AS ref_count FROM photo_versions WHERE photo_id = {0} AND parent_version_id = {1}", version.Photo.Id, version.VersionId);
+		uint ref_count = Convert.ToUInt32 (Database.QuerySingle (query));
 		return ref_count;
 	}
 
@@ -562,6 +589,15 @@ public class PhotoStore : DbStore<Photo> {
 					"photo_id", photo.Id,
 					"version_id", version_id));
 			}
+		if (changes.VersionsHidden != null)
+			foreach (uint version_id in changes.VersionsHidden) {
+				Database.ExecuteNonQuery (new DbCommand (
+					"UPDATE photo_versions SET type = :type " +
+					"WHERE photo_id = :photo_id AND version_id = :version_id",
+					"type", (uint) PhotoVersionType.Hidden,
+					"photo_id", photo.Id,
+					"version_id", version_id));
+			}
 		photo.Changes = null;
 		return changes;
 	}
diff --git a/src/PhotoVersionCommands.cs b/src/PhotoVersionCommands.cs
index ef1d27f..ddd26d1 100644
--- a/src/PhotoVersionCommands.cs
+++ b/src/PhotoVersionCommands.cs
@@ -218,7 +218,8 @@ public class PhotoVersionCommands
 				new_parent.AddTag (photo.Tags);
 				foreach (uint version_id in photo.VersionIds) {
 					try {
-						new_parent.DefaultVersionId = new_parent.CreateReparentedVersion (photo.GetVersion (version_id) as PhotoVersion);
+						uint new_version = new_parent.CreateReparentedVersion (photo.GetVersion (version_id) as PhotoVersion);
+						new_parent.DefaultVersionId = new_version;
 						store.Commit (new_parent);
 					} catch (Exception e) {
 						Log.DebugException (e);	
@@ -228,7 +229,7 @@ public class PhotoVersionCommands
 				Array.Reverse (version_ids);
 				foreach (uint version_id in version_ids) {
 					try {
-						photo.DeleteVersion (version_id, true, true);
+						photo.DeleteVersion (version_id, true);
 					} catch (Exception e) {
 						Log.DebugException (e);
 					}



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]