[tracker/tracker-needle-improved-tagging: 1/4] tracker-needle: Include tags in search results and only show files for selected tag
- From: Martyn James Russell <mr src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [tracker/tracker-needle-improved-tagging: 1/4] tracker-needle: Include tags in search results and only show files for selected tag
- Date: Sun, 31 Jul 2011 09:11:05 +0000 (UTC)
commit 35db1f9a9634aac65bf9846b3454963798af62ee
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 1eeb88e..f15c0de 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 4c1f15a..b677832 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;
@@ -202,6 +203,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 ();
@@ -324,6 +326,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]