[tracker/tracker-needle-improved-tagging: 1/4] tracker-needle: Include tags in search results and only show files for selected tag



commit f301a28173f4d1fc81ab28cbdcd796962bd2db14
Author: Martyn Russell <martyn lanedo com>
Date:   Fri Jun 24 13:12:29 2011 +0100

    tracker-needle: Include tags in search results and only show files for selected tag
    
    This means searching for "foo" will find that using fts:match AND nao:prefLabel.
    
    This also means the tags list on the right side will show ONLY those files in
    the selected view.

 src/tracker-needle/tracker-needle.vala       |   20 ++++
 src/tracker-needle/tracker-query.vala        |  133 +++++++++++++++++++++-----
 src/tracker-needle/tracker-result-store.vala |    4 +
 src/tracker-needle/tracker-taglist.vala      |   38 ++++++--
 4 files changed, 163 insertions(+), 32 deletions(-)
---
diff --git a/src/tracker-needle/tracker-needle.vala b/src/tracker-needle/tracker-needle.vala
index 901e9b7..62f4552 100644
--- a/src/tracker-needle/tracker-needle.vala
+++ b/src/tracker-needle/tracker-needle.vala
@@ -315,6 +315,7 @@ public class Tracker.Needle {
 		taglist = new Tracker.TagList ();
 		taglist.hide ();
 		view.pack_end (taglist, false, true, 0);
+		taglist.selection_changed.connect (taglist_selection_changed);
 
 		view_categories.set_active (true);
 	}
@@ -329,6 +330,15 @@ public class Tracker.Needle {
 		return false;
 	}
 
