f-spot r4289 - in trunk: . src src/Query src/Widgets



Author: sdelcroix
Date: Mon Aug 25 12:17:42 2008
New Revision: 4289
URL: http://svn.gnome.org/viewvc/f-spot?rev=4289&view=rev

Log:
Merge branch '02'


Added:
   trunk/src/Query/IOrderCondition.cs
   trunk/src/Query/OrderByTime.cs
Modified:
   trunk/ChangeLog
   trunk/src/DirectoryAdaptor.cs
   trunk/src/GroupAdaptor.cs
   trunk/src/MainWindow.cs
   trunk/src/Makefile.am
   trunk/src/PhotoQuery.cs
   trunk/src/PhotoStore.cs
   trunk/src/Query/DateRange.cs
   trunk/src/SendEmail.cs
   trunk/src/TagCommands.cs
   trunk/src/TimeAdaptor.cs
   trunk/src/Widgets/PreviewPopup.cs
   trunk/src/Widgets/TrayView.cs

Modified: trunk/src/DirectoryAdaptor.cs
==============================================================================
--- trunk/src/DirectoryAdaptor.cs	(original)
+++ trunk/src/DirectoryAdaptor.cs	Mon Aug 25 12:17:42 2008
@@ -109,7 +109,7 @@
 
 		public override FSpot.IBrowsableItem PhotoFromIndex (int item) 
 		{
-			return query.Items [LookupItem (item)];
+			return query [LookupItem (item)];
 		}
 
 		private int LookupItem (int group)

Modified: trunk/src/GroupAdaptor.cs
==============================================================================
--- trunk/src/GroupAdaptor.cs	(original)
+++ trunk/src/GroupAdaptor.cs	Mon Aug 25 12:17:42 2008
@@ -45,20 +45,19 @@
 
 		protected void HandleQueryChanged (IBrowsableCollection sender)
 		{
-			Log.Debug ("GroupAdaptor::Reloading" );
 			Reload ();
 		}
 
 		public void Dispose ()
 		{
-			this.query.PreChanged -= HandleQueryChanged; 
+			this.query.Changed -= HandleQueryChanged;
 		}
 
 		protected GroupAdaptor (PhotoQuery query, bool order_ascending)
 		{
 			this.order_ascending = order_ascending;
 			this.query = query;
-			this.query.PreChanged += HandleQueryChanged;
+			this.query.Changed += HandleQueryChanged;
 
 			Reload (); 
 		}

Modified: trunk/src/MainWindow.cs
==============================================================================
--- trunk/src/MainWindow.cs	(original)
+++ trunk/src/MainWindow.cs	Mon Aug 25 12:17:42 2008
@@ -546,7 +546,7 @@
 		get {
 			int active = ActiveIndex ();
 			if (active >= 0)
-				return query.Photos [active];
+				return query [active] as Photo;
 			else
 				return null;
 		}
@@ -866,7 +866,7 @@
 	
 		int i = 0;
 		foreach (int num in selected_ids)
-			photo_list [i ++] = query.Photos [num];
+			photo_list [i ++] = query [num] as Photo;
 		
 		return photo_list;
 	}
@@ -876,6 +876,7 @@
 		return SelectedPhotos (SelectedIds ());
 	}
 
