[f-spot/fullfile-dupedetect: 3/4] Make dupe detect work on full-file hash during import.



commit c34d3fe4bbe43f0c8706f8c0d6338971a4102086
Author: Ruben Vermeersch <ruben savanne be>
Date:   Wed Jun 9 23:19:36 2010 +0200

    Make dupe detect work on full-file hash during import.
    
    The hash is calculated when the file is imported and will never be
    recalculated.
    
    Advantages:
    * Faster, no need to generate a thumbnail
    * Does perfect duplicate detection of files that come from a
      camera / card
    
    Disadvantages:
    * We need to nuke all the duplicate data
    * Changed files which are reimported won't get the right import hash

 lib/Hyena                                          |    2 +-
 src/Core/IBrowsableItemVersion.cs                  |    2 +
 src/Core/Photo.cs                                  |   74 ++------
 src/Core/PhotoVersion.cs                           |    4 +-
 src/FileBrowsableItem.cs                           |    2 +
 src/Import/ImportController.cs                     |    2 +-
 src/Import/ImportSource.cs                         |    2 +
 src/Jobs/CalculateHashJob.cs                       |    2 +-
 src/PhotoQuery.cs                                  |   12 +-
 src/PhotoStore.cs                                  |  210 ++++++--------------
 src/PhotoVersionCommands.cs                        |    1 -
 ...{TagConditionWrapper.cs => ConditionWrapper.cs} |    6 +-
 src/Query/Makefile.am                              |    2 +-
 src/TagQueryWidget.cs                              |    2 +-
 src/Widgets/FindBar.cs                             |    2 +-
 15 files changed, 93 insertions(+), 232 deletions(-)
---
diff --git a/lib/Hyena b/lib/Hyena
index dec9a4e..1d17311 160000
--- a/lib/Hyena
+++ b/lib/Hyena
@@ -1 +1 @@
-Subproject commit dec9a4edf244ccc8bf5b8a28fd09980baa771a62
+Subproject commit 1d173113fa4c23d3e9a6b2295cce3291470056cc
diff --git a/src/Core/IBrowsableItemVersion.cs b/src/Core/IBrowsableItemVersion.cs
index a0006f9..366716f 100644
--- a/src/Core/IBrowsableItemVersion.cs
+++ b/src/Core/IBrowsableItemVersion.cs
@@ -10,5 +10,7 @@ namespace FSpot
 
         // For convenience
         SafeUri Uri { get; }
+
+		string ImportMD5 { get; }
     }
 }
diff --git a/src/Core/Photo.cs b/src/Core/Photo.cs
index aa723d0..0182adc 100644
--- a/src/Core/Photo.cs
+++ b/src/Core/Photo.cs
@@ -107,18 +107,6 @@ namespace FSpot
 			}
 		}
 
-		private string md5_sum;
-		public string MD5Sum {
-			get { return md5_sum; }
-			set { 
-				if (md5_sum == value)
-				 	return;
-
-				md5_sum = value; 
-				changes.MD5SumChanged = true;
-			} 
-		}
-	
 		// Version management
 		public const int OriginalVersionId = 1;
 		private uint highest_version_id;
@@ -164,9 +152,9 @@ namespace FSpot
 	
 		// 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.
-		internal void AddVersionUnsafely (uint version_id, SafeUri base_uri, string filename, string md5_sum, string name, bool is_protected)
+		internal void AddVersionUnsafely (uint version_id, SafeUri base_uri, string filename, string import_md5, string name, bool is_protected)
 		{
-			versions [version_id] = new PhotoVersion (this, version_id, base_uri, filename, md5_sum, name, is_protected);
+			versions [version_id] = new PhotoVersion (this, version_id, base_uri, filename, import_md5, name, is_protected);
 	
 			highest_version_id = Math.Max (version_id, highest_version_id);
 			changes.AddVersion (version_id);
@@ -182,9 +170,9 @@ namespace FSpot
 			if (VersionNameExists (name))
 				throw new ApplicationException ("A version with that name already exists");
 			highest_version_id ++;
-			string md5_sum = GenerateMD5 (base_uri.Append (filename));
+			string import_md5 = String.Empty; // Modified version
 
-			versions [highest_version_id] = new PhotoVersion (this, highest_version_id, base_uri, filename, md5_sum, name, is_protected);
+			versions [highest_version_id] = new PhotoVersion (this, highest_version_id, base_uri, filename, import_md5, name, is_protected);
 
 			changes.AddVersion (highest_version_id);
 			return highest_version_id;
@@ -245,7 +233,7 @@ namespace FSpot
 					using (Stream stream = System.IO.File.OpenWrite (versionUri.LocalPath)) {
 						img.Save (buffer, stream);
 					}
-					(GetVersion (version) as PhotoVersion).MD5Sum = GenerateMD5 (VersionUri (version));
+					(GetVersion (version) as PhotoVersion).ImportMD5 = GenerateMD5 (VersionUri (version));
 					DefaultVersionId = version;
 				} catch (System.Exception e) {
 					Log.Exception (e);
@@ -320,7 +308,7 @@ namespace FSpot
 			string filename = GetFilenameForVersionName (name, extension);
 			SafeUri original_uri = VersionUri (base_version_id);
 			SafeUri new_uri = new_base_uri.Append (filename);
-			string md5_sum = MD5Sum;
+			string import_md5 = DefaultVersion.ImportMD5;
 	
 			if (VersionNameExists (name))
 				throw new Exception ("This version name already exists");
@@ -336,7 +324,7 @@ namespace FSpot
 			}
 			highest_version_id ++;
 
