Re: Duplicates patch new version - Check box in importing
- From: Alvaro del Castillo <acs openshine com>
- To: Stewart Smith <stewart flamingspork com>
- Cc: f-spot-list gnome org
- Subject: Re: Duplicates patch new version - Check box in importing
- Date: Tue, 04 Oct 2005 06:30:39 +0200
Hi Stewart!
El vie, 30-09-2005 a las 18:45 +1000, Stewart Smith escribió:
> On Wed, 2005-09-28 at 06:04 +0200, Alvaro del Castillo wrote:
> > Some days ago I have modified the Duplicates patch in order to be more
> > user friendly. When you are importing photos you have a new checkbox in
> > the import dialog so you can enable or disable it in order to import or
> > not to import the duplicates photos. You can see it in this screenshot:
>
> After applying this patch, f-spot would crash trying to do database foo.
>
Yes, if you try to use the actual database format it will crash because
the patch needs a new field for the MD5 string. So you need to test the
patch removing your current database. This is a very bad thing because
you can't use F-Spot seriously until the database scheme is maintained
between versions. But F-Spot isn't yet for end user consumption as you
can read in the README, so I have followed this way.
> so, after removing the f-spot database and starting my import again, i
> got an error during import:
This is really strange because I have tested it a lot.
Trying to reproduce your problem:
1. I have created a database with F-Spot 0.1.3 (0.1.3-1ubuntu1).
2. I have tried to use the patched version of F-Spot with this database:
Unhandled Exception: System.NullReferenceException: Object reference not
set to an instance of an object
in <0x00000> <unknown method>
in (wrapper managed-to-native)
Mono.Data.SqliteClient.Sqlite:sqlite_finalize (intptr,intptr&)
in <0x00176> Mono.Data.SqliteClient.SqliteCommand:ExecuteReader
(CommandBehavior behavior, Boolean want_results, System.Int32
rows_affected)
....
3. I have removed the database in order the patched F-Spot doesn't find
the database scheme without the needed field:
rm ~/.gnome2/f-spot/photos.db
4. I have launched the patched F-Spot and try to import some photos and
I have right now exactly the same problem. Time to find the reason:
The problem is updating the photo tags ... and it comes from the fact
that the Duplicate tag isn't created. In my developing environment I
have a database which already had the duplicate tag created in the past
so this is why I haven't found the problem.
I attach a modified patch with the problem solved. Apply it against the
current CVS.
Thanks a lot Stewart for catching the bug and testing the duplicates
patch.
Cheers
>
> Unhandled Exception: System.NullReferenceException: Object reference not
> set to an instance of an object
> in <0x002fa> PhotoStore:Commit (.DbItem item)
> in <0x001f4> ImportCommand:Step ()
> in <0x00191> ImportCommand:DoImport (.ImportBackend imp)
> in <0x000c2> ImportCommand:Start ()
> in <0x00305> ImportCommand:HandleSourceChanged (System.Object sender,
> System.EventArgs args)
> in (wrapper delegate-invoke)
> System.MulticastDelegate:invoke_void_object_EventArgs
> (object,System.EventArgs)
> in <0x00096> GLib.Signal:voidObjectCallback (IntPtr handle, IntPtr gch)
> in (wrapper native-to-managed) GLib.Signal:voidObjectCallback
> (intptr,intptr)
> in <0x00000> <unknown method>
> in (wrapper managed-to-native) Gtk.Dialog:gtk_dialog_run (intptr)
> in <0x0001d> Gtk.Dialog:Run ()
> in <0x0064a> ImportCommand:ImportFromFile (.PhotoStore store,
> System.String path)
> in <0x0005a> MainWindow:HandleImportCommand (System.Object sender,
> System.EventArgs e)
> in (wrapper delegate-invoke)
> System.MulticastDelegate:invoke_void_object_EventArgs
> (object,System.EventArgs)
> in <0x00096> GLib.Signal:voidObjectCallback (IntPtr handle, IntPtr gch)
> in (wrapper native-to-managed) GLib.Signal:voidObjectCallback
> (intptr,intptr)
> in <0x00000> <unknown method>
> in (wrapper managed-to-native) Gtk.Application:gtk_main ()
> in <0x00007> Gtk.Application:Run ()
> in <0x00007> Gnome.Program:Run ()
> in <0x003ea> Driver:Main (System.String[] args)
>
>
> hope this helps.
using System;
using System.Collections;
using System.IO;
using System.Security.Cryptography;
using System.Text;
namespace FSpot {
public delegate void DuplicatesFinderEnd (Boolean success);
public class DuplicatesFinder {
private System.Threading.Thread duplicates_thread = null;
private FSpot.ThreadProgressDialog progress_dialog_duplicates;
private ArrayList duplicates = null;
private Boolean end_duplicates = false;
private uint duplicates_timer = 0;
private System.Threading.Thread md5_thread = null;
private FSpot.ThreadProgressDialog progress_dialog_md5;
private Boolean end_computeMD5 = false;
private uint computeMD5_timer = 0;
// Shared data variables we need to work with
private Db db;
private int[] selected_ids;
private FSpot.PhotoQuery query;
// To inform that the Finder has finished
public event DuplicatesFinderEnd SearchFinished;
public DuplicatesFinder (Db db,
FSpot.PhotoQuery query)
{
this.db = db;
this.query = query;
}
public void CreateDuplicateTag () {
Tag tag_duplicate = db.Tags.Duplicate;
if (tag_duplicate == null) {
Console.WriteLine ("Creating the Duplicate tag ...");
tag_duplicate = db.Tags.CreateTag (null, "Duplicate");
db.Tags.Duplicate = tag_duplicate;
tag_duplicate.StockIconName = "f-spot-hidden.png";
tag_duplicate.SortPriority = -11;
db.Tags.Commit (tag_duplicate);
} else {
Console.WriteLine ("The duplicate tag already exists ...");
}
}
public void startFind (int [] selected_ids) {
this.selected_ids = selected_ids;
md5_thread =
new System.Threading.Thread (new System.Threading.ThreadStart (this.ComputeMD5));
md5_thread.Name = Mono.Posix.Catalog.GetString ("Creating image unique identifiers");
progress_dialog_md5 = new
FSpot.ThreadProgressDialog (md5_thread, selected_ids.Length);
progress_dialog_md5.Start();
StartComputeMD5Timer ();
}
private bool HandleDuplicatesTimer ()
{
Console.WriteLine ("Duplicates Timer ...");
if (end_duplicates || !duplicates_thread.IsAlive) {
if (db.Tags.Duplicate == null) {
CreateDuplicateTag ();
}
end_duplicates = false;
duplicates_timer = 0;
foreach (int num in duplicates) {
Console.WriteLine ("Tagging duplicate photo {0}", num);
query.Photos[num].AddTag (db.Tags.Duplicate);
query.Commit (num);
}
if (SearchFinished != null) {
SearchFinished (true);
}
return false;
}
return true;
}
private void StartDuplicatesTimer ()
{
if (duplicates_timer == 0)
duplicates_timer =
GLib.Timeout.Add (100, new GLib.TimeoutHandler (HandleDuplicatesTimer));
}
private bool HandleComputeMD5Timer ()
{
Console.WriteLine ("MD5 Timer ...");
if (md5_thread.IsAlive) {
Console.WriteLine ("The MD5 thread is alive ...");
}
if (end_computeMD5 || !md5_thread.IsAlive) {
if (progress_dialog_md5 != null) {
progress_dialog_md5.Destroy ();
}
computeMD5_timer = 0;
if (end_computeMD5) {
end_computeMD5 = false;
/* duplicates_thread = new System.Threading.Thread
(new System.Threading.ThreadStart (this.FindDuplicates));
duplicates_thread.Name = Mono.Posix.Catalog.GetString ("Finding Duplicates");
progress_dialog_duplicates =
new FSpot.ThreadProgressDialog (duplicates_thread, selected_ids.Length);
progress_dialog_duplicates.Start (); */
StartDuplicatesTimer ();
lock (this) {
end_duplicates = true;
}
} else {
if (SearchFinished != null) {
SearchFinished (false);
}
}
return false;
}
return true;
}
private void StartComputeMD5Timer ()
{
if (computeMD5_timer == 0)
computeMD5_timer =
GLib.Timeout.Add (1000, new GLib.TimeoutHandler (HandleComputeMD5Timer));
}
public static string PhotoMD5 (Photo photo) {
FileStream fs = new FileStream(photo.Path, FileMode.Open, FileAccess.Read);
MD5 md5ServiceProvider = new MD5CryptoServiceProvider();
byte[] md5 = md5ServiceProvider.ComputeHash(fs);
StringBuilder hash = new StringBuilder();
for (int pos = 0; pos < md5.Length; pos++) {
hash.Append(md5[pos].ToString("X2").ToLower());
}
return hash.ToString ();
}
/* FIXME: We should use a cache of all photos MD5? */
public static bool IsDuplicate (Photo photo) {
Photo[] photos;
photos = MainWindow.Toplevel.Database.Photos.Query (null, null);
if (photos == null) {
Console.WriteLine ("No photos in duplicates ...");
return false;
}
if (photo.MD5Sum == null) {
photo.MD5Sum = PhotoMD5 (photo);
}
bool duplicate = false;
foreach (Photo p in photos) {
if (p.MD5Sum == null) {
p.MD5Sum = PhotoMD5 (p);
}
//Console.WriteLine ("Looking: {0},{1} {2},{3}",
// p.Name, p.MD5Sum, photo.Name, photo.MD5Sum);
if (p.MD5Sum.CompareTo(photo.MD5Sum) == 0 &&
p.Id != photo.Id) {
//Console.WriteLine ("DUPLICATES");
duplicate = true;
break;
}
}
return duplicate;
}
// Executed in a different thread
private void ComputeMD5 () {
// A really simple implementation: Build hash table with MD5 of images
// and we later use it to find duplicates. If the MD5 is in the hash table
// we don't add it. We have only the "original" in this table.
Hashtable photos_md5 = new Hashtable ();
duplicates = new ArrayList ();
int counter = 1;
foreach (int num in selected_ids) {
Photo photo = query.Photos [num];
progress_dialog_md5.Message = System.String.Format
(Mono.Posix.Catalog.GetString ("Creating unique identifier for {0}"), photo.Name);
progress_dialog_md5.Fraction = counter / (double) selected_ids.Length;
progress_dialog_md5.ProgressText = System.String.Format (Mono.Posix.Catalog.GetString ("{0} of {1}"), counter, selected_ids.Length);
if (string.Compare(photo.MD5Sum, "") != 0) {
// It is a duplicate. We should mark it.
if (photos_md5[photo.MD5Sum] != null) {
duplicates.Add (num);
} else {
photos_md5.Add (photo.MD5Sum, num);
}
counter++;
continue;
}
// Computing time is measured for testing purposes
try {
long startTime = DateTime.Now.Ticks;
FileStream fs = new FileStream(photo.Path, FileMode.Open, FileAccess.Read);
MD5 md5ServiceProvider = new MD5CryptoServiceProvider();
byte[] md5 = md5ServiceProvider.ComputeHash(fs);
StringBuilder hash = new StringBuilder();
for (int pos = 0; pos < md5.Length; pos++) {
hash.Append(md5[pos].ToString("X2").ToLower());
}
long endTime = DateTime.Now.Ticks;
TimeSpan timeTaken = new TimeSpan(endTime - startTime);
Console.WriteLine("MD5 compute: {0}", timeTaken.ToString());
photo.MD5Sum = hash.ToString ();
db.Photos.Commit (photo);
counter++;
// It is a duplicate. We should mark it.
if (photos_md5[photo.MD5Sum] != null) {
duplicates.Add (num);
} else {
photos_md5.Add (photo.MD5Sum, num);
}
} catch (Exception ex) {
Console.WriteLine ("Problems creating MD5: {0} ", photo.Path);
Console.WriteLine (ex);
}
}
progress_dialog_md5.Message = Mono.Posix.Catalog.GetString ("Done Creating Unique Identifiers for Photos");
progress_dialog_md5.Fraction = 1.0;
progress_dialog_md5.ProgressText = Mono.Posix.Catalog.GetString ("All unique identifiers created.");
progress_dialog_md5.ButtonLabel = Gtk.Stock.Ok;
lock (this) {
end_computeMD5 = true;
}
}
}
}
Index: src/ImportCommand.cs
===================================================================
RCS file: /cvs/gnome/f-spot/src/ImportCommand.cs,v
retrieving revision 1.39
diff -u -b -B -p -r1.39 ImportCommand.cs
--- src/ImportCommand.cs 22 Aug 2005 10:47:34 -0000 1.39
+++ src/ImportCommand.cs 4 Oct 2005 04:27:22 -0000
@@ -362,6 +365,7 @@ public class ImportCommand : FSpot.Glade
[Glade.Widget] Gtk.ScrolledWindow photo_scrolled;
[Glade.Widget] Gtk.CheckButton attach_check;
[Glade.Widget] Gtk.CheckButton recurse_check;
+ [Glade.Widget] Gtk.CheckButton duplicate_check;
[Glade.Widget] Gtk.Button ok_button;
[Glade.Widget] Gtk.Image tag_image;
[Glade.Widget] Gtk.Label tag_label;
@@ -378,6 +382,11 @@ public class ImportCommand : FSpot.Glade
bool copy;
int total;
+
+ private int duplicates;
+ private long total_md5;
+ private long total_import;
+
PhotoStore store;
FSpot.Delay step;
@@ -390,6 +399,8 @@ public class ImportCommand : FSpot.Glade
{
main_window = mw;
step = new FSpot.Delay (10, new GLib.IdleHandler (Step));
+ total_md5 = 0;
+ total_import = 0;
}
private void HandleDialogResponse (object obj, ResponseArgs args)
@@ -401,12 +412,16 @@ public class ImportCommand : FSpot.Glade
}
}
- private void UpdateProgressBar (int count, int total)
+ private void UpdateProgressBar (int count, int total, int duplicates)
{
if (progress_bar == null)
return;
-
+ if (duplicates > 0) {
+ progress_bar.Text = String.Format ("Importing {0} of {1}, {2} duplicate/s",
+ count-duplicates, total-duplicates, duplicates);
+ } else {
progress_bar.Text = String.Format ("Importing {0} of {1}", count, total);
+ }
progress_bar.Fraction = (double) count / System.Math.Max (total, 1);
}
@@ -431,6 +446,10 @@ public class ImportCommand : FSpot.Glade
Pixbuf thumbnail;
int count;
bool ongoing = true;
+ TimeSpan timeTakenMD5 = new TimeSpan();;
+
+ //Console.WriteLine ("Start importing the photo ...");
+ long startTime = DateTime.Now.Ticks;
if (importer == null)
return false;
@@ -440,14 +459,48 @@ public class ImportCommand : FSpot.Glade
if (thumbnail == null) {
Console.WriteLine ("Could not import file");
} else {
- //icon_scrolled.Visible = true;
+ long startTimeMD5 = DateTime.Now.Ticks;
+ photo.MD5Sum = FSpot.DuplicatesFinder.PhotoMD5 (photo);
+ store.Commit (photo);
+ long endTimeMD5 = DateTime.Now.Ticks;
+ total_md5 += endTimeMD5 - startTimeMD5;
+ timeTakenMD5 = new TimeSpan (endTimeMD5 - startTimeMD5);
+ //Console.WriteLine ("Total time for MD5 {0}", timeTakenMD5.ToString());
+
+ if (FSpot.DuplicatesFinder.IsDuplicate (photo)) {
+ photo.AddTag (MainWindow.Toplevel.Database.Tags.Duplicate);
+ store.Commit (photo);
+ }
+
+ if (FSpot.DuplicatesFinder.IsDuplicate (photo)) {
+ //Console.WriteLine ("Photo: {0} duplicated\n", photo.Name);
+ duplicates++;
+ if (duplicate_check.Active) {
collection.Add (photo);
+ } else {
+ //Console.WriteLine ("Removing duplicate ...");
+ store.Remove (photo);
+ }
+ } else {
+ //Console.WriteLine ("Importing Photo: {0}", photo.Name);
+ collection.Add (photo);
+ }
//grid.AddThumbnail (thumbnail);
- UpdateProgressBar (count, total);
+ if (duplicate_check.Active) {
+ UpdateProgressBar (count, total, 0);
+ } else {
+ UpdateProgressBar (count, total, duplicates);
+ }
thumbnail.Dispose ();
}
+ long endTime = DateTime.Now.Ticks;
+ total_import += endTime - startTime;
+ TimeSpan timeTaken = new TimeSpan(endTime - startTime);
+ //Console.WriteLine ("Total time importing the photo {0} ({1} MD5)\n",
+ // timeTaken.ToString(), timeTakenMD5.ToString ());
+
if (ongoing && total > 0)
return true;
else {
@@ -473,8 +526,9 @@ public class ImportCommand : FSpot.Glade
this.importer = imp;
AllowFinish = false;
+ duplicates = 0;
total = importer.Prepare ();
- UpdateProgressBar (0, total);
+ UpdateProgressBar (0, total, 0);
collection.Clear ();
collection.Capacity = total;
@@ -492,10 +546,20 @@ public class ImportCommand : FSpot.Glade
}
}
+ TimeSpan timeTaken = new TimeSpan(total_import);
+ TimeSpan timeTakenMD5 = new TimeSpan(total_md5);
+ //Console.WriteLine ("Total time importing the photos {0} ({1} MD5)\n",
+ // timeTaken.ToString(), timeTakenMD5.ToString ());
+
FSpot.ThumbnailGenerator.Default.PopBlock ();
- if (importer != null)
+ if (importer != null) {
+ try {
importer.Finish ();
+ } catch (System.Exception e) {
+ Console.WriteLine ("Exception finishing import ..." + e);
+ }
+ }
importer = null;
@@ -619,6 +683,15 @@ public class ImportCommand : FSpot.Glade
this.Start ();
}
+
+ private void HandleDuplicateToggled (object sender, System.EventArgs args)
+ {
+ this.Cancel ();
+ while (Application.EventsPending ())
+ Application.RunIteration ();
+ this.Start ();
+ }
+
public int ImportFromFile (PhotoStore store, string path)
{
this.store = store;
@@ -643,6 +716,7 @@ public class ImportCommand : FSpot.Glade
AllowFinish = false;
recurse_check.Toggled += HandleRecurseToggled;
+ duplicate_check.Toggled += HandleRecurseToggled;
tag_option_menu.Menu = tagmenu;
SourceMenu menu = new SourceMenu ();
@@ -786,7 +860,7 @@ public class ImportCommand : FSpot.Glade
{
Db db = new Db (db_path, true);
- ImportCommand command = new ImportCommand ();
+ ImportCommand command = new ImportCommand (main_window);
command.ImportFromPath (db.Photos, directory_path, true);
Index: src/MainWindow.cs
===================================================================
RCS file: /cvs/gnome/f-spot/src/MainWindow.cs,v
retrieving revision 1.218
diff -u -b -B -p -r1.218 MainWindow.cs
--- src/MainWindow.cs 2 Oct 2005 07:13:38 -0000 1.218
+++ src/MainWindow.cs 4 Oct 2005 04:27:22 -0000
@@ -13,10 +13,11 @@ using System.Text.RegularExpressions;
using LibGPhoto2;
public class MainWindow {
- public static MainWindow Toplevel;
+ public static MainWindow Toplevel = null;
Db db;
+
TagSelectionWidget tag_selection_widget;
[Glade.Widget] Gtk.Window main_window;
[Glade.Widget] Gtk.VBox left_vbox;
@@ -68,6 +69,8 @@ public class MainWindow {
[Glade.Widget] MenuItem remove_tag;
[Glade.Widget] MenuItem find_tag;
+ [Glade.Widget] MenuItem find_duplicates;
+
[Glade.Widget] Scale zoom_scale;
[Glade.Widget] VPaned info_vpaned;
@@ -1686,6 +1689,28 @@ public class MainWindow {
void HandleClearDateRange (object sender, EventArgs args) {
query.Range = null;
}
+
+ void HandleFindDuplicates (object sender, EventArgs args) {
+ find_duplicates.Sensitive = false;
+ FSpot.DuplicatesFinder finder = new FSpot.DuplicatesFinder (db, query);
+ finder.CreateDuplicateTag ();
+ tag_selection_widget.Update ();
+ if (!PhotoSelectionActive()) {
+ icon_view.SelectAllCells ();
+ }
+ System.Console.WriteLine ("Looking for duplicates ...");
+ finder.SearchFinished += new FSpot.DuplicatesFinderEnd (HandleEndDuplicates);
+ finder.startFind (SelectedIds());
+ }
+
+ void HandleEndDuplicates (Boolean success) {
+ if (success) {
+ tag_selection_widget.Select (db.Tags.Duplicate);
+ UpdateQuery ();
+ SetViewMode (ModeType.IconView);
+ }
+ find_duplicates.Sensitive = true;
+ }
// Version Id updates.
Index: src/Makefile.am
===================================================================
RCS file: /cvs/gnome/f-spot/src/Makefile.am,v
retrieving revision 1.43
diff -u -b -B -p -r1.43 Makefile.am
--- src/Makefile.am 29 Sep 2005 10:37:09 -0000 1.43
+++ src/Makefile.am 4 Oct 2005 04:27:22 -0000
@@ -16,6 +16,7 @@ F_SPOT_CSDISTFILES = \
$(srcdir)/Delay.cs \
$(srcdir)/DirectoryAdaptor.cs \
$(srcdir)/DirectoryCollection.cs \
+ $(srcdir)/DuplicatesFinder.cs \
$(srcdir)/Exif.cs \
$(srcdir)/ExifUtils.cs \
$(srcdir)/FlickrExport.cs \
Index: src/PhotoStore.cs
===================================================================
RCS file: /cvs/gnome/f-spot/src/PhotoStore.cs,v
retrieving revision 1.71
diff -u -b -B -p -r1.71 PhotoStore.cs
--- src/PhotoStore.cs 1 Sep 2005 10:01:52 -0000 1.71
+++ src/PhotoStore.cs 4 Oct 2005 04:27:22 -0000
@@ -28,6 +28,7 @@ public class Photo : DbItem, IComparable
return Compare (this, photo);
}
+ // FIXME: With md5sum field this could be easy
public static int Compare (Photo photo1, Photo photo2)
{
int result = photo1.Id.CompareTo (photo2.Id);
@@ -137,6 +138,16 @@ public class Photo : DbItem, IComparable
}
}
+ private string md5sum;
+ public string MD5Sum {
+ get {
+ return md5sum;
+ }
+ set {
+ md5sum = value;
+ }
+ }
+
// Version management
public const int OriginalVersionId = 1;
private uint highest_version_id;
@@ -393,6 +404,7 @@ public class Photo : DbItem, IComparable
this.name = name;
description = "";
+ md5sum = "";
// Note that the original version is never stored in the photo_versions table in the
// database.
@@ -493,7 +505,8 @@ public class PhotoStore : DbStore {
" directory_path STRING NOT NULL, " +
" name STRING NOT NULL, " +
" description TEXT NOT NULL, " +
- " default_version_id INTEGER NOT NULL " +
+ " default_version_id INTEGER NOT NULL, " +
+ " md5sum STRING NOT NULL " +
")";
command.ExecuteNonQuery ();
@@ -538,8 +551,8 @@ public class PhotoStore : DbStore {
command.Connection = Connection;
command.CommandText = String.Format ("INSERT INTO photos (time, " +
- "directory_path, name, description, default_version_id) " +
- " VALUES ({0}, '{1}', '{2}', '{3}', {4}) ",
+ "directory_path, name, description, default_version_id, md5sum) " +
+ " VALUES ({0}, '{1}', '{2}', '{3}', {4}, '') ",
unix_time,
SqlString (System.IO.Path.GetDirectoryName (path)),
SqlString (System.IO.Path.GetFileName (path)),
@@ -728,7 +741,8 @@ public class PhotoStore : DbStore {
" directory_path, " +
" name, " +
" description, " +
- " default_version_id " +
+ " default_version_id, " +
+ " md5sum " +
" FROM photos " +
" WHERE id = {0} ",
id);
@@ -742,6 +756,7 @@ public class PhotoStore : DbStore {
photo.Description = reader[3].ToString ();
photo.DefaultVersionId = Convert.ToUInt32 (reader[4]);
+ photo.MD5Sum = reader[5].ToString ();
AddToCache (photo);
}
@@ -895,11 +910,13 @@ public class PhotoStore : DbStore {
SqliteCommand command = new SqliteCommand ();
command.Connection = Connection;
- command.CommandText = String.Format ("UPDATE photos SET description = '{0}', " +
- " default_version_id = {1} " +
- " WHERE id = {2}",
+ command.CommandText = String.Format ("UPDATE photos SET description = '{0}'," +
+ " default_version_id = {1}," +
+ " md5sum = '{2}'"+
+ " WHERE id = {3}",
SqlString (photo.Description),
photo.DefaultVersionId,
+ SqlString (photo.MD5Sum),
photo.Id);
command.ExecuteNonQuery ();
command.Dispose ();
@@ -913,6 +930,7 @@ public class PhotoStore : DbStore {
command.Dispose ();
foreach (Tag tag in photo.Tags) {
+
command = new SqliteCommand ();
command.Connection = Connection;
command.CommandText = String.Format ("INSERT INTO photo_tags (photo_id, tag_id) " +
@@ -1004,6 +1022,7 @@ public class PhotoStore : DbStore {
photo.Description = reader[4].ToString ();
photo.DefaultVersionId = Convert.ToUInt32 (reader[5]);
+ photo.MD5Sum = reader[6].ToString ();
version_list.Add (photo);
}
@@ -1043,7 +1062,8 @@ public class PhotoStore : DbStore {
" photos.directory_path, " +
" photos.name, " +
" photos.description, " +
- " photos.default_version_id " +
+ " photos.default_version_id, " +
+ " photos.md5sum " +
" FROM photos " +
" WHERE directory_path = \"{0}\"", dir.FullName);
@@ -1084,7 +1104,8 @@ public class PhotoStore : DbStore {
" photos.directory_path, " +
" photos.name, " +
" photos.description, " +
- " photos.default_version_id " +
+ " photos.default_version_id, " +
+ " photos.md5sum " +
" FROM photos ");
if (range != null) {
Index: src/TagStore.cs
===================================================================
RCS file: /cvs/gnome/f-spot/src/TagStore.cs,v
retrieving revision 1.19
diff -u -b -B -p -r1.19 TagStore.cs
--- src/TagStore.cs 27 Sep 2005 03:15:05 -0000 1.19
+++ src/TagStore.cs 4 Oct 2005 04:27:22 -0000
@@ -257,6 +257,16 @@ public class TagStore : DbStore {
}
}
+ private Tag duplicate;
+ public Tag Duplicate {
+ get {
+ return duplicate;
+ }
+ set {
+ duplicate = value;
+ }
+ }
+
// In this store we keep all the items (i.e. the tags) in memory at all times. This is
// mostly to simplify handling of the parent relationship between tags, but it also makes it
// a little bit faster. We achieve this by passing "true" as the cache_is_immortal to our
@@ -290,6 +300,9 @@ public class TagStore : DbStore {
if (tag.Name == "Hidden")
hidden = tag;
+
+ if (tag.Name == "Duplicate")
+ duplicate = tag;
}
reader.Close ();
@@ -354,6 +367,12 @@ public class TagStore : DbStore {
this.hidden = hidden_tag;
Commit (hidden_tag);
+ Tag duplicate_tag = CreateTag (RootCategory, "Duplicate");
+ duplicate_tag.StockIconName = "f-spot-hidden.png";
+ duplicate_tag.SortPriority = -11;
+ this.duplicate = duplicate_tag;
+ Commit (duplicate_tag);
+
Tag people_category = CreateCategory (RootCategory, "People");
people_category.StockIconName = "f-spot-people.png";
people_category.SortPriority = -8;
@@ -455,6 +474,11 @@ public class TagStore : DbStore {
category.Children.Length > 0)
throw new InvalidTagOperationException (category, "Cannot remove category that contains children");
+ // FIXME: Hack!
+ if (string.Compare (((Tag) item).Name, "Duplicate") == 0) {
+ duplicate = null;
+ }
+
RemoveFromCache (item);
((Tag)item).Category = null;
Index: src/f-spot.glade
===================================================================
RCS file: /cvs/gnome/f-spot/src/f-spot.glade,v
retrieving revision 1.109
diff -u -b -B -p -r1.109 f-spot.glade
--- src/f-spot.glade 3 Oct 2005 22:36:36 -0000 1.109
+++ src/f-spot.glade 4 Oct 2005 04:27:23 -0000
@@ -7129,6 +7129,15 @@ Photo Details</property>
</child>
<child>
+ <widget class="GtkMenuItem" id="find_duplicates">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">_Find Duplicates</property>
+ <property name="use_underline">True</property>
+ <signal name="activate" handler="HandleFindDuplicates" last_modification_time="Tue, 10 Aug 2004 07:08:24 GMT"/>
+ </widget>
+ </child>
+
+ <child>
<widget class="GtkSeparatorMenuItem" id="separator15">
<property name="visible">True</property>
</widget>
@@ -9841,6 +9850,12 @@ Photo Details</property>
<property name="spacing">6</property>
<child>
+ <widget class="GtkHBox" id="hbox70">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">0</property>
+
+ <child>
<widget class="GtkCheckButton" id="recurse_check">
<property name="visible">True</property>
<property name="can_focus">True</property>
@@ -9851,6 +9866,32 @@ Photo Details</property>
<property name="active">True</property>
<property name="inconsistent">False</property>
<property name="draw_indicator">True</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkCheckButton" id="duplicate_check">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="label" translatable="yes">Include duplicates.</property>
+ <property name="use_underline">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="focus_on_click">True</property>
+ <property name="active">False</property>
+ <property name="inconsistent">False</property>
+ <property name="draw_indicator">True</property>
+ </widget>
+ <packing>
+ <property name="padding">10</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
</widget>
<packing>
<property name="padding">0</property>
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]