+	[Obsolete ("MARKED FOR REMOVAL")]
 	public Photo [] ActivePhotos () 
 	{
 		return query.Photos;
@@ -930,7 +931,7 @@
 	public void AddTagExtended (int [] nums, Tag [] tags)
 	{
 		foreach (int num in nums)
-			query.Photos [num].AddTag (tags);
+			(query[num] as Photo).AddTag (tags);
 		query.Commit (nums);
 
 		foreach (Tag t in tags) {
@@ -939,7 +940,7 @@
 			// FIXME this needs a lot more work.
 			Pixbuf icon = null;
 			try {
-				Pixbuf tmp = FSpot.PhotoLoader.LoadAtMaxSize (query.Items [nums[0]], 128, 128);
+				Pixbuf tmp = FSpot.PhotoLoader.LoadAtMaxSize (query [nums[0]], 128, 128);
 				icon = PixbufUtils.TagIconFromPixbuf (tmp);
 				tmp.Dispose ();
 			} catch {
@@ -954,7 +955,7 @@
 	public void RemoveTags (int [] nums, Tag [] tags)
 	{
 		foreach (int num in nums)
-			query.Photos [num].RemoveTag (tags);
+			(query[num] as Photo).RemoveTag (tags);
 		query.Commit (nums);
 	}
 
@@ -1150,7 +1151,7 @@
 		
 		FSpot.TimeAdaptor time_adaptor = group_selector.Adaptor as FSpot.TimeAdaptor;
 		if (time_adaptor != null)
-			JumpTo (time_adaptor.LookupItem (time));
+			JumpTo (query.LookupItem (time));
 	}
 
 	private void JumpTo (int index)
@@ -1189,7 +1190,7 @@
 		if (cell_num == -1 /*|| cell_num == lastTopLeftCell*/)
 			return;
 
-		FSpot.IBrowsableItem photo = icon_view.Collection.Items [cell_num];
+		FSpot.IBrowsableItem photo = icon_view.Collection [cell_num];
 #if false
 		group_selector.Adaptor.GlassSet -= HandleAdaptorGlassSet;
 		group_selector.Adaptor.SetGlass (group_selector.Adaptor.IndexFromPhoto (photo));
@@ -1586,7 +1587,7 @@
 		db.BeginTransaction ();
 		int [] selected_photos = SelectedIds ();
 		foreach (int num in selected_photos) {
-			p = query.Photos [num];
+			p = query [num] as Photo;
 			p.Rating = (uint) r;
 		}
 		query.Commit (selected_photos);
@@ -1872,7 +1873,7 @@
 			return;
 		
 		group_selector.Adaptor.OrderAscending = item.Active;
-		query.RequestReload ();
+		query.TimeOrderAsc = item.Active;
 
 		// FIXME this is blah...we need UIManager love here
 		if (item != reverse_order)
@@ -2256,12 +2257,14 @@
 		
 		clear_date_range.Sensitive = (query.Range != null);
 		clear_rating_filter.Sensitive = (query.RatingRange != null);
-		UpdateStatusLabel ();
+		update_status_label = true;
+		GLib.Idle.Add (UpdateStatusLabel);
 	}
 
-	private void UpdateStatusLabel ()
+	bool update_status_label;
+	private bool UpdateStatusLabel ()
 	{
-		//uint timer = Log.DebugTimerStart ();
+		update_status_label = false;
 		int total_photos = Database.Photos.TotalPhotos;
 		if (total_photos != query.Count)
 			status_label.Text = String.Format (Catalog.GetPluralString ("{0} Photo out of {1}", "{0} Photos out of {1}", query.Count), query.Count, total_photos);
@@ -2271,7 +2274,7 @@
 		if ((selection != null) && (selection.Count > 0))
 			status_label.Text += String.Format (Catalog.GetPluralString (" ({0} selected)", " ({0} selected)", selection.Count), selection.Count);
 		status_label.UseMarkup = true;
-		//Log.DebugTimerPrint (timer, "UpdateStatusLabel took {0}");
+		return update_status_label;
 	}
 	
 	void HandleZoomChanged (object sender, System.EventArgs args)
@@ -2402,9 +2405,9 @@
 									   MessageType.Warning, 
 									   header, msg, ok_caption)) {                              
 			
+			uint timer = Log.DebugTimerStart ();
 			foreach (Photo photo in photos) {
 				foreach (uint id in photo.VersionIds) {
-					Console.WriteLine (" path == {0}", photo.VersionUri (id).LocalPath);
 					try {
 						photo.DeleteVersion (id, true);
 					} catch (Exception e) {
@@ -2415,6 +2418,7 @@
 			db.Photos.Remove (photos);
 			
 			UpdateQuery ();
+			Log.DebugTimerPrint (timer, "HandleDeleteCommand took {0}");
 		}
 	}
 
@@ -2489,7 +2493,7 @@
 		Db db = MainWindow.Toplevel.Database;
 		FSpot.PhotoQuery count_query = new FSpot.PhotoQuery(db.Photos);
 		count_query.Terms = FSpot.OrTerm.FromTags(tags);
-		int associated_photos = count_query.Photos.Length;
+		int associated_photos = count_query.Count;
 
 		string header;
 		if (tags.Length == 1)

Modified: trunk/src/Makefile.am
==============================================================================
--- trunk/src/Makefile.am	(original)
+++ trunk/src/Makefile.am	Mon Aug 25 12:17:42 2008
@@ -37,8 +37,10 @@
 
 QUERY_CSDISTFILES =				\
 	$(srcdir)/Query/DateRange.cs		\
+	$(srcdir)/Query/IOrderCondition.cs	\
 	$(srcdir)/Query/IQueryCondition.cs	\
 	$(srcdir)/Query/LogicalTerm.cs		\
+	$(srcdir)/Query/OrderByTime.cs		\
 	$(srcdir)/Query/RatingRange.cs		\
 	$(srcdir)/Query/RollSet.cs		\
 	$(srcdir)/Query/UntaggedCondition.cs

Modified: trunk/src/PhotoQuery.cs
==============================================================================
--- trunk/src/PhotoQuery.cs	(original)
+++ trunk/src/PhotoQuery.cs	Mon Aug 25 12:17:42 2008
@@ -12,17 +12,70 @@
 using System.Collections;
 using System.Collections.Generic;
 using FSpot.Query;
+using FSpot.Utils;
 
 namespace FSpot {
 	public class PhotoQuery : FSpot.IBrowsableCollection {
-		private Photo [] photos;
+		class PhotoCache
+		{
+			static int SIZE = 100;
+			public int Size {
+				get { return SIZE; }
+			}
+
+			Dictionary <int, Photo []> cache;
+			string temp_table;
+			PhotoStore store;
+
+			public PhotoCache (PhotoStore store, string temp_table)
+			{
+				this.temp_table = temp_table;
+				this.store = store;
+				cache = new Dictionary<int, Photo[]> ();
+			}
+
+			public bool TryGetPhoto (int index, out Photo photo)
+			{
+				photo = null;
+				Photo [] val;
+				int offset = index - index % SIZE;
+				if (!cache.TryGetValue (offset, out val))
+					return false;
+				photo = val [index - offset];
+				return true;
+			}
+
+			public Photo Get (int index)
+			{
+				Photo [] val;
+				int offset = index - index % SIZE;
+				if (!cache.TryGetValue (offset, out val)) {
+					val = store.QueryFromTemp (temp_table, offset, SIZE);
+					cache [offset] = val;
+				}
+				return val [index - offset];
+			}
+		}
+
+		PhotoCache cache;
 		private PhotoStore store;
 		private Term terms;
 		private Tag [] tags;
 		private string extra_condition;
+
+		static int query_count = 0;
+		static int QueryCount {
+			get {return query_count ++;}
+		}
+
+		Dictionary<uint, int> reverse_lookup;
+
+		int count = -1;
 		
+		string temp_table = String.Format ("photoquery_temp_{0}", QueryCount);
+
 		// Constructor
-		public PhotoQuery (PhotoStore store)
+		public PhotoQuery (PhotoStore store, params IQueryCondition [] conditions)
 		{
 			this.store = store;
 			// Note: this is to let the query pick up
@@ -30,12 +83,22 @@
 			this.store.ItemsAddedOverDBus += delegate { RequestReload(); };
 			this.store.ItemsRemovedOverDBus += delegate { RequestReload(); };
 			this.store.ItemsChanged += MarkChanged;
+			cache = new PhotoCache (store, temp_table);
+			reverse_lookup = new Dictionary<uint, int> ();
+			SetCondition (OrderByTime.OrderByTimeDesc);
+
+			foreach (IQueryCondition condition in conditions)
+				SetCondition (condition);
 
-			photos = store.Query ((Tag [])null, null, Range, RollSet, RatingRange);
+			store.QueryToTemp (temp_table, (Tag [])null, null, Range, RollSet, RatingRange, OrderByTime);
 		}
 
 		public int Count {
-			get { return photos.Length;}
+			get {
+				if (count < 0)
+					count = store.Count (temp_table);
+				return count;
+			}
 		}
 		
 		public bool Contains (IBrowsableItem item) {
@@ -44,26 +107,26 @@
 
 		// IPhotoCollection Interface
 		public event FSpot.IBrowsableCollectionChangedHandler Changed;
-		public event FSpot.IBrowsableCollectionChangedHandler PreChanged;
 		public event FSpot.IBrowsableCollectionItemsChangedHandler ItemsChanged;
 		
 		public IBrowsableItem this [int index] {
-			get { return photos [index]; }
+			get { return cache.Get (index); }
 		}
 
+		[Obsolete ("DO NOT USE THIS, IT'S TOO SLOW")]
 		public Photo [] Photos {
-			get { return photos; }
+			get { return store.QueryFromTemp (temp_table); }
 		}
 
+		[Obsolete ("DO NOT USE Items on PhotoQuery")]
 		public IBrowsableItem [] Items {
-			get { return (IBrowsableItem [])photos; }
+			get { throw new NotImplementedException (); }
 		}
-		
+
 		public PhotoStore Store {
 			get { return store; }
 		}
 		
-
 		//Query Conditions
 		private Dictionary<Type, IQueryCondition> conditions;
 		private Dictionary<Type, IQueryCondition> Conditions {
@@ -84,11 +147,11 @@
 			return true;
 		}
 
-		internal IQueryCondition GetCondition<T> ()
+		internal T GetCondition<T> () where T : IQueryCondition
 		{
-			if (Conditions.ContainsKey (typeof (T)))
-				return Conditions [typeof (T)];
-			return null;
+			IQueryCondition val;
+			Conditions.TryGetValue (typeof (T), out val);
+			return (T)val;
 		}
 
 		internal bool UnSetCondition<T> ()
@@ -129,7 +192,7 @@
  		}
 		
 		public DateRange Range {
-			get { return GetCondition<DateRange> () as DateRange; }
+			get { return GetCondition<DateRange> (); }
 			set {
 				if (value == null && UnSetCondition<DateRange> () || value != null && SetCondition (value))
 					RequestReload ();
@@ -150,7 +213,7 @@
 		}
 
 		public RollSet RollSet {
-			get { return GetCondition<RollSet> () as RollSet; }
+			get { return GetCondition<RollSet> (); }
 			set {
 				if (value == null && UnSetCondition<RollSet> () || value != null && SetCondition (value))
 					RequestReload ();
@@ -158,33 +221,107 @@
 		}
 
 		public RatingRange RatingRange {
-			get { return GetCondition<RatingRange> () as RatingRange; }
+			get { return GetCondition<RatingRange> (); }
 			set {
 				if (value == null && UnSetCondition<RatingRange>() || value != null && SetCondition (value))
 					RequestReload ();
 			}
 		}
 
+		public OrderByTime OrderByTime {
+			get { return GetCondition<OrderByTime> (); }
+			set {
+				if (value != null && SetCondition (value))
+					RequestReload ();
+			}
+		}
+
+		public bool TimeOrderAsc {
+			get { return OrderByTime.Asc; }
+			set {
+				if (value != OrderByTime.Asc)
+					OrderByTime = new OrderByTime (value);
+			}
+		}
+
 		public void RequestReload ()
 		{
+			uint timer = Log.DebugTimerStart ();
 			if (untagged)
-				photos = store.Query (new UntaggedCondition (), Range, RollSet, RatingRange);
+				store.QueryToTemp (temp_table, new UntaggedCondition (), Range, RollSet, RatingRange, OrderByTime);
 			else
-				photos = store.Query (terms, extra_condition, Range, RollSet, RatingRange);
+				store.QueryToTemp (temp_table, terms, extra_condition, Range, RollSet, RatingRange, OrderByTime);
 
-			//this event will allow resorting the query content
-			if (PreChanged != null)
-				PreChanged (this);
+			count = -1;
+			cache = new PhotoCache (store, temp_table);
+			reverse_lookup = new Dictionary<uint,int> ();
 
 			if (Changed != null)
 				Changed (this);
+			Log.DebugTimerPrint (timer, "Reloading the query took {0}");
 		}
 		
 		public int IndexOf (IBrowsableItem photo)
 		{
-			return System.Array.IndexOf (photos, photo);
+			if (photo == null || !(photo is Photo))
+				return -1;
+			return store.IndexOf (temp_table, photo as Photo);
+		}
+
+		private int [] IndicesOf (DbItem [] dbitems)
+		{
+			uint timer = Log.DebugTimerStart ();
+			List<int> indices = new List<int> ();
+			List<uint> items_to_search = new List<uint> ();
+			int cur;
+			foreach (DbItem dbitem in dbitems) {
+				if (reverse_lookup.TryGetValue (dbitem.Id, out cur))
+					indices.Add (cur);
+				else
+					items_to_search.Add (dbitem.Id);
+			}
+
+			if (items_to_search.Count > 0)
+				indices.AddRange (store.IndicesOf (temp_table, items_to_search.ToArray ()));
+			Log.DebugTimerPrint (timer, "IndicesOf took {0}");
+			return indices.ToArray ();
+		}
+
+		public int LookupItem (System.DateTime date)
+		{
+			return LookupItem (date, TimeOrderAsc);
+		}
+
+		private int LookupItem (System.DateTime date, bool asc)
+		{
+			uint timer = Log.DebugTimerStart ();
+			int low = 0;
+			int high = Count - 1;
+			int mid = (low + high) / 2;
+			Photo current;
+			while (low <= high) {
+				mid = (low + high) / 2;
+				if (!cache.TryGetPhoto (mid, out current))
+					//the item we're looking for is not in the cache
+					//a binary search could take up to ln2 (N/cache.SIZE) request
+					//lets reduce that number to 1
+					return store.IndexOf (temp_table, date, asc);
+
+				int comp = this [mid].Time.CompareTo (date);
+				if (!asc && comp < 0 || asc && comp > 0)
+					high = mid - 1;
+				else if (!asc && comp > 0 || asc && comp < 0)
+					low = mid + 1;
+				else
+					return mid;
+			}
+			Log.DebugTimerPrint (timer, "LookupItem took {0}");
+			if (asc)
+				return this[mid].Time < date ? mid + 1 : mid;
+			return this[mid].Time > date ? mid + 1 : mid;
+
 		}
-		
+
 		public void Commit (int index)
 		{
 			Commit (new int [] {index});
@@ -193,25 +330,21 @@
 		public void Commit (int [] indexes)
 		{
 			List<Photo> to_commit = new List<Photo>();
-			foreach (int index in indexes)
-				to_commit.Add (photos [index]);
+			foreach (int index in indexes) {
+				to_commit.Add (this [index] as Photo);
+				reverse_lookup [(this [index] as Photo).Id] = index;
+			}
 			store.Commit (to_commit.ToArray ());
 		}
 
 		private void MarkChanged (object sender, DbItemEventArgs args)
 		{
-			List<int> indexes = new List<int>();
-			foreach (DbItem item in args.Items) {
-				Photo photo = item as Photo;
-				int index = IndexOf (photo);
-
-				// Ignore photos that are not in the query
-				if (index > -1) 
-					indexes.Add (index);
-			}
+			int [] indexes = IndicesOf (args.Items);
+
+			PhotoEventArgs photo_args = args as PhotoEventArgs;
 
-			if (indexes.Count > 0 && ItemsChanged != null)
-				ItemsChanged (this, new BrowsableEventArgs(indexes.ToArray (), (args as PhotoEventArgs).Changes));
+			if (indexes.Length > 0 && ItemsChanged != null)
+				ItemsChanged (this, new BrowsableEventArgs(indexes, (args as PhotoEventArgs).Changes));
 		}
 
 		public void MarkChanged (int index, IBrowsableItemChanges changes)

Modified: trunk/src/PhotoStore.cs
==============================================================================
--- trunk/src/PhotoStore.cs	(original)
+++ trunk/src/PhotoStore.cs	Mon Aug 25 12:17:42 2008
@@ -529,6 +529,123 @@
 		 	ItemsRemovedOverDBus (this, new DbItemEventArgs (photos)); 
 	}
 
+	public int Count (string table_name, params IQueryCondition [] conditions)
+	{
+		StringBuilder query_builder = new StringBuilder ("SELECT COUNT(*) FROM " + table_name + " ");
+		bool where_added = false;
+		foreach (IQueryCondition condition in conditions) {
+			if (condition == null)
+				continue;
+			if (condition is IOrderCondition)
+				continue;
+			query_builder.Append (where_added ? " AND " : " WHERE ");
+			query_builder.Append (condition.SqlClause ());
+			where_added = true;
+		}
+
+		SqliteDataReader reader = Database.Query (query_builder.ToString());
+		reader.Read ();
+		int count = Convert.ToInt32 (reader [0]);
+		reader.Close();
+		return count;
+	}
+
+	public int [] IndicesOf (string table_name, uint [] items)
+	{
+		StringBuilder query_builder = new StringBuilder ("SELECT ROWID FROM ");
+		query_builder.Append (table_name);
+		query_builder.Append (" WHERE \"photos.id\" IN (");
+		for (int i = 0; i < items.Length; i++) {
+			query_builder.Append (items [i]);
+			query_builder.Append ((i != items.Length - 1) ? ", " : ")" );
+		}
+		return IndicesOf (query_builder.ToString ());
+	}
+
+	public int IndexOf (string table_name, Photo photo)
+	{
+		string query = String.Format ("SELECT ROWID FROM {0} WHERE \"photos.id\" = {1}", table_name, photo.Id);
+		return IndexOf (query);
+	}
+
+	public int IndexOf (string table_name, DateTime time, bool asc)
+	{
+		string query = String.Format ("SELECT ROWID FROM {0} WHERE \"photos.time\" {2} {1} ORDER BY \"photos.time\" {3} LIMIT 1",
+				table_name,
+				DbUtils.UnixTimeFromDateTime (time),
+				asc ? ">=" : "<=",
+				asc ? "ASC" : "DESC");
+		return IndexOf (query);
+	}
+
+	private int IndexOf (string query)
+	{
+		uint timer = Log.DebugTimerStart ();
+		SqliteDataReader reader = Database.Query (query);
+		int index = - 1;
+		if (reader.Read ())
+			index = Convert.ToInt32 (reader [0]);
+		reader.Close();
+		Log.DebugTimerPrint (timer, "IndexOf took {0} : " + query);
+		return index - 1; //ROWID starts counting at 1
+	}
+
+	private int [] IndicesOf (string query)
+	{
+		uint timer = Log.DebugTimerStart ();
+		List<int> list = new List<int> ();
+		SqliteDataReader reader = Database.Query (query);
+		while (reader.Read ())
+			list.Add (Convert.ToInt32 (reader [0]) - 1);
+		Log.DebugTimerPrint (timer, "IndicesOf took {0} : " + query);
+		return list.ToArray ();
+	}
+
+	public Dictionary<int,int[]> PhotosPerMonth (params IQueryCondition [] conditions)
+	{
+		uint timer = Log.DebugTimerStart ();
+		Dictionary<int, int[]> val = new Dictionary<int, int[]> ();
+
+		//Sqlite is way more efficient querying to a temp then grouping than grouping at once
+		Database.ExecuteNonQuery ("DROP TABLE IF EXISTS POPULATION");
+		StringBuilder query_builder = new StringBuilder ("CREATE TEMP TABLE population AS SELECT strftime('%Y%m', datetime(time, 'unixepoch')) AS month FROM photos");
+		bool where_added = false;
+		foreach (IQueryCondition condition in conditions) {
+			if (condition == null)
+				continue;
+			if (condition is IOrderCondition)
+				continue;
+			query_builder.Append (where_added ? " AND " : " WHERE ");
+			query_builder.Append (condition.SqlClause ());
+			where_added = true;
+		}
+		Database.ExecuteNonQuery (query_builder.ToString ());
+
+		int minyear = Int32.MaxValue;
+		int maxyear = Int32.MinValue;
+
+		SqliteDataReader reader = Database.Query ("SELECT COUNT (*), month from population GROUP BY month");
+		while (reader.Read ()) {
+			string yyyymm = reader [1].ToString ();
+			int count = Convert.ToInt32 (reader [0]);
+			int year = Convert.ToInt32 (yyyymm.Substring (0,4));
+			maxyear = Math.Max (year, maxyear);
+			minyear = Math.Min (year, minyear);
+			int month = Convert.ToInt32 (yyyymm.Substring (4));
+			if (!val.ContainsKey (year))
+				val.Add (year, new int[12]);
+			val[year][month-1] = count;
+		}
+		reader.Close ();
+
+		//Fill the blank
+		for (int i = minyear; i <= maxyear; i++)
+			if (!val.ContainsKey (i))
+				val.Add (i, new int[12]);
+
+		Log.DebugTimerPrint (timer, "PhotosPerMonth took {0}");
+		return val;
+	}
 
 	// Queries.
 	[Obsolete ("drop this, use IQueryCondition correctly instead")]
@@ -541,16 +658,78 @@
 		StringBuilder query_builder = new StringBuilder ("SELECT * FROM photos ");
 		
 		bool where_added = false;
-		foreach (IQueryCondition condition in conditions)
-			if (condition != null) {
-				query_builder.Append (where_added ? " AND " : " WHERE ");
-				query_builder.Append (condition.SqlClause ());
-				where_added = true;
-			}
-		query_builder.Append(" ORDER BY time ");
+		foreach (IQueryCondition condition in conditions) {
+			if (condition == null)
+				continue;
+			if (condition is IOrderCondition)
+				continue;
+			query_builder.Append (where_added ? " AND " : " WHERE ");
+			query_builder.Append (condition.SqlClause ());
+			where_added = true;
+		}
+
+		bool order_added = false;
+		foreach (IQueryCondition condition in conditions) {
+			if (condition == null)
+				continue;
+			if (!(condition is IOrderCondition))
+				continue;
+			query_builder.Append (order_added ? " , " : "ORDER BY ");
+			query_builder.Append (condition.SqlClause ());
+			order_added = true;
+		}
 		return Query (query_builder.ToString ());
 	}
 
+	public void QueryToTemp (string temp_table, params IQueryCondition [] conditions)
+	{
+		StringBuilder query_builder = new StringBuilder ("SELECT * FROM photos ");
+
+		bool where_added = false;
+		foreach (IQueryCondition condition in conditions) {
+			if (condition == null)
+				continue;
+			if (condition is IOrderCondition)
+				continue;
+			query_builder.Append (where_added ? " AND " : " WHERE ");
+			query_builder.Append (condition.SqlClause ());
+			where_added = true;
+		}
+
+		bool order_added = false;
+		foreach (IQueryCondition condition in conditions) {
+			if (condition == null)
+				continue;
+			if (!(condition is IOrderCondition))
+				continue;
+			query_builder.Append (order_added ? " , " : "ORDER BY ");
+			query_builder.Append (condition.SqlClause ());
+			order_added = true;
+		}
+		QueryToTemp (temp_table, query_builder.ToString ());
+	}
+
+	public void QueryToTemp(string temp_table, string query)
+	{
+		uint timer = Log.DebugTimerStart ();
+		Database.BeginTransaction ();
+		Database.ExecuteNonQuery (String.Format ("DROP TABLE IF EXISTS {0}", temp_table));
+		//Database.ExecuteNonQuery (String.Format ("CREATE TEMPORARY TABLE {0} AS {1}", temp_table, query));
+		Database.Query (String.Format ("CREATE TEMPORARY TABLE {0} AS {1}", temp_table, query)).Close ();
+		Database.CommitTransaction ();
+		Log.DebugTimerPrint (timer, "QueryToTemp took {0} : " + query);
+	}
+
+	public Photo [] QueryFromTemp (string temp_table)
+	{
+		return QueryFromTemp (temp_table, 0, -1);
+	}
+
+	public Photo [] QueryFromTemp (string temp_table, int offset, int limit)
+	{
+		return Query (String.Format ("SELECT * FROM {0} LIMIT {1} OFFSET {2}", temp_table, limit, offset));
+	}
+
 	public Photo [] Query (string query)
 	{
 		return Query (new DbCommand (query));
@@ -558,7 +737,7 @@
 
 	public Photo [] Query (DbCommand query)
 	{
-		uint timer = Log.DebugTimerStart ("Query: " + query.CommandText);
+		uint timer = Log.DebugTimerStart ();
 		SqliteDataReader reader = Database.Query(query);
 
 		List<Photo> new_photos = new List<Photo> ();
@@ -604,7 +783,7 @@
 		foreach (Photo photo in new_photos)
 			photo.Changes = null;
 
-		Log.DebugTimerPrint (timer, "Query took {0}");
+ 		Log.DebugTimerPrint (timer, "Query took {0} : " + query.CommandText);
 		return query_result.ToArray ();
 	}
 
@@ -650,12 +829,88 @@
 	}
 
 	[Obsolete ("drop this, use IQueryCondition correctly instead")]
+	public void QueryToTemp (string temp_table, Tag [] tags, string extra_condition, DateRange range, RollSet importidrange, RatingRange ratingrange, OrderByTime orderbytime)
+	{
+		QueryToTemp (temp_table, FSpot.OrTerm.FromTags(tags), extra_condition, range, importidrange, ratingrange, orderbytime);
+	}
+
+	[Obsolete ("drop this, use IQueryCondition correctly instead")]
 	public Photo [] Query (Tag [] tags, string extra_condition, DateRange range, RollSet importidrange, RatingRange ratingrange)
 	{
 		return Query (FSpot.OrTerm.FromTags(tags), extra_condition, range, importidrange, ratingrange);
 	}
 
 	[Obsolete ("drop this, use IQueryCondition correctly instead")]
+	public void QueryToTemp (string temp_table, Term searchexpression, string extra_condition, DateRange range, RollSet importidrange, RatingRange ratingrange, OrderByTime orderbytime)
+	{
+		bool hide = (extra_condition == null);
+
+		// The SQL query that we want to construct is:
+		//
+		// SELECT photos.id
+		//        photos.time
+		//        photos.uri,
+		//        photos.description,
+		//	  photos.roll_id,
+		//        photos.default_version_id
+		//        photos.rating
+		//                  FROM photos, photo_tags
+		//		    WHERE photos.time >= time1 AND photos.time <= time2
+		//				AND photos.rating >= rat1 AND photos.rating <= rat2
+		//				AND photos.id NOT IN (select photo_id FROM photo_tags WHERE tag_id = HIDDEN)
+		//				AND photos.id IN (select photo_id FROM photo_tags where tag_id IN (tag1, tag2..)
+		//				AND extra_condition_string
+		//                  GROUP BY photos.id
+
+		StringBuilder query_builder = new StringBuilder ();
+		ArrayList where_clauses = new ArrayList ();
+		query_builder.Append ("SELECT photos.id, " 			+
+					     "photos.time, "			+
+					     "photos.uri, "			+
+					     "photos.description, "		+
+					     "photos.roll_id, "   		+
+					     "photos.default_version_id, "	+
+					     "photos.rating "			+
+				      "FROM photos ");
+
+		if (range != null) {
+			where_clauses.Add (String.Format ("photos.time >= {0} AND photos.time <= {1}",
+							  DbUtils.UnixTimeFromDateTime (range.Start),
+							  DbUtils.UnixTimeFromDateTime (range.End)));
+
+		}
+
+		if (ratingrange != null) {
+			where_clauses.Add (ratingrange.SqlClause ());
+		}
+
+		if (importidrange != null) {
+			where_clauses.Add (importidrange.SqlClause ());
+		}
+
+		if (hide && Core.Database.Tags.Hidden != null) {
+			where_clauses.Add (String.Format ("photos.id NOT IN (SELECT photo_id FROM photo_tags WHERE tag_id = {0})",
+							  FSpot.Core.Database.Tags.Hidden.Id));
+		}
+
+		if (searchexpression != null) {
+			where_clauses.Add (searchexpression.SqlCondition ());
+		}
+
+		if (extra_condition != null && extra_condition.Trim () != String.Empty) {
+			where_clauses.Add (extra_condition);
+		}
+
+		if (where_clauses.Count > 0) {
+			query_builder.Append (" WHERE ");
+			query_builder.Append (String.Join (" AND ", ((String []) where_clauses.ToArray (typeof(String)))));
+		}
+		query_builder.Append (" ORDER BY ");
+		query_builder.Append (orderbytime.SqlClause ());
+		QueryToTemp (temp_table, query_builder.ToString ());
+	}
+
+	[Obsolete ("drop this, use IQueryCondition correctly instead")]
 	public Photo [] Query (Term searchexpression, string extra_condition, DateRange range, RollSet importidrange, RatingRange ratingrange)
 	{
 		bool hide = (extra_condition == null);

Modified: trunk/src/Query/DateRange.cs
==============================================================================
--- trunk/src/Query/DateRange.cs	(original)
+++ trunk/src/Query/DateRange.cs	Mon Aug 25 12:17:42 2008
@@ -30,6 +30,12 @@
 			this.end = end;
 		}
 
+		public DateRange (int year, int month)
+		{
+			start = new DateTime (year, month, 1);
+			end = new DateTime (month < 12 ? year : year + 1, month < 12 ? month + 1 : 1, 1);
+		}
+
 		public string SqlClause ()
 		{
 			return String.Format (" photos.time >= {0} AND photos.time <= {1} ", 

Added: trunk/src/Query/IOrderCondition.cs
==============================================================================
--- (empty file)
+++ trunk/src/Query/IOrderCondition.cs	Mon Aug 25 12:17:42 2008
@@ -0,0 +1,16 @@
+/*
+ * IOrderCondition.cs
+ *
+ * Author(s)
+ * 	Stephane Delcroix  <stephane delcroix org>
+ *
+ * This is free software. See COPYING for details.
+ */
+
+namespace FSpot.Query
+{
+	public interface IOrderCondition
+	{
+		string SqlClause ();
+	}
+}

Added: trunk/src/Query/OrderByTime.cs
==============================================================================
--- (empty file)
+++ trunk/src/Query/OrderByTime.cs	Mon Aug 25 12:17:42 2008
@@ -0,0 +1,35 @@
+/*
+ * FSpot.Query.OrderByTime.cs
+ *
+ * Author(s):
+ *	Stephane Delcroix <stephane delcroix org>
+ *
+ * This is free software. See COPYING for details.
+ *
+ */
+
+using System;
+using FSpot.Utils;
+
+namespace FSpot.Query {
+	public class OrderByTime : IQueryCondition, IOrderCondition
+	{
+		public static OrderByTime OrderByTimeAsc = new OrderByTime (true);
+		public static OrderByTime OrderByTimeDesc = new OrderByTime (false);
+
+		bool asc;
+		public bool Asc {
+			get { return asc; }
+		}
+
+		public OrderByTime (bool asc)
+		{
+			this.asc = asc;
+		}
+
+		public string SqlClause ()
+		{
+			return String.Format (" time {0}", asc ? "ASC" : "DESC");
+		}
+	}
+}

Modified: trunk/src/SendEmail.cs
==============================================================================
--- trunk/src/SendEmail.cs	(original)
+++ trunk/src/SendEmail.cs	Mon Aug 25 12:17:42 2008
@@ -56,9 +56,11 @@
 		{
 			this.selection = selection;
 
-			foreach (Photo p in selection.Items)
+			for (int i = 0; i < selection.Count; i++) {
+				Photo p = selection[i] as Photo;
 				if (Gnome.Vfs.MimeType.GetMimeTypeForUri (p.DefaultVersionUri.ToString ()) != "image/jpeg")
 					force_original = true;
+			}
 
 			if (force_original) {
 				original_size.Active = true;
@@ -86,7 +88,8 @@
 			Dialog.Modal = false;
 
 			// Calculate total original filesize 
-			foreach (Photo photo in selection.Items) {
+			for (int i = 0; i < selection.Count; i++) {
+				Photo photo = selection[i] as Photo;
 				try {
 					Orig_Photo_Size += (new Gnome.Vfs.FileInfo (photo.DefaultVersionUri.ToString ())).Size;
 				} catch {
@@ -98,7 +101,7 @@
 
 
 			// Calculate approximate size shrinking, use first photo, and shrink to medium size as base.
-			Photo scalephoto = selection.Items [0] as Photo;			
+			Photo scalephoto = selection [0] as Photo;
 			if (scalephoto != null && !force_original) {
 				
 				// Get first photos file size
@@ -236,7 +239,7 @@
 		
 			progress_dialog = new ProgressDialog (Catalog.GetString ("Preparing email"),
 							      ProgressDialog.CancelButtonType.Stop,
-							      selection.Items.Length, 
+							      selection.Count,
 							      parent_window);
 			
 			size = GetScaleSize(); // Which size should we scale to. 0 --> Original
@@ -280,8 +283,8 @@
 			filters.Add (new UniqueNameFilter (tmp_mail_dir));
 
 
-			foreach (Photo photo in selection.Items) {
-			
+			for (int i = 0; i < selection.Count; i++) {
+				Photo photo = selection [i] as Photo;
 				if ( (photo != null) && (!UserCancelled) ) {
 
 					if (progress_dialog != null)

Modified: trunk/src/TagCommands.cs
==============================================================================
--- trunk/src/TagCommands.cs	(original)
+++ trunk/src/TagCommands.cs	Mon Aug 25 12:17:42 2008
@@ -482,10 +482,10 @@
 
 			photo_scrolled_window.Add (image_view);
 
-			if (query.Photos.Length > 0) {
+			if (query.Count > 0) {
 				photo_spin_button.Wrap = true;
 				photo_spin_button.Adjustment.Lower = 1.0;
-				photo_spin_button.Adjustment.Upper = (double)query.Photos.Length;
+				photo_spin_button.Adjustment.Upper = (double) query.Count;
 				photo_spin_button.Adjustment.StepIncrement = 1.0;
 				photo_spin_button.ValueChanged += HandleSpinButtonChanged;
 				

Modified: trunk/src/TimeAdaptor.cs
==============================================================================
--- trunk/src/TimeAdaptor.cs	(original)
+++ trunk/src/TimeAdaptor.cs	Mon Aug 25 12:17:42 2008
@@ -1,56 +1,34 @@
+/*
+ * FSpot.TimeAdaptor.cs
+ *
+ * Author(s):
+ *	Larry Ewing  <lewing novell com>
+ * 	Stephane Delcroix  <stephnae delcroix org>
+ *
+ * This is free software. See COPYING for details.
+ */
+
 using System;
-using System.Collections;
+using System.Threading;
+using System.Collections.Generic;
 using FSpot.Query;
 using FSpot.Utils;
 
 namespace FSpot {
 	public class TimeAdaptor : GroupAdaptor, FSpot.ILimitable {
-		ArrayList years = new ArrayList ();
-		struct YearData {
-			public int Year;
-			public int [] Months;
-		}
+		Dictionary <int, int[]> years = new Dictionary<int, int[]> ();
 
 		public override event GlassSetHandler GlassSet;
 		public override void SetGlass (int min)
 		{
 			DateTime date = DateFromIndex (min);
-			
-			if (GlassSet != null)
-				GlassSet (this, LookupItem (date));
-		}
-
-		public int LookupItem (System.DateTime date)
-		{
-			if (order_ascending) 
-				return LookUpItemAscending (date);
-			
-			return LookUpItemDescending (date);
-		}
 
-		private int LookUpItemAscending (System.DateTime date)
-		{
-			int i = 0;
-
-			while (i < query.Count && query [i].Time < date)
-				i++;
-
-			return i;
+			if (GlassSet != null)
+				GlassSet (this, query.LookupItem (date));
 		}
 
-		private int LookUpItemDescending (System.DateTime date)
-		{
-			int i = 0;
-
-			while (i < query.Count && query [i].Time > date)
-				i++;
-
-			return i;
-		}
-		
 		public void SetLimits (int min, int max) 
 		{
-			//Console.WriteLine ("min {0} max {1}", min, max);
 			DateTime start = DateFromIndex (min);
 
 			DateTime end = DateFromIndex(max);
@@ -65,11 +43,7 @@
 
 		public void SetLimits (DateTime start, DateTime end)
 		{
-			//Console.WriteLine ("{0} {1}", start, end);
-			if (start > end)
-				query.Range = new DateRange (end, start);
-			else 
-				query.Range = new DateRange (start, end);
+			query.Range = (start > end) ? new DateRange (end, start) : new DateRange (start, end);
 		}
 
 		public override int Count ()
@@ -79,9 +53,7 @@
 
 		public override string GlassLabel (int item)
 		{
-			DateTime start = DateFromIndex (item);
-			
-			return String.Format ("{0} ({1})", start.ToString ("MMMM yyyy"), Value (item));
+			return String.Format ("{0} ({1})", DateFromIndex (item).ToString ("MMMM yyyy"), Value (item));
 		}
 
 		public override string TickLabel (int item)
@@ -96,9 +68,10 @@
 
 		public override int Value (int item)
 		{
-			YearData data = (YearData)years [item/12];
-
-			return data.Months [item % 12];
+			if (order_ascending)
+				return years [startyear + item/12][item % 12];
+			else
+				return years [endyear - item/12][11 - item % 12];
 		}
 
 		public DateTime DateFromIndex (int item) 
@@ -114,7 +87,7 @@
 
 		private DateTime DateFromIndexAscending (int item)
 		{
-			int year = (int)((YearData)years [item / 12]).Year;
+			int year = startyear + item/12;
 			int month = 1 + (item % 12);
 
 			return new DateTime(year, month, 1);
@@ -122,7 +95,7 @@
 
 		private DateTime DateFromIndexDescending (int item)
 		{
-			int year =  (int)((YearData)years [item / 12]).Year;
+			int year = endyear - item/12;
 			int month = 12 - (item % 12);
 			
 			return new DateTime (year, month, DateTime.DaysInMonth (year, month)).AddDays (1.0).AddMilliseconds (-.1);
@@ -147,96 +120,67 @@
 		private int IndexFromDateAscending(DateTime date)
 		{
 			int year = date.Year;
-			int max_year = ((YearData)years [years.Count - 1]).Year;
-			int min_year = ((YearData)years [0]).Year;
+			int min_year = startyear;
+			int max_year = endyear;
 
 			if (year < min_year || year > max_year) {
-				Console.WriteLine("TimeAdaptor.IndexFromDate year out of range[{1},{2}]: {0}", year, min_year, max_year);
+				Log.DebugFormat ("TimeAdaptor.IndexFromDate year out of range[{1},{2}]: {0}", year, min_year, max_year);
 				return 0;
 			}
 
-			int index = date.Month - 1;
-
-			for (int i = 0 ; i < years.Count; i++)
-				if (year > ((YearData)years[i]).Year)
-					index += 12;
-
-			return index;	
+			return (year - startyear) * 12 + date.Month - 1 ;
 		}
 
 		private int IndexFromDateDescending(DateTime date)
 		{
 			int year = date.Year;
-			int max_year = ((YearData)years [0]).Year;
-			int min_year = ((YearData)years [years.Count - 1]).Year;
+			int min_year = startyear;
+			int max_year = endyear;
 		
 			if (year < min_year || year > max_year) {
-				Console.WriteLine("TimeAdaptor.IndexFromPhoto year out of range[{1},{2}]: {0}", year, min_year, max_year);
+				Log.DebugFormat ("TimeAdaptor.IndexFromPhoto year out of range[{1},{2}]: {0}", year, min_year, max_year);
 				return 0;
 			}
 
-			int index = 12 - date.Month;
-
-			for (int i = 0; i < years.Count; i++)
-				if (year < ((YearData)years[i]).Year)
-					index += 12;
-
-			return index;
+			return 12 * (endyear - year) + 12 - date.Month;
 		}
 
 		public override FSpot.IBrowsableItem PhotoFromIndex (int item)
 	       	{
 			DateTime start = DateFromIndex (item);
-			return query.Items [LookupItem (start)];
+			return query [query.LookupItem (start)];
 		
 		}
 
 		public override event ChangedHandler Changed;
 		
+		uint timer;
 		protected override void Reload () 
 		{
-			years.Clear ();
-
-			Photo [] photos = query.Store.Query ((Tag [])null, null, null, null, null);
-
-			Array.Sort (query.Photos);
-			Array.Sort (photos);
-
-			if (!order_ascending) {				
-				Array.Reverse (query.Photos);
-				Array.Reverse (photos);
-			}
+			timer = Log.DebugTimerStart ();
+			Thread reload = new Thread (new ThreadStart (DoReload));
+			reload.IsBackground = true;
+			reload.Priority = ThreadPriority.Lowest;
+			reload.Start ();
+		}
 
-			if (photos.Length > 0) {
-				YearData data = new YearData ();
-				data.Year = 0;
-
-				foreach (Photo photo in photos) {
-					int current = photo.Time.Year;
-					if (current != data.Year) {
-						
-						data.Year = current;
-						data.Months = new int [12];
-						years.Add (data);
-						//Console.WriteLine ("Found Year {0}", current);
-					}
-					if (order_ascending)
-						data.Months [photo.Time.Month - 1] += 1;
-					else
-						data.Months [12 - photo.Time.Month] += 1;
-				}
-			} else {
-				YearData data = new YearData ();
-				data.Year = DateTime.Now.Year;
-				data.Months = new int [12];
-				years.Add (data);
+		int startyear = Int32.MaxValue, endyear = Int32.MinValue;
+		void DoReload ()
+		{
+			Thread.Sleep (200);
+			years = query.Store.PhotosPerMonth ();
+			foreach (int year in years.Keys) {
+				startyear = Math.Min (year,startyear);
+				endyear = Math.Max (year,endyear);
 			}
-
  			if (Changed != null)
-				Changed (this);
+				Gtk.Application.Invoke(delegate {
+					if (Changed != null)
+						Changed (this);
+				});
+			Log.DebugTimerPrint (timer, "TimeAdaptor REAL Reload took {0}");
 		}
 
-
 		public TimeAdaptor (PhotoQuery query, bool order_ascending) 
 			: base (query, order_ascending)
 		{ }

Modified: trunk/src/Widgets/PreviewPopup.cs
==============================================================================
--- trunk/src/Widgets/PreviewPopup.cs	(original)
+++ trunk/src/Widgets/PreviewPopup.cs	Mon Aug 25 12:17:42 2008
@@ -113,7 +113,7 @@
 
 		private void UpdateImage ()
 		{
-			FSpot.IBrowsableItem item = view.Collection.Items [Item];
+			FSpot.IBrowsableItem item = view.Collection [Item];
 			
 			string orig_path = item.DefaultVersionUri.LocalPath;
 

Modified: trunk/src/Widgets/TrayView.cs
==============================================================================
--- trunk/src/Widgets/TrayView.cs	(original)
+++ trunk/src/Widgets/TrayView.cs	Mon Aug 25 12:17:42 2008
@@ -38,7 +38,7 @@
 				cell_width = System.Math.Min (256, available_width / cells_per_row);
 				width = cell_width - 2 * cell_border_width;
 				cell_height = (int)(width / ThumbnailRatio) + 2 * cell_border_width;
-				total_rows = (int) System.Math.Ceiling (collection.Items.Length / (double)cells_per_row);
+				total_rows = (int) System.Math.Ceiling (collection.Count / (double)cells_per_row);
 				cells_per_row ++;
 			} while (total_rows > Allocation.Height / cell_height);
 			cells_per_row --;



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