+	private void taglist_selection_changed (GenericArray<string> new_tags) {
+		if (new_tags != null && new_tags.length > 0)
+			debug ("Tags selected changed, first:'%s', ...", new_tags[0]);
+		else
+			debug ("Tags selected changed, none selected");
+
+		search_run ();
+	}
+
 	private void search_changed (Editable editable) {
 		if (last_search_id != 0) {
 			Source.remove (last_search_id);
@@ -457,6 +467,13 @@ public class Tracker.Needle {
 		}
 
 		if (store != null) {
+			// Set tags first
+			if (show_tags.active) {
+				store.search_tags = taglist.tags;
+			} else {
+				store.search_tags = null;
+			}
+
 			store.search_term = search.get_text ();
 		}
 
@@ -600,6 +617,9 @@ public class Tracker.Needle {
 			debug ("Hiding tags");
 			taglist.hide ();
 		}
+
+		// Re-run search to filter with or without tags
+		search_run ();
 	}
 
 	private void show_stats_clicked () {
diff --git a/src/tracker-needle/tracker-query.vala b/src/tracker-needle/tracker-query.vala
index 892303d..f1c4f5a 100644
--- a/src/tracker-needle/tracker-query.vala
+++ b/src/tracker-needle/tracker-query.vala
@@ -39,7 +39,9 @@ public class Tracker.Query {
 		FTS,
 		FTS_INDIRECT,
 		TITLES,
-		TITLES_INDIRECT
+		TITLES_INDIRECT,
+		TAGS_ONLY,
+		TAGS_ONLY_INDIRECT
 	}
 
 	private string [] match_clauses = {
@@ -47,25 +49,35 @@ public class Tracker.Query {
 		"",
 
 		// FTS
-		"?urn fts:match \"%s\"",
+		"{
+		   ?urn fts:match \"%s\"
+		 } UNION {
+		   ?urn nao:hasTag ?tag .
+                   FILTER (fn:contains (fn:lower-case (nao:prefLabel(?tag)), \"%s\"))
+		 }",
 
 		// FTS_INDIRECT (with sub-matching)
-		"?match fts:match \"%s\"",
+		"{
+		   ?match fts:match \"%s\"
+		 } UNION {
+		   ?match nao:hasTag ?tag .
+                   FILTER (fn:contains (fn:lower-case (nao:prefLabel(?tag)), \"%s\"))
+		 }",
 
 		// TITLES
 		"FILTER (fn:contains (fn:lower-case (nfo:fileName(?urn)), \"%s\"))",
 
-		// TITLES INDIRECT (with sub-matching)
-		"FILTER (fn:contains (fn:lower-case (nie:title (?match), \"%s\"))"
-	};
+		// TITLES_INDIRECT (with sub-matching)
+		"FILTER (fn:contains (fn:lower-case (nie:title(?match)), \"%s\"))",
+
+		// TAGS_ONLY (no fts:match, just nao:prefLabel matching, %s is filled in by get_tags_filter()
+		"?urn nao:hasTag ?tag .
+		 FILTER (nao:prefLabel(?tag) IN (%s))",
 
-		// ALL_ONLY_IN_TITLES
-//		"WHERE {
-//		  ?urn a nfo:FileDataObject ;
-//		  nfo:belongsToContainer ?parent ;
-//		  tracker:available true .
-//		  FILTER (fn:contains (fn:lower-case (nfo:fileName(?urn)), \"%s\"))
-//		}",
+		// TAGS_ONLY_INDIRECT (same as TAGS_ONLY for ?match)
+		"?match nao:hasTag ?tag .
+		 FILTER (nao:prefLabel(?tag) IN (%s))"
+	};
 
 	private string [] where_clauses = {
 		// ALL
@@ -98,7 +110,7 @@ public class Tracker.Query {
 		  %s .
 		  ?urn nmm:performer [ nmm:artistName ?performer ] ;
 		       nmm:musicAlbum [ nie:title ?album ] ;
-		       nie:url ?tooltip
+		       nie:url ?tooltip .
 		}",
 
 		// IMAGES
@@ -152,7 +164,7 @@ public class Tracker.Query {
 		// BOOKMARKS
 		"WHERE {
 		  ?urn a nfo:Bookmark ;
-               nfo:bookmarks ?bookmark .
+                         nfo:bookmarks ?bookmark .
 		  %s
 		}"
 	};
@@ -162,6 +174,8 @@ public class Tracker.Query {
 	public uint limit { get; set; }
 	public string query { get; private set; }
 
+	public GenericArray<string> tags { get; set; }
+
 	private static Sparql.Connection connection;
 
 	public Query () {
@@ -170,6 +184,25 @@ public class Tracker.Query {
 		} catch (GLib.Error e) {
 			warning ("Could not get Sparql connection: %s", e.message);
 		}
+
+		tags = null;
+	}
+
+	private string get_tags_filter () {
+		string filter = "";
+
+		if (tags != null && tags.length > 0) {
+			for (int i = 0; i < tags.length; i++) {
+				string escaped = Tracker.Sparql.escape_string (tags[i]);
+
+				if (filter.length > 1)
+					filter += ", ";
+
+				filter += "\"%s\"".printf (escaped);
+			}
+		}
+
+		return filter;
 	}
 
 	private bool check_query_and_match_type (Type query_type, Match match_type) {
@@ -202,13 +235,39 @@ public class Tracker.Query {
 			return 0;
 		}
 
-		if (match_type != Match.NONE && (criteria == null || criteria.length < 1)) {
-			warning ("Criteria was NULL or an empty string, no query performed");
+		// If we have tags supplied, we ONLY show files from those tags
+		if (tags != null && tags.length > 0) {
+			if (match_type == Match.FTS_INDIRECT ||
+			    match_type == Match.TITLES_INDIRECT) {
+				match_type = Match.TAGS_ONLY_INDIRECT;
+			} else {
+				match_type = Match.TAGS_ONLY;
+			}
+		}
+
+		if (match_type != Match.NONE &&
+	            match_type != Match.TAGS_ONLY &&
+                    (criteria == null || criteria.length < 1)) {
+			warning ("Criteria was NULL or an empty string no query performed");
 			return 0;
 		}
 
-		string criteria_escaped = Tracker.Sparql.escape_string (criteria);
-		string match = match_clauses[match_type].printf (criteria_escaped);
+		string match;
+
+		if (match_type == Match.TAGS_ONLY ||
+		    match_type == Match.TAGS_ONLY_INDIRECT) {
+			match = match_clauses[match_type].printf (get_tags_filter ());
+		} else {
+			string criteria_escaped = Tracker.Sparql.escape_string (criteria);
+
+			// FTS queries take 2 arguments for tags and fts:match
+			if (match_type == Match.FTS ||
+			    match_type == Match.FTS_INDIRECT) {
+				match = match_clauses[match_type].printf (criteria_escaped, criteria_escaped);
+			} else {
+				match = match_clauses[match_type].printf (criteria_escaped);
+			}
+		}
 
 		query = "SELECT count(?urn) " + where_clauses[query_type].printf (match);
 
@@ -222,7 +281,7 @@ public class Tracker.Query {
 		return (uint) cursor.get_integer (0);
 	}
 
-	public async Sparql.Cursor? perform_async (Type query_type, Match match_type, string [] ?args, Cancellable? cancellable = null) throws IOError
+	public async Sparql.Cursor? perform_async (Type query_type, Match match_type, string[] ?args, Cancellable? cancellable = null) throws IOError
 	requires (connection != null) {
 		Sparql.Cursor cursor = null;
 
@@ -230,8 +289,20 @@ public class Tracker.Query {
 			return null;
 		}
 
-		if (match_type != Match.NONE && (criteria == null || criteria.length < 1)) {
-			warning ("Criteria was NULL or an empty string, no query performed");
+		// If we have tags supplied, we ONLY show files from those tags
+		if (tags != null && tags.length > 0) {
+			if (match_type == Match.FTS_INDIRECT ||
+			    match_type == Match.TITLES_INDIRECT) {
+				match_type = Match.TAGS_ONLY_INDIRECT;
+			} else {
+				match_type = Match.TAGS_ONLY;
+			}
+		}
+
+		if (match_type != Match.NONE &&
+	            match_type != Match.TAGS_ONLY &&
+                    (criteria == null || criteria.length < 1)) {
+			warning ("Criteria was NULL or an empty string no query performed");
 			return null;
 		}
 
@@ -240,8 +311,22 @@ public class Tracker.Query {
 			return null;
 		}
 
-		string criteria_escaped = Tracker.Sparql.escape_string (criteria);
-		string match = match_clauses[match_type].printf (criteria_escaped);
+		string match;
+
+		if (match_type == Match.TAGS_ONLY ||
+		    match_type == Match.TAGS_ONLY_INDIRECT) {
+			match = match_clauses[match_type].printf (get_tags_filter ());
+		} else {
+			string criteria_escaped = Tracker.Sparql.escape_string (criteria);
+
+			// FTS queries take 2 arguments for tags and fts:match
+			if (match_type == Match.FTS ||
+			    match_type == Match.FTS_INDIRECT) {
+				match = match_clauses[match_type].printf (criteria_escaped, criteria_escaped);
+			} else {
+				match = match_clauses[match_type].printf (criteria_escaped);
+			}
+		}
 
 		query = "SELECT " + string.joinv (" ", args) + " " + where_clauses[query_type].printf (match);
 		query += @" OFFSET $offset LIMIT $limit";
diff --git a/src/tracker-needle/tracker-result-store.vala b/src/tracker-needle/tracker-result-store.vala
index 4c8b18e..8a54af9 100644
--- a/src/tracker-needle/tracker-result-store.vala
+++ b/src/tracker-needle/tracker-result-store.vala
@@ -87,6 +87,7 @@ public class Tracker.ResultStore : Gtk.TreeModel, GLib.Object {
 
 			query = new Tracker.Query ();
 			query.criteria = _search_term;
+			query.tags = search_tags;
 			query.limit = 100;
 			query.offset = op.offset;
 
@@ -207,6 +208,7 @@ public class Tracker.ResultStore : Gtk.TreeModel, GLib.Object {
 
 			Tracker.Query query = new Tracker.Query ();
 			query.criteria = _search_term;
+			query.tags = search_tags;
 
 			count = yield query.get_count_async (query_data.type, query_data.match, cancellable);
 			cancellable.set_error_if_cancelled ();
@@ -329,6 +331,8 @@ public class Tracker.ResultStore : Gtk.TreeModel, GLib.Object {
 		}
 	}
 
+	public GenericArray<string> search_tags { get; set; }
+
 	public bool active {
 		get;
 		private set;
diff --git a/src/tracker-needle/tracker-taglist.vala b/src/tracker-needle/tracker-taglist.vala
index 818c2a5..3b5b5b9 100644
--- a/src/tracker-needle/tracker-taglist.vala
+++ b/src/tracker-needle/tracker-taglist.vala
@@ -26,9 +26,15 @@ public class Tracker.TagList : ScrolledWindow {
 	private int offset;
 	private int limit;
 
+	public GenericArray<string> tags { get; private set; }
+
+	public signal void selection_changed (GenericArray<string> new_tags); 
+
 	public TagList () {
 		limit = 100;
 
+		tags = new GenericArray<string> ();
+
 		// Set scrolling
 		set_policy (PolicyType.NEVER, PolicyType.AUTOMATIC);
 		set_size_request (175, -1);
@@ -47,7 +53,7 @@ public class Tracker.TagList : ScrolledWindow {
 		Gtk.CellRenderer renderer;
 
 		col = new Gtk.TreeViewColumn ();
-		col.set_title (_("Tags"));
+		col.set_title (_("Filter by tags"));
 		col.set_resizable (true);
 		col.set_expand (true);
 		col.set_sizing (Gtk.TreeViewColumnSizing.AUTOSIZE);
@@ -61,7 +67,7 @@ public class Tracker.TagList : ScrolledWindow {
 
 		renderer = new CellRendererText ();
 		col.pack_start (renderer, true);
-		col.set_cell_data_func (renderer, text_renderer_func);
+		col.set_cell_data_func (renderer, model_text_renderer_func);
 
 		renderer = new CellRendererText ();
 		renderer.xpad = 5;
@@ -70,6 +76,9 @@ public class Tracker.TagList : ScrolledWindow {
 		col.add_attribute (renderer, "text", 3);
 		treeview.append_column (col);
 
+		var selection = treeview.get_selection ();
+		selection.changed.connect (model_selection_changed);
+
 		add (treeview);
 		base.show_all ();
 
@@ -81,13 +90,13 @@ public class Tracker.TagList : ScrolledWindow {
 			return;
 		}
 
-		get_tags.begin ();
+		query_get_tags.begin ();
 	}
 
-	private void text_renderer_func (CellLayout   cell_layout,
-	                                 CellRenderer cell,
-	                                 TreeModel    tree_model,
-	                                 TreeIter     iter) {
+	private void model_text_renderer_func (CellLayout   cell_layout,
+	                                       CellRenderer cell,
+	                                       TreeModel    tree_model,
+	                                       TreeIter     iter) {
 		string text, subtext;
 		string markup = null;
 
@@ -104,7 +113,20 @@ public class Tracker.TagList : ScrolledWindow {
 		cell.set ("markup", markup);
 	}
 
-	private async void get_tags () {
+	private void model_selection_foreach (TreeModel model, TreePath path, TreeIter iter) {
+		weak string tag;
+		model.get (iter, 1, out tag);
+		tags.add (tag);
+	}
+
+	private void model_selection_changed (TreeSelection selection) {
+		tags = new GenericArray<string> ();
+
+		selection.selected_foreach (model_selection_foreach);
+		selection_changed (tags);
+	}
+
+	private async void query_get_tags () {
 		string query = @"
 		               SELECT 
 		                 ?tag 



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