-			versions [highest_version_id] = new PhotoVersion (this, highest_version_id, new_base_uri, filename, md5_sum, name, is_protected);
+			versions [highest_version_id] = new PhotoVersion (this, highest_version_id, new_base_uri, filename, import_md5, name, is_protected);
 
 			changes.AddVersion (highest_version_id);
 	
@@ -363,7 +351,7 @@ namespace FSpot
 				name = String.Format (name, num);
 			}
 			highest_version_id ++;
-			versions [highest_version_id] = new PhotoVersion (this, highest_version_id, version.BaseUri, version.Filename, version.MD5Sum, name, is_protected);
+			versions [highest_version_id] = new PhotoVersion (this, highest_version_id, version.BaseUri, version.Filename, version.ImportMD5, name, is_protected);
 
 			changes.AddVersion (highest_version_id);
 
@@ -438,7 +426,6 @@ namespace FSpot
 			Time = that.Time;
 			Description = that.Description;
 			Rating = that.Rating;
-			MD5Sum = that.MD5Sum;
 			AddTag (that.Tags);
 		}
 	
@@ -506,20 +493,6 @@ namespace FSpot
 			return tags.Contains (tag);
 		}
 	
-		//
-		// MD5 Calculator
-		//
-		private static System.Security.Cryptography.MD5 md5_generator;
-
-		private static System.Security.Cryptography.MD5 MD5Generator {
-			get {
-				if (md5_generator == null)
-				 	md5_generator = new System.Security.Cryptography.MD5CryptoServiceProvider ();
-
-				return md5_generator;
-			} 
-		}
-
 		private static IDictionary<SafeUri, string> md5_cache = new Dictionary<SafeUri, string> ();
 
 		public static void ResetMD5Cache () {
@@ -529,30 +502,14 @@ namespace FSpot
 
 		public static string GenerateMD5 (SafeUri uri)
 		{
-		 	try {
-			 	if (md5_cache.ContainsKey (uri))
-				 	return md5_cache [uri];
-
-				using (Gdk.Pixbuf pixbuf = XdgThumbnailSpec.LoadThumbnail (uri, ThumbnailSize.Large))
-				{
-					byte[] serialized = GdkUtils.Serialize (pixbuf);
-					byte[] md5 = MD5Generator.ComputeHash (serialized);
-					string md5_string = Convert.ToBase64String (md5);
-
-					md5_cache.Add (uri, md5_string);
-					return md5_string;
-				}
-			} catch (Exception e) {
-				Log.DebugFormat ("Failed to create MD5Sum for Uri: {0}\n", uri);
-				Log.DebugException (e);
-			}
-
-			return string.Empty; 
+			var file = GLib.FileFactory.NewForUri (uri);
+			var stream = new GLib.GioStream (file.Read (null));
+			var hash = CryptoUtil.Md5EncodeStream (stream);
+			return hash;
 		}
 
-
 		// Constructor
-		public Photo (uint id, long unix_time, SafeUri base_uri, string filename, string md5_sum)
+		public Photo (uint id, long unix_time, SafeUri base_uri, string filename)
 			: base (id)
 		{
 			if (base_uri == null)
@@ -564,11 +521,6 @@ namespace FSpot
 	
 			description = String.Empty;
 			rating = 0;
-			this.md5_sum = md5_sum;
-	
-			// Note that the original version is never stored in the photo_versions table in the
-			// database.
-			AddVersionUnsafely (OriginalVersionId, base_uri, filename, md5_sum, Catalog.GetString ("Original"), true);
 		}
 
 #region IComparable implementation
diff --git a/src/Core/PhotoVersion.cs b/src/Core/PhotoVersion.cs
index f5cdd82..683a3a9 100644
--- a/src/Core/PhotoVersion.cs
+++ b/src/Core/PhotoVersion.cs
@@ -21,7 +21,7 @@ namespace FSpot
 		public SafeUri BaseUri { get; set; }
         public string Filename { get; set; }
         public SafeUri Uri { get { return BaseUri.Append (Filename); } }
-		public string MD5Sum { get; internal set; }
+		public string ImportMD5 { get; internal set; }
 		public uint VersionId { get; private set; }
 		public bool IsProtected { get; private set; }
 	
@@ -31,7 +31,7 @@ namespace FSpot
 			VersionId = version_id;
 			BaseUri = base_uri;
             Filename = filename;
-			MD5Sum = md5_sum;
+			ImportMD5 = md5_sum;
 			Name = name;
 			IsProtected = is_protected;
 		}
