ANDing categories together



This patch makes categories work the way I intuitively expected. Of
course I'm a geek, so using my opinion for this sort of thing is
dangerous.

* You can select/deselect all tags and categories independently
* Only photos which have all tags are displayed
* A photo is considered to "have" a tag if it is tagged with it or any
of its children

The implementation is a bit sucky, but gets the concept across.
-- 
Loz
? Makefile.solution.f-spot
? configure.scan
? f-spot.cmbx
? f-spot.mdsx
? make.sh
? po/Makefile
? po/Makefile.in
? po/Makefile.in.in
? po/POTFILES
? po/es.gmo
? src/AssemblyInfo.cs
? src/Main.cs
? src/Makefile.f-spot
? src/MyProgram.cs
? src/f-spot.pidb
? src/f-spot.prjx
Index: src/PhotoStore.cs
===================================================================
RCS file: /cvs/gnome/f-spot/src/PhotoStore.cs,v
retrieving revision 1.40
diff -u -r1.40 PhotoStore.cs
--- src/PhotoStore.cs	24 Aug 2004 15:56:04 -0000	1.40
+++ src/PhotoStore.cs	20 Oct 2004 19:36:42 -0000
@@ -967,7 +967,9 @@
 
 	public Photo [] Query (Tag [] tags, DateRange range)
 	{
+		const string AND = " AND ";
 		string query;
+		string sep = " WHERE ";
 
 		bool hide = true;
 		if (tags != null) {
@@ -1005,38 +1007,44 @@
 			query_builder.Append (String.Format ("WHERE photos.time >= {0} AND photos.time < {1} ",
 							     DbUtils.UnixTimeFromDateTime (range.Start), 
 							     DbUtils.UnixTimeFromDateTime (range.End)));
+			sep = AND;
 		}
 		
 		if (hide) {
 			query_builder.Append (String.Format ("{0} photos.id NOT IN (SELECT photo_id FROM photo_tags WHERE tag_id = {1})", 
-							     range != null ? " AND " : " WHERE ", tag_store.Hidden.Id));
+							     sep, tag_store.Hidden.Id));
+			sep = AND;				     
 		}
 		
 		if (tags != null && tags.Length > 0) {
-				bool first = true;
 				foreach (Tag t in tags) {
 					if (t.Id == tag_store.Hidden.Id)
 						continue;
-					
-					if (first) {
-						query_builder.Append (String.Format ("{0} photos.id IN (SELECT photo_id FROM photo_tags WHERE tag_id IN (",
-										     hide || range != null ? " AND " : " WHERE "));
+						
+					//Optimizations
+					//1. if t is root then we can ignore
+					//2. maintain table of tag_id, tag_id which is the relation (is_or_is_child_of) and join against that rather than the big in statement
+					bool first = true;
+					foreach (Tag tag in t.MeAndAncestors) {
+						if (first) {
+							query_builder.Append (sep);
+							query_builder.Append(" photos.id IN (SELECT photo_id FROM photo_tags WHERE tag_id IN (");
+							sep = AND;
+						}
+						query_builder.Append (String.Format ("{0}{1} ", first ? "" : ", ", tag.Id));						
+						first = false;
 					}
-					
-					query_builder.Append (String.Format ("{0}{1} ", first ? "" : ", ", t.Id));
-					
-					first = false;
+					if (!first)
+						query_builder.Append(")) ");
 				}
 				
-				if (!first)
-					query_builder.Append (")) ");
 		}
 		
 		query_builder.Append ("ORDER BY photos.time");
 		query = query_builder.ToString ();
 		
 		Console.WriteLine ("Query Start {0}", System.DateTime.Now.ToLongTimeString ());
-
+		// Console.WriteLine(query);
 		SqliteCommand command = new SqliteCommand ();
 		command.Connection = Connection;
 		command.CommandText = query;
@@ -1091,7 +1099,7 @@
 
 		return id_list.ToArray (typeof (Photo)) as Photo [];
 	}
-
+	
 #if TEST_PHOTO_STORE
 	static void Dump (Photo photo)
 	{
Index: src/TagSelectionWidget.cs
===================================================================
RCS file: /cvs/gnome/f-spot/src/TagSelectionWidget.cs,v
retrieving revision 1.11
diff -u -r1.11 TagSelectionWidget.cs
--- src/TagSelectionWidget.cs	17 Jun 2004 04:05:57 -0000	1.11
+++ src/TagSelectionWidget.cs	20 Oct 2004 19:36:43 -0000
@@ -67,8 +67,8 @@
 			return false;
 		else if (selection.ContainsKey (tag.Id))
 			return true;
-		else if (tag.Category != tag_store.RootCategory && IsSelected (tag.Category))
-			return true;
+		//else if (tag.Category != tag_store.RootCategory && IsSelected (tag.Category))
+		//	return true;
 		else
 			return false;
 	}
@@ -169,6 +169,13 @@
 		uint tag_id = (uint) value;
 		Tag tag = tag_store.Get (tag_id) as Tag;
 
+		// Tags stand alone now
+		if (IsSelected (tag)) 
+			Unselect (tag);
+		else
+			Select (tag);
+		(Model as TreeStore).EmitRowChanged (path, iter);
+		/*
 		// Tags under an unselected category are always conceptually unselected.
 		// They appear as selected just in virtue of being children of a selected category.
 		if (! IsSelected (tag.Category)) {
@@ -183,7 +190,7 @@
 			if (tag is Category)
 				UnselectTagsForCategory (tag as Category);
 		}
-
+		*/
 		if (SelectionChanged != null)
 			SelectionChanged (this);
 	}
Index: src/TagStore.cs
===================================================================
RCS file: /cvs/gnome/f-spot/src/TagStore.cs,v
retrieving revision 1.13
diff -u -r1.13 TagStore.cs
--- src/TagStore.cs	18 Aug 2004 00:23:35 -0000	1.13
+++ src/TagStore.cs	20 Oct 2004 19:36:43 -0000
@@ -135,6 +135,20 @@
 			return Category.CompareTo (tag.Category);
 		}
 	}
+	
+	public Tag[] MeAndAncestors { //is there a word for that?
+		get {
+			// can be improved we are creating a lot of array lists by recursing this way
+			// should pass an accumulator around instead
+			ArrayList ancestors = new ArrayList();
+			ancestors.Add(this);
+			if (this is Category) 
+				foreach (Tag tag in (this as Category).Children) 
+					ancestors.AddRange(tag.MeAndAncestors);
+			return (Tag []) ancestors.ToArray (typeof (Tag));
+		}
+	}
+
 }
 
 
@@ -153,7 +167,7 @@
 			children_need_sort = true;
 		}
 	}
-
+		
 	public void AddChild (Tag child)
 	{
 		children.Add (child);


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