diff --git a/src/FileBrowsableItem.cs b/src/FileBrowsableItem.cs
index e2ab934..d69bed7 100644
--- a/src/FileBrowsableItem.cs
+++ b/src/FileBrowsableItem.cs
@@ -94,6 +94,8 @@ namespace FSpot {
 			public SafeUri BaseUri { get { return Uri.GetBaseUri (); } }
 			public string Filename { get { return Uri.GetFilename (); } }
 			public SafeUri Uri { get; set; }
+
+			public string ImportMD5 { get { return String.Empty; } }
 		}
 	}
 }
diff --git a/src/Import/ImportController.cs b/src/Import/ImportController.cs
index f36e05b..0f7fa78 100644
--- a/src/Import/ImportController.cs
+++ b/src/Import/ImportController.cs
@@ -294,7 +294,7 @@ namespace FSpot.Import
             var destination = FindImportDestination (item.DefaultVersion.Uri);
 
             // Do duplicate detection
-            if (DuplicateDetect && store.CheckForDuplicate (item.DefaultVersion.Uri, destination)) {
+            if (DuplicateDetect && store.HasDuplicate (item.DefaultVersion.Uri, destination)) {
                 return;
             }
 
diff --git a/src/Import/ImportSource.cs b/src/Import/ImportSource.cs
index 5c6f370..ba27d96 100644
--- a/src/Import/ImportSource.cs
+++ b/src/Import/ImportSource.cs
@@ -18,5 +18,7 @@ namespace FSpot.Import
 		public string Filename { get; set; }
 
 		public SafeUri Uri { get { return BaseUri.Append (Filename); } }
+
+        public string ImportMD5 { get { return String.Empty; } }
 	}
 }
diff --git a/src/Jobs/CalculateHashJob.cs b/src/Jobs/CalculateHashJob.cs
index 4dd70ef..d2a9007 100644
--- a/src/Jobs/CalculateHashJob.cs
+++ b/src/Jobs/CalculateHashJob.cs
@@ -40,7 +40,7 @@ namespace FSpot.Jobs {
 
 			try {
 				Photo photo = FSpot.App.Instance.Database.Photos.Get (Convert.ToUInt32 (photo_id)) as Photo;
-				FSpot.App.Instance.Database.Photos.UpdateMD5Sum (photo);
+				FSpot.App.Instance.Database.Photos.CalculateMD5Sum (photo);
 				return true;
 			} catch (System.Exception e) {
 				Log.DebugFormat ("Error Calculating Hash for photo {0}: {1}", JobOptions, e.Message);
diff --git a/src/PhotoQuery.cs b/src/PhotoQuery.cs
index 93b9cd2..68c111c 100644
--- a/src/PhotoQuery.cs
+++ b/src/PhotoQuery.cs
@@ -185,7 +185,7 @@ namespace FSpot {
 					untagged = value;
 					
 					if (untagged) {
-						UnSetCondition<TagConditionWrapper> ();
+						UnSetCondition<ConditionWrapper> ();
 						UnSetCondition<HiddenTag> ();
 					}
 					
@@ -218,10 +218,10 @@ namespace FSpot {
 			}
 		}
 		
-		public TagConditionWrapper TagTerm {
-			get { return GetCondition<TagConditionWrapper> (); }
+		public ConditionWrapper TagTerm {
+			get { return GetCondition<ConditionWrapper> (); }
 			set {
-				if (value == null && UnSetCondition<TagConditionWrapper>()
+				if (value == null && UnSetCondition<ConditionWrapper>()
 				    || value != null && SetCondition (value)) {
 					
 					if (value != null) {
@@ -264,8 +264,8 @@ namespace FSpot {
 				i = 1;
 			} else {
 				condition_array = new IQueryCondition[conditions.Count + 2];
-		//		condition_array[0] = new TagConditionWrapper (extra_condition);
-				condition_array[1] = new TagConditionWrapper (terms != null ? terms.SqlCondition () : null);
+		//		condition_array[0] = new ConditionWrapper (extra_condition);
+				condition_array[1] = new ConditionWrapper (terms != null ? terms.SqlCondition () : null);
 				i = 2;
 			}
 			
diff --git a/src/PhotoStore.cs b/src/PhotoStore.cs
index 2880cea..f9b9f84 100644
--- a/src/PhotoStore.cs
+++ b/src/PhotoStore.cs
@@ -72,8 +72,7 @@ public class PhotoStore : DbStore<Photo> {
 			"	description		TEXT NOT NULL, \n" +
 			"	roll_id			INTEGER NOT NULL, \n" +
 			"	default_version_id	INTEGER NOT NULL, \n" +
-			"	rating			INTEGER NULL, \n" +
-			"	md5_sum			TEXT NULL\n" +
+			"	rating			INTEGER NULL \n" +
 			")");
 
 		Database.ExecuteNonQuery (
@@ -90,45 +89,24 @@ public class PhotoStore : DbStore<Photo> {
 			"	name		STRING, \n" +
 			"	base_uri		STRING NOT NULL, \n" +
 		    "	filename		STRING NOT NULL, \n" +
-			"	md5_sum		TEXT NULL, \n" +
+			"	import_md5		TEXT NULL, \n" +
 			"	protected	BOOLEAN, \n" +
 			"	UNIQUE (photo_id, version_id)\n" +
 			")");
 
 		Database.ExecuteNonQuery ("CREATE INDEX idx_photo_versions_id ON photo_versions(photo_id)");
+		Database.ExecuteNonQuery ("CREATE INDEX idx_photo_versions_import_md5 ON photo_versions(import_md5)");
 		Database.ExecuteNonQuery ("CREATE INDEX idx_photos_roll_id ON photos(roll_id)");
 	}
 
-	public bool CheckForDuplicate (SafeUri uri, SafeUri dest_uri) {
-		// Here we can go wild in comparing photos,
-		// for now we check on uri and md5
-		Photo found = GetByUri (dest_uri);
-		
-		if (found != null)
-			return true;
-
-		string md5 = Photo.GenerateMD5 (uri);			
-		var file = GLib.FileFactory.NewForUri (uri);
-		var info = file.QueryInfo ("standard::content-type", GLib.FileQueryInfoFlags.None, null);
-
-		Photo[] md5_matches = GetByMD5 (md5);
-
-		foreach (Photo match in md5_matches)
-		{
-			var file2 = GLib.FileFactory.NewForUri (match.DefaultVersion.Uri);
-			var info2 = file2.QueryInfo ("standard::content-type", GLib.FileQueryInfoFlags.None, null);
-
-			// same mimetype?
-			if (info.ContentType != info2.ContentType)
-			 	continue;
-
-			// other comparisons?
-
-			// TODO? load pixbuf and compare sizes?	
-
+	public bool HasDuplicate (SafeUri uri, SafeUri destination) {
+		var hash = Photo.GenerateMD5 (uri);
+		var condition = new ConditionWrapper (String.Format ("import_md5 = \"{0}\"", hash));
+		var dupes_by_hash = Count ("photo_versions", condition);
+		if (dupes_by_hash > 0)
 			return true;
-		}
 
+		// FIXME
 		return false;
 	}
 
@@ -147,35 +125,51 @@ public class PhotoStore : DbStore<Photo> {
 		using (FSpot.ImageFile img = FSpot.ImageFile.Create (orig_uri)) {
 			long unix_time = DbUtils.UnixTimeFromDateTime (img.Date);
 			string description = img.Description != null  ? img.Description.Split ('\0') [0] : String.Empty;
-			string md5_sum = Photo.GenerateMD5 (new_uri);
+			string import_md5 = Photo.GenerateMD5 (new_uri);
 
 	 		uint id = (uint) Database.Execute (
 				new DbCommand (
-					"INSERT INTO photos (time, base_uri, filename, description, roll_id, default_version_id, rating, md5_sum) "	+
-					"VALUES (:time, :base_uri, :filename, :description, :roll_id, :default_version_id, :rating, :md5_sum)",
+					"INSERT INTO photos (time, base_uri, filename, description, roll_id, default_version_id, rating) "	+
+					"VALUES (:time, :base_uri, :filename, :description, :roll_id, :default_version_id, :rating)",
 	 				"time", unix_time,
 					"base_uri", new_base_uri.ToString (),
 					"filename", filename,
 	 				"description", description,
 					"roll_id", roll_id,
 	 				"default_version_id", Photo.OriginalVersionId,
-					"rating", "0",
-					"md5_sum", (md5_sum != String.Empty ? md5_sum : null)
+					"rating", "0"
 				)
 			);
-	
-			photo = new Photo (id, unix_time, new_base_uri, filename, md5_sum);
+
+			photo = new Photo (id, unix_time, new_base_uri, filename);
+			photo.AddVersionUnsafely (Photo.OriginalVersionId, new_base_uri, filename, import_md5, Catalog.GetString ("Original"), true);	
 			photo.Loaded = true;
+
+			InsertVersion (photo, photo.DefaultVersion as PhotoVersion);
 			EmitAdded (photo);
 		}
 		return photo;
 	}
 
+	private void InsertVersion (Photo photo, PhotoVersion version)
+	{
+		Database.ExecuteNonQuery (new DbCommand (
+			"INSERT OR IGNORE INTO photo_versions (photo_id, version_id, name, base_uri, filename, protected, import_md5) " +
+			"VALUES (:photo_id, :version_id, :name, :base_uri, :filename, :is_protected, :import_md5)",
+			"photo_id", photo.Id,
+			"version_id", version.VersionId,
+			"name", version.Name,
+			"base_uri", version.BaseUri.ToString (),
+			"filename", version.Filename,
+			"is_protected", version.IsProtected,
+			"import_md5", (version.ImportMD5 != String.Empty ? version.ImportMD5 : null)));
+	}
+
 
 	private void GetVersions (Photo photo)
 	{
 		SqliteDataReader reader = Database.Query(
-			new DbCommand("SELECT version_id, name, base_uri, filename, md5_sum, protected " + 
+			new DbCommand("SELECT version_id, name, base_uri, filename, import_md5, protected " + 
 				      "FROM photo_versions " + 
 				      "WHERE photo_id = :id", 
 				      "id", photo.Id
@@ -187,10 +181,10 @@ public class PhotoStore : DbStore<Photo> {
 			string name = reader["name"].ToString ();
 			var base_uri = new SafeUri (reader ["base_uri"].ToString (), true);
 			var filename = reader ["filename"].ToString ();
-			string md5_sum = reader["md5_sum"] != null ? reader ["md5_sum"].ToString () : null;
+			string import_md5 = reader["import_md5"] != null ? reader ["import_md5"].ToString () : null;
 			bool is_protected = Convert.ToBoolean (reader["protected"]);
 			                              
-			photo.AddVersionUnsafely (version_id, base_uri, filename, md5_sum, name, is_protected);
+			photo.AddVersionUnsafely (version_id, base_uri, filename, import_md5, name, is_protected);
 		}
 		reader.Close();
 	}
@@ -208,7 +202,7 @@ public class PhotoStore : DbStore<Photo> {
 	}		
 	
 	private void GetAllVersions  (string ids) {
-		SqliteDataReader reader = Database.Query ("SELECT photo_id, version_id, name, base_uri, filename, md5_sum, protected FROM photo_versions WHERE photo_id IN " + ids);
+		SqliteDataReader reader = Database.Query ("SELECT photo_id, version_id, name, base_uri, filename, import_md5, protected FROM photo_versions WHERE photo_id IN " + ids);
 		
 		while (reader.Read ()) {
 			uint id = Convert.ToUInt32 (reader ["photo_id"]);
@@ -229,10 +223,10 @@ public class PhotoStore : DbStore<Photo> {
 				string name = reader["name"].ToString ();
 				var base_uri = new SafeUri (reader ["base_uri"].ToString (), true);
 				var filename = reader ["filename"].ToString ();
-				string md5_sum = reader["md5_sum"] != null ? reader ["md5_sum"].ToString () : null;
+				string import_md5 = reader["import_md5"] != null ? reader ["import_md5"].ToString () : null;
 				bool is_protected = Convert.ToBoolean (reader["protected"]);
 				
-				photo.AddVersionUnsafely (version_id, base_uri, filename, md5_sum, name, is_protected);
+				photo.AddVersionUnsafely (version_id, base_uri, filename, import_md5, name, is_protected);
 			}
 
 			/*
@@ -278,7 +272,7 @@ public class PhotoStore : DbStore<Photo> {
 			return photo;
 		
 		SqliteDataReader reader = Database.Query(
-			new DbCommand("SELECT time, base_uri, filename, description, roll_id, default_version_id, rating, md5_sum " + 
+			new DbCommand("SELECT time, base_uri, filename, description, roll_id, default_version_id, rating " + 
 				      "FROM photos " + 
 				      "WHERE id = :id", "id", id
 				     )
@@ -289,8 +283,7 @@ public class PhotoStore : DbStore<Photo> {
 			var filename = reader ["filename"].ToString ();
 			photo = new Photo (id,
 				Convert.ToInt64 (reader ["time"]),
-			    base_uri, filename,
-				reader["md5_sum"] != null ? reader["md5_sum"].ToString () : null
+			    base_uri, filename
 			);
 
 			photo.Description = reader["description"].ToString ();
@@ -318,7 +311,7 @@ public class PhotoStore : DbStore<Photo> {
 		var filename = uri.GetFilename ();
 
 		SqliteDataReader reader =
-			Database.Query (new DbCommand ("SELECT id, time, description, roll_id, default_version_id, rating, photos.md5_sum AS md5_sum " +
+			Database.Query (new DbCommand ("SELECT id, time, description, roll_id, default_version_id, rating " +
 			                               " FROM photos " +
 			                               " LEFT JOIN photo_versions AS pv ON photos.id = pv.photo_id" +
 			                               " WHERE (photos.base_uri = :base_uri AND photos.filename = :filename)" +
@@ -330,8 +323,7 @@ public class PhotoStore : DbStore<Photo> {
 			photo = new Photo (Convert.ToUInt32 (reader ["id"]),
 					   Convert.ToInt64 (reader ["time"]),
 					   base_uri,
-					   filename,
-					   reader["md5_sum"] != null ? reader["md5_sum"].ToString () : null);
+					   filename);
 
 			photo.Description = reader["description"].ToString ();
 			photo.RollId = Convert.ToUInt32 (reader["roll_id"]);
@@ -357,61 +349,6 @@ public class PhotoStore : DbStore<Photo> {
 		return photo;
 	}
 
-	public Photo[] GetByMD5 (string md5_sum)
-	{
-		List<Photo> photos = new List<Photo> ();
-		
-		SqliteDataReader reader = Database.Query (
-			new DbCommand ("SELECT DISTINCT " + 
-				       "id, time, photos.base_uri AS base_uri, photos.filename AS filename, description, roll_id, default_version_id, rating " + 
-				       "FROM photos " + 
-				       "LEFT JOIN photo_versions " + 
-				       "ON   photos.id = photo_versions.photo_id " +
-				       "WHERE photos.md5_sum = :md5_sum " +
-				       "OR photo_versions.md5_sum = :md5_sum", 
-				       "md5_sum", md5_sum
-				      )
-		);
-
-		while (reader.Read ()) {
-			var base_uri = new SafeUri (reader ["base_uri"].ToString (), true);
-			var filename = reader ["filename"].ToString ();
-			Photo photo =
-				new Photo (Convert.ToUInt32 (reader ["id"]),
-				           Convert.ToInt64 (reader ["time"]),
-				           base_uri, filename,
-				           md5_sum);
-
-			photo.Description = reader["description"].ToString ();
-			photo.RollId = Convert.ToUInt32 (reader["roll_id"]);
-			photo.DefaultVersionId = Convert.ToUInt32 (reader["default_version_id"]);
-			photo.Rating = Convert.ToUInt32 (reader ["rating"]);
-			photo.MD5Sum = md5_sum;
-
-			// get cached if possible
-			Photo cached = LookupInCache (photo.Id);
-
-			if (cached != null)
-			{
-				photos.Add (cached);
-				continue;
-			}
-
-			// Add to cache and fully load if not found in cache
-			AddToCache (photo);
-	
-			GetTags (photo);
-			GetVersions (photo);
-
-			// add to collection
-			photos.Add (photo);
-		}
-
-	        reader.Close();
-
-		return photos.ToArray ();
-	}
-
 	public void Remove (Tag []tags)
 	{
 		Photo [] photos = Query (tags, String.Empty, null, null);	
@@ -484,8 +421,7 @@ public class PhotoStore : DbStore<Photo> {
 					"    time = :time, " + 
 					"    base_uri = :base_uri, " +
 					"    filename = :filename, " +       
-					"    rating = :rating, " +
-					"    md5_sum = :md5_sum	" +
+					"    rating = :rating " +
 					"WHERE id = :id ",
 					"description", photo.Description,
 					"default_version_id", photo.DefaultVersionId,
@@ -493,7 +429,6 @@ public class PhotoStore : DbStore<Photo> {
 					"base_uri", photo.VersionUri (Photo.OriginalVersionId).GetBaseUri ().ToString (),
 					"filename", photo.VersionUri (Photo.OriginalVersionId).GetFilename (),
 					"rating", String.Format ("{0}", photo.Rating),
-					"md5_sum", (photo.MD5Sum != String.Empty ? photo.MD5Sum : null),
 					"id", photo.Id
 				)
 			);
@@ -525,62 +460,37 @@ public class PhotoStore : DbStore<Photo> {
 		if (changes.VersionsAdded != null)
 			foreach (uint version_id in changes.VersionsAdded) {
 				PhotoVersion version = photo.GetVersion (version_id) as PhotoVersion;
-				Database.ExecuteNonQuery (new DbCommand (
-					"INSERT OR IGNORE INTO photo_versions (photo_id, version_id, name, base_uri, filename, protected, md5_sum) " +
-					"VALUES (:photo_id, :version_id, :name, :base_uri, :filename, :is_protected, :md5_sum)",
-					"photo_id", photo.Id,
-					"version_id", version_id,
-					"name", version.Name,
-			        "base_uri", version.BaseUri.ToString (),
-					"filename", version.Filename,
-					"is_protected", version.IsProtected,
-					"md5_sum", (version.MD5Sum != String.Empty ? version.MD5Sum : null)));
+				InsertVersion (photo, version);
 			}
 		if (changes.VersionsModified != null)
 			foreach (uint version_id in changes.VersionsModified) {
 				PhotoVersion version = photo.GetVersion (version_id) as PhotoVersion;
 				Database.ExecuteNonQuery (new DbCommand (
 					"UPDATE photo_versions SET name = :name, " +
-					"base_uri = :base_uri, filename = :filename, protected = :protected, md5_sum = :md5_sum " +
+					"base_uri = :base_uri, filename = :filename, protected = :protected, import_md5 = :import_md5 " +
 					"WHERE photo_id = :photo_id AND version_id = :version_id",
 					"name", version.Name,
 					"base_uri", version.BaseUri.ToString (),
 					"filename", version.Filename,
 					"protected", version.IsProtected,
 					"photo_id", photo.Id,
-					"md5_sum", (version.MD5Sum != String.Empty ? version.MD5Sum : null),
+					"import_md5", (version.ImportMD5 != String.Empty ? version.ImportMD5 : null),
 					"version_id", version_id));
 			}
 		photo.Changes = null;
 		return changes;
 	}
 
-	public void UpdateMD5Sum (Photo photo) {
-		string md5_sum = Photo.GenerateMD5 (photo.VersionUri (Photo.OriginalVersionId)); 
-		photo.MD5Sum = md5_sum;
-
-		Database.ExecuteNonQuery (
-			new DbCommand (
-				"UPDATE photos " +
-				"SET    md5_sum = :md5_sum " +
-				"WHERE  ID = :id",
-				"md5_sum", (md5_sum != String.Empty ? md5_sum : null),
-				"id", photo.Id
-			)
-		);
-
+	public void CalculateMD5Sum (Photo photo) {
 		foreach (uint version_id in photo.VersionIds) {
-			if (version_id == Photo.OriginalVersionId)
-			 	continue;
-
 			PhotoVersion version = photo.GetVersion (version_id) as PhotoVersion;
 
-			string version_md5_sum = Photo.GenerateMD5 (version.Uri);
-
-			if (version.MD5Sum == version_md5_sum)
-			 	continue;
+			// Don't overwrite MD5 sums that are already calculated.
+			if (version.ImportMD5 != String.Empty && version.ImportMD5 != null)
+				continue;
 
-			version.MD5Sum = version_md5_sum; 
+			string version_md5_sum = Photo.GenerateMD5 (version.Uri);
+			version.ImportMD5 = version_md5_sum; 
 			photo.Changes.ChangeVersion (version_id);
 		}
 
@@ -855,11 +765,8 @@ public class PhotoStore : DbStore<Photo> {
 				var base_uri = new SafeUri (reader ["base_uri"].ToString (), true);
 				var filename = reader ["filename"].ToString ();
 				photo =
-					new Photo (id,
-					           Convert.ToInt64 (reader ["time"]),
-					           base_uri, filename,
-					           reader["md5_sum"] != null ? reader ["md5_sum"].ToString () : null
-				);
+					new Photo (id, Convert.ToInt64 (reader ["time"]),
+					           base_uri, filename);
 				photo.Description = reader["description"].ToString ();
 				photo.RollId = Convert.ToUInt32 (reader["roll_id"]);
 				photo.DefaultVersionId = Convert.ToUInt32 (reader["default_version_id"]);
@@ -911,8 +818,7 @@ public class PhotoStore : DbStore<Photo> {
 				"description, "		+
 				"roll_id, "		+
 				"default_version_id, "	+
-				"rating, "		+
-				"md5_sum "		+
+				"rating "		+
 			"FROM photos " 				+
 			"WHERE base_uri LIKE :base_uri "		+
 			"AND filename LIKE :filename",
@@ -929,8 +835,7 @@ public class PhotoStore : DbStore<Photo> {
 				"description, "		+
 				"roll_id, "		+
 				"default_version_id, "	+
-				"rating, "		+
-				"md5_sum "		+
+				"rating "		+
 			"FROM photos " 				+
 			"WHERE base_uri LIKE :base_uri "		+
 			"AND base_uri NOT LIKE :base_uri_",
@@ -981,8 +886,7 @@ public class PhotoStore : DbStore<Photo> {
 					     "description, "		+
 				      	     "roll_id, "   		+
 					     "default_version_id, "	+
-					     "rating, "			+
-					     "md5_sum "			+
+					     "rating "			+
 				      "FROM photos ");
 		
 		if (range != null) {
diff --git a/src/PhotoVersionCommands.cs b/src/PhotoVersionCommands.cs
index 6e45143..f753849 100644
--- a/src/PhotoVersionCommands.cs
+++ b/src/PhotoVersionCommands.cs
@@ -175,7 +175,6 @@ public class PhotoVersionCommands
 									   MessageType.Warning, msg, desc, ok_caption)) {
 					Photo new_photo = store.Create (photo.DefaultVersion.Uri, photo.RollId);
 					new_photo.CopyAttributesFrom (photo);
-					new_photo.MD5Sum = (photo.DefaultVersion as PhotoVersion).MD5Sum;
 					photo.DeleteVersion (photo.DefaultVersionId, false, true);
 					store.Commit (new Photo[] {new_photo, photo});
 					return true;
diff --git a/src/Query/TagConditionWrapper.cs b/src/Query/ConditionWrapper.cs
similarity index 68%
rename from src/Query/TagConditionWrapper.cs
rename to src/Query/ConditionWrapper.cs
index ce6359a..1a6bc76 100644
--- a/src/Query/TagConditionWrapper.cs
+++ b/src/Query/ConditionWrapper.cs
@@ -1,5 +1,5 @@
 /*
- * TagConditionWrapper.cs
+ * ConditionWrapper.cs
  * 
  * Author(s)
  *	Stephane Delcroix  <stephane delcroix org>
@@ -9,11 +9,11 @@
 
 namespace FSpot.Query
 {
-	public class TagConditionWrapper : IQueryCondition
+	public class ConditionWrapper : IQueryCondition
 	{
 		string condition;
 
-		public TagConditionWrapper (string condition)
+		public ConditionWrapper (string condition)
 		{
 			this.condition = condition;
 		}
diff --git a/src/Query/Makefile.am b/src/Query/Makefile.am
index d81fedb..3ad8fc8 100644
--- a/src/Query/Makefile.am
+++ b/src/Query/Makefile.am
@@ -3,6 +3,7 @@ TARGET = library
 LINK = $(REF_FSPOT_QUERY)
 
 SOURCES = \
+	ConditionWrapper.cs \
 	DateRange.cs \
 	FolderSet.cs \
 	IOrderCondition.cs \
@@ -11,7 +12,6 @@ SOURCES = \
 	OrderByTime.cs \
 	RatingRange.cs \
 	RollSet.cs \
-	TagConditionWrapper.cs \
 	UntaggedCondition.cs \
 	Tests/LogicalTermTests.cs
 
diff --git a/src/TagQueryWidget.cs b/src/TagQueryWidget.cs
index a48f12d..ba1c10a 100644
--- a/src/TagQueryWidget.cs
+++ b/src/TagQueryWidget.cs
@@ -680,7 +680,7 @@ namespace FSpot
 				query.TagTerm = null;
 			} else {
 				help.Hide ();
-				query.TagTerm = new TagConditionWrapper (rootTerm.SqlCondition ());
+				query.TagTerm = new ConditionWrapper (rootTerm.SqlCondition ());
 			}
 
 			EventHandler handler = Changed;
diff --git a/src/Widgets/FindBar.cs b/src/Widgets/FindBar.cs
index 0d03fb2..96a0d63 100644
--- a/src/Widgets/FindBar.cs
+++ b/src/Widgets/FindBar.cs
@@ -400,7 +400,7 @@ namespace FSpot.Widgets {
 						root_term = root_parent;
 					}
 					//Log.Debug ("condition = {0}", RootTerm.SqlCondition ());
-					query.TagTerm = new TagConditionWrapper (RootTerm.SqlCondition ());
+					query.TagTerm = new ConditionWrapper (RootTerm.SqlCondition ());
 				} else {
 					query.TagTerm = null;
 					//Log.Debug ("root term is null");



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