From 824725b7d2e4381ab581479e15cde21fec271f2d Mon Sep 17 00:00:00 2001 From: babubabu Date: Wed, 25 Apr 2012 14:05:23 +0200 Subject: [PATCH 01/17] test --- extension.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extension.js b/extension.js index 14d1c42..113eca2 100644 --- a/extension.js +++ b/extension.js @@ -1,6 +1,6 @@ /* Tracker Search Provider for Gnome Shell * - * Copyright (c) 2012 Christian Weber, Felix Schultze + * Copyright (c) 2012 Christian Weber * * This programm is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by From 0f4fbbb40e849f3b32a7c7fd9f3cd2f1a0685a70 Mon Sep 17 00:00:00 2001 From: babubabu Date: Wed, 25 Apr 2012 14:08:34 +0200 Subject: [PATCH 02/17] reset test --- extension.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extension.js b/extension.js index 113eca2..14d1c42 100644 --- a/extension.js +++ b/extension.js @@ -1,6 +1,6 @@ /* Tracker Search Provider for Gnome Shell * - * Copyright (c) 2012 Christian Weber + * Copyright (c) 2012 Christian Weber, Felix Schultze * * This programm is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by From c7a4e96ea33f02992669852b922e8472b9849709 Mon Sep 17 00:00:00 2001 From: babubabu Date: Wed, 25 Apr 2012 15:23:58 +0200 Subject: [PATCH 03/17] code formatted, check for existing file --- extension.js | 207 ++++++++++++++++++++++++++++----------------------- 1 file changed, 114 insertions(+), 93 deletions(-) diff --git a/extension.js b/extension.js index 14d1c42..93dac40 100644 --- a/extension.js +++ b/extension.js @@ -8,18 +8,19 @@ * (at your option) any later version. * * Version 1.4 - * + * * https://github.com/cewee/tracker-search */ -const Main = imports.ui.main; -const Search = imports.ui.search; -const Gio = imports.gi.Gio; -const GLib = imports.gi.GLib; -const Lang = imports.lang; -const Shell = imports.gi.Shell; -const Util = imports.misc.util; -const Tracker = imports.gi.Tracker; +const Main = imports.ui.main; +const Search = imports.ui.search; +const Gio = imports.gi.Gio; +const GLib = imports.gi.GLib; +const Lang = imports.lang; +const Shell = imports.gi.Shell; +const Util = imports.misc.util; +const Tracker = imports.gi.Tracker; +const St = imports.gi.St; /* let xdg-open pick the appropriate program to open/execute the file */ const DEFAULT_EXEC = 'xdg-open'; @@ -33,117 +34,137 @@ function TrackerSearchProvider() { } TrackerSearchProvider.prototype = { - __proto__ : Search.SearchProvider.prototype, + __proto__ : Search.SearchProvider.prototype, - _init : function(name) { - Search.SearchProvider.prototype._init.call(this, "Tracker Search"); - }, + _init : function(name) { + Search.SearchProvider.prototype._init.call(this, "TRACKER SEARCH"); + }, - getResultMetas: function(resultIds) { + getResultMetas: function(resultIds) { let metas = []; for (let i = 0; i < resultIds.length; i++) { metas.push(this.getResultMeta(resultIds[i])); } return metas; - }, + }, - getResultMeta : function(resultId) { - let type = resultId.contentType; - let name = resultId.filename; - return { + getResultMeta : function(resultId) { + let type = resultId.contentType; + let name = resultId.filename; + return { 'id' : resultId, 'name' : name, 'createIcon' : function(size) { - let icon = Gio.app_info_get_default_for_type(type,null).get_icon(); - global.log("icon : " + String(icon)); - return imports.gi.St.TextureCache.get_default().load_gicon(null, icon, size); + let icon = Gio.app_info_get_default_for_type(type,null).get_icon(); + + return imports.gi.St.TextureCache.get_default().load_gicon(null, icon, size); } }; }, - activateResult : function(id) { - // Action executed when clicked on result - var target = id.fileAndPath; - Util.spawn([ DEFAULT_EXEC, target ]); - }, + activateResult : function(id) { + // Action executed when clicked on result + var target = id.fileAndPath; + Util.spawn([ DEFAULT_EXEC, target ]); + }, - getInitialResultSet : function(terms) { // terms holds array of search items - // check if 1st search term is >2 letters else drop the request - if( terms[0].length <=2 ){ + getInitialResultSet : function(terms) { // terms holds array of search items + // check if 1st search term is >2 letters else drop the request + if(terms[0].length <= 2) { return []; - } - let results = []; - /* Build sparql query */ - var new_query = "SELECT nie:url(?f) WHERE {?f fts:match '"; - for ( var i = 0; i < terms.length; i++) { + } + + let results = []; + /* Build sparql query */ + var new_query = "SELECT nie:url(?f) WHERE {?f fts:match'"; + for ( var i = 0; i < terms.length; i++) { new_query = new_query + " " + terms[i] + "*"; - } - new_query = new_query + "' } ORDER BY DESC (fts:rank(?f)) LIMIT " + String(MAX_RESULTS); - - try { - let conn = Tracker.SparqlConnection.get(null); - let cursor = conn.query(new_query, null); - - while (cursor.next(null)) { - var result = cursor.get_string (null); - if (String(result) == ",0") {continue;} // filter our, bogus tracker responses - var fileStr = String(result).split(','); // cut of number of internal hits - fileStr = decodeURI(fileStr[0]); - // Extract filename from line - var splitted = String(fileStr).split('/'); - var filename = decodeURI(splitted[splitted.length - 1]); - let ft = String(filename).split('.'); - // extract path and filename - splitted = String(fileStr).split('ile://'); - var fileAndPath = ""; - if (splitted.length == 2) { - fileAndPath = decodeURI(splitted[1]); - } - // contentType is an array, the index "1" set true, - // if function is uncertain if type is the right one - let contentType = Gio.content_type_guess(fileAndPath, null); - var newContentType = contentType[0]; - if(contentType[1]){ - if(newContentType == "application/octet-stream") { - let fileInfo = Gio.file_new_for_path(fileAndPath).query_info('standard::type', 0, null); - if(fileInfo.get_file_type() == Gio.FileType.DIRECTORY) // for some reason 'content_type_guess' returns a wrong mime type for folders - { - newContentType = "inode/directory"; - } else { - newContentType = "text/x-log"; // unrecognized mime-types are set to text, so that later an icon can be picked - } - } - } - results.push({ - 'filename' : filename, - 'fileAndPath' : fileAndPath, - 'contentType' : newContentType - }); + } + + new_query = new_query + "' } ORDER BY DESC (fts:rank(?f)) LIMIT " + String(MAX_RESULTS); + + let conn = Tracker.SparqlConnection.get(null); + let cursor = conn.query(new_query, null); + + try { + while (cursor != null && cursor.next(null)) { + var result = cursor.get_string (null); + // filter our, bogus tracker responses + if (String(result) == ",0") { + continue; + } + + // cut of number of internal hits + var fileStr = String(result).split(','); + fileStr = decodeURI(fileStr[0]); + + // Extract filename from line + var splitted = String(fileStr).split('/'); + var filename = decodeURI(splitted[splitted.length - 1]); + let ft = String(filename).split('.'); + + // extract path and filename + splitted = String(fileStr).split('ile://'); + var fileAndPath = ""; + if (splitted.length == 2) { + fileAndPath = decodeURI(splitted[1]); + } + + // if file does not exist, it won't be shown + if(!Gio.file_new_for_path(fileAndPath).query_exists(null)) + { + continue; + } + + // contentType is an array, the index "1" set true, + // if function is uncertain if type is the right one + let contentType = Gio.content_type_guess(fileAndPath, null); + var newContentType = contentType[0]; + if(contentType[1]){ + if(newContentType == "application/octet-stream") { + + + let fileInfo = Gio.file_new_for_path(fileAndPath).query_info('standard::type', 0, null); + + // for some reason 'content_type_guess' returns a wrong mime type for folders + if(fileInfo.get_file_type() == Gio.FileType.DIRECTORY) + { + newContentType = "inode/directory"; + } else { + // unrecognized mime-types are set to text, so that later an icon can be picked + newContentType = "text/x-log"; + } + } + } + + results.push({ + 'filename' : filename, + 'fileAndPath' : fileAndPath, + 'contentType' : newContentType + }); } - } catch (error) { - global.log(error.message); // - return []; } - if (results.length > 0) { - return (results); - } - return []; - }, + } catch (error) { + global.log("cursor " + error.message); // + return []; + } - getSubsearchResultSet : function(previousResults, terms) { - return this.getInitialResultSet(terms); - }, + return (results.length > 0) ? results : []; + }, + + getSubsearchResultSet : function(previousResults, terms) { + return this.getInitialResultSet(terms); + }, }; function init(meta) { } function enable() { - trackerSearchProvider = new TrackerSearchProvider(); - Main.overview.addSearchProvider(trackerSearchProvider); + trackerSearchProvider = new TrackerSearchProvider(); + Main.overview.addSearchProvider(trackerSearchProvider); } function disable() { - Main.overview.removeSearchProvider(trackerSearchProvider); - trackerSearchProvider = null; + Main.overview.removeSearchProvider(trackerSearchProvider); + trackerSearchProvider = null; } - From 03707d9acc84b87fe1411ef476a52288896cebc5 Mon Sep 17 00:00:00 2001 From: Martyn Russell Date: Tue, 1 May 2012 12:05:18 +0100 Subject: [PATCH 04/17] extension: Refactor a little for modularisation --- extension.js | 52 ++++++++++++++++++++++++++++++---------------------- 1 file changed, 30 insertions(+), 22 deletions(-) diff --git a/extension.js b/extension.js index 93dac40..3f37b49 100644 --- a/extension.js +++ b/extension.js @@ -68,23 +68,8 @@ TrackerSearchProvider.prototype = { Util.spawn([ DEFAULT_EXEC, target ]); }, - getInitialResultSet : function(terms) { // terms holds array of search items - // check if 1st search term is >2 letters else drop the request - if(terms[0].length <= 2) { - return []; - } - + filterResults : function(cursor) { let results = []; - /* Build sparql query */ - var new_query = "SELECT nie:url(?f) WHERE {?f fts:match'"; - for ( var i = 0; i < terms.length; i++) { - new_query = new_query + " " + terms[i] + "*"; - } - - new_query = new_query + "' } ORDER BY DESC (fts:rank(?f)) LIMIT " + String(MAX_RESULTS); - - let conn = Tracker.SparqlConnection.get(null); - let cursor = conn.query(new_query, null); try { while (cursor != null && cursor.next(null)) { @@ -98,7 +83,7 @@ TrackerSearchProvider.prototype = { var fileStr = String(result).split(','); fileStr = decodeURI(fileStr[0]); - // Extract filename from line + // extract filename from line var splitted = String(fileStr).split('/'); var filename = decodeURI(splitted[splitted.length - 1]); let ft = String(filename).split('.'); @@ -111,8 +96,7 @@ TrackerSearchProvider.prototype = { } // if file does not exist, it won't be shown - if(!Gio.file_new_for_path(fileAndPath).query_exists(null)) - { + if(!Gio.file_new_for_path(fileAndPath).query_exists(null)) { continue; } @@ -122,8 +106,6 @@ TrackerSearchProvider.prototype = { var newContentType = contentType[0]; if(contentType[1]){ if(newContentType == "application/octet-stream") { - - let fileInfo = Gio.file_new_for_path(fileAndPath).query_info('standard::type', 0, null); // for some reason 'content_type_guess' returns a wrong mime type for folders @@ -144,14 +126,40 @@ TrackerSearchProvider.prototype = { }); } } catch (error) { - global.log("cursor " + error.message); // + global.log("Tracker: Could not traverse results cursor: " + error.message); return []; } return (results.length > 0) ? results : []; }, + getInitialResultSet : function(terms) { + // terms holds array of search items + // check if 1st search term is >2 letters else drop the request + var new_query = "SELECT nie:url(?f) WHERE {?f fts:match'"; + for ( var i = 0; i < terms.length; i++) { + new_query = new_query + " " + terms[i] + "*"; + } + + new_query = new_query + "' } ORDER BY DESC (fts:rank(?f)) LIMIT " + String(MAX_RESULTS); + + let conn = Tracker.SparqlConnection.get(null); + + global.log("Tracker: Running query '" + new_query + "'"); + let cursor = conn.query(new_query, null); + + global.log("Tracker: Filtering results..."); + return this.filterResults(cursor); + }, + getSubsearchResultSet : function(previousResults, terms) { + if(terms[0].length <= 2) { + global.log("Tracker: Ignoring search terms, length < 3"); + return []; + } + + global.log("Tracker: Searching for '" + terms + "'"); + return this.getInitialResultSet(terms); }, }; From 06f7f948b77372c6ec53bc57a520b4d458d605e5 Mon Sep 17 00:00:00 2001 From: Martyn Russell Date: Tue, 1 May 2012 15:31:38 +0100 Subject: [PATCH 05/17] extension: Improved search with FTS and add another category JUST for folders --- extension.js | 146 +++++++++++++++++++++++++++++++-------------------- 1 file changed, 90 insertions(+), 56 deletions(-) diff --git a/extension.js b/extension.js index 3f37b49..8062017 100644 --- a/extension.js +++ b/extension.js @@ -27,17 +27,27 @@ const DEFAULT_EXEC = 'xdg-open'; /* Limit search results, since number of displayed items is limited */ const MAX_RESULTS = 12; -var trackerSearchProvider = null; +const CategoryType = { + FTS : 0, + FILES : 1, + FOLDERS : 2 +}; + +var trackerSearchProviderFiles = null; +var trackerSearchProviderFolders = null; -function TrackerSearchProvider() { - this._init(); +function TrackerSearchProvider(title, categoryType) { + this._init(title, categoryType); } TrackerSearchProvider.prototype = { __proto__ : Search.SearchProvider.prototype, + _categoryType : -1, - _init : function(name) { - Search.SearchProvider.prototype._init.call(this, "TRACKER SEARCH"); + _init : function(title, categoryType) { + this._categoryType = categoryType; + Search.SearchProvider.prototype._init.call(this, title + " (from Tracker)"); + global.log(this.title + ": Created provider (type:" + String(this._categoryType) + ")"); }, getResultMetas: function(resultIds) { @@ -50,7 +60,7 @@ TrackerSearchProvider.prototype = { getResultMeta : function(resultId) { let type = resultId.contentType; - let name = resultId.filename; + let name = resultId.name; return { 'id' : resultId, 'name' : name, @@ -62,10 +72,45 @@ TrackerSearchProvider.prototype = { }; }, - activateResult : function(id) { + activateResult : function(result) { // Action executed when clicked on result - var target = id.fileAndPath; - Util.spawn([ DEFAULT_EXEC, target ]); + var uri = result.id; + var f = Gio.file_new_for_uri(uri); + var fileName = f.get_path(); + + Util.spawn([DEFAULT_EXEC, fileName]); + }, + + getQuery : function (terms) { + // terms holds array of search items + // check if 1st search term is >2 letters else drop the request + var query = ""; + + if (this._categoryType == CategoryType.FTS) { + var terms_in_sparql = ""; + + for (var i = 0; i < terms.length; i++) { + if (terms_in_sparql.length > 0) + terms_in_sparql += " "; + + terms_in_sparql += terms[i] + "*"; + } + // Technically, the tag should really be matched + // separately not as one phrase too. + query += "SELECT ?urn nie:url(?urn) tracker:coalesce(nie:title(?urn), nfo:fileName(?urn)) nie:url(?parent) nfo:fileLastModified(?urn) WHERE { { ?urn a nfo:FileDataObject . ?urn fts:match \"" + terms_in_sparql + "\" } UNION { ?urn nao:hasTag ?tag . FILTER (fn:contains (fn:lower-case (nao:prefLabel(?tag)), \"" + terms + "\")) } OPTIONAL { ?urn nfo:belongsToContainer ?parent . } } ORDER BY DESC(nfo:fileLastModified(?urn)) ASC(nie:title(?urn)) OFFSET 0 LIMIT " + String(MAX_RESULTS); + + } else if (this._categoryType == CategoryType.FILES) { + // TODO: Do we really want this? + } else if (this._categoryType == CategoryType.FOLDERS) { + query += "SELECT ?urn nie:url(?urn) tracker:coalesce(nie:title(?urn), nfo:fileName(?urn)) nie:url(?parent) nfo:fileLastModified(?urn) WHERE {"; + query += " ?urn a nfo:Folder ."; + query += " FILTER (fn:contains (fn:lower-case (nfo:fileName(?urn)), '" + terms + "')) ."; + query += " ?urn nfo:belongsToContainer ?parent ;"; + query += " tracker:available true ."; + query += "} ORDER BY DESC(nfo:fileLastModified(?urn)) DESC(nie:contentCreated(?urn)) ASC(nie:title(?urn)) OFFSET 0 LIMIT " + String(MAX_RESULTS); + } + + return query; }, filterResults : function(cursor) { @@ -73,44 +118,28 @@ TrackerSearchProvider.prototype = { try { while (cursor != null && cursor.next(null)) { - var result = cursor.get_string (null); - // filter our, bogus tracker responses - if (String(result) == ",0") { - continue; - } - - // cut of number of internal hits - var fileStr = String(result).split(','); - fileStr = decodeURI(fileStr[0]); + var urn = cursor.get_string(0)[0]; + var uri = cursor.get_string(1)[0]; + var title = cursor.get_string(2)[0]; + var parentUri = cursor.get_string(3)[0]; - // extract filename from line - var splitted = String(fileStr).split('/'); - var filename = decodeURI(splitted[splitted.length - 1]); - let ft = String(filename).split('.'); - - // extract path and filename - splitted = String(fileStr).split('ile://'); - var fileAndPath = ""; - if (splitted.length == 2) { - fileAndPath = decodeURI(splitted[1]); - } + global.log (this.title + ": uri '" + uri + "', title '" + title + "', parent uri '" + parentUri + "'"); // if file does not exist, it won't be shown - if(!Gio.file_new_for_path(fileAndPath).query_exists(null)) { - continue; - } + var f = Gio.file_new_for_uri(uri); + var fileName = f.get_path(); // contentType is an array, the index "1" set true, // if function is uncertain if type is the right one - let contentType = Gio.content_type_guess(fileAndPath, null); + let contentType = Gio.content_type_guess(fileName, null); var newContentType = contentType[0]; + if(contentType[1]){ if(newContentType == "application/octet-stream") { - let fileInfo = Gio.file_new_for_path(fileAndPath).query_info('standard::type', 0, null); + let fileInfo = Gio.file_new_for_path(fileName).query_info('standard::type', 0, null); // for some reason 'content_type_guess' returns a wrong mime type for folders - if(fileInfo.get_file_type() == Gio.FileType.DIRECTORY) - { + if(fileInfo.get_file_type() == Gio.FileType.DIRECTORY) { newContentType = "inode/directory"; } else { // unrecognized mime-types are set to text, so that later an icon can be picked @@ -120,13 +149,13 @@ TrackerSearchProvider.prototype = { } results.push({ - 'filename' : filename, - 'fileAndPath' : fileAndPath, + 'id' : uri, + 'name' : title, 'contentType' : newContentType }); } } catch (error) { - global.log("Tracker: Could not traverse results cursor: " + error.message); + global.log(this.title + ": Could not traverse results cursor: " + error.message); return []; } @@ -134,45 +163,50 @@ TrackerSearchProvider.prototype = { }, getInitialResultSet : function(terms) { - // terms holds array of search items - // check if 1st search term is >2 letters else drop the request - var new_query = "SELECT nie:url(?f) WHERE {?f fts:match'"; - for ( var i = 0; i < terms.length; i++) { - new_query = new_query + " " + terms[i] + "*"; + if(terms[0].length < 3) { + global.log(this.title + ": Ignoring search term:'" + terms + "', length < 3"); + return []; } - new_query = new_query + "' } ORDER BY DESC (fts:rank(?f)) LIMIT " + String(MAX_RESULTS); - let conn = Tracker.SparqlConnection.get(null); - global.log("Tracker: Running query '" + new_query + "'"); - let cursor = conn.query(new_query, null); + var query = this.getQuery(terms); + global.log(this.title + ": Running query '" + query + "'"); + let cursor = conn.query(query, null); - global.log("Tracker: Filtering results..."); + global.log(this.title + ": Filtering results..."); return this.filterResults(cursor); }, getSubsearchResultSet : function(previousResults, terms) { - if(terms[0].length <= 2) { - global.log("Tracker: Ignoring search terms, length < 3"); + if(terms[0].length < 3) { + global.log(this.title + ": Ignoring search term:'" + terms + "', length < 3"); return []; } - global.log("Tracker: Searching for '" + terms + "'"); + global.log(this.title + ": Searching for '" + terms + "'"); return this.getInitialResultSet(terms); }, }; + + function init(meta) { } function enable() { - trackerSearchProvider = new TrackerSearchProvider(); - Main.overview.addSearchProvider(trackerSearchProvider); + trackerSearchProviderFolders = new TrackerSearchProvider("Folders", CategoryType.FOLDERS); + Main.overview.addSearchProvider(trackerSearchProviderFolders); + + trackerSearchProviderFiles = new TrackerSearchProvider("Files", CategoryType.FTS); + Main.overview.addSearchProvider(trackerSearchProviderFiles); } function disable() { - Main.overview.removeSearchProvider(trackerSearchProvider); - trackerSearchProvider = null; + Main.overview.removeSearchProvider(trackerSearchProviderFiles); + trackerSearchProviderFiles = null; + + Main.overview.removeSearchProvider(trackerSearchProviderFolders); + trackerSearchProviderFolders = null; } From 5b09679c5f09a7029c014c8f1564747471b93762 Mon Sep 17 00:00:00 2001 From: Christian Weber Date: Wed, 2 May 2012 23:00:32 +0200 Subject: [PATCH 06/17] removed debug output/ re-add file_exist check/ exclude folders from file search --- extension.js | 59 ++++++++++++++++++++++++---------------------------- 1 file changed, 27 insertions(+), 32 deletions(-) diff --git a/extension.js b/extension.js index 8062017..e86c3f9 100644 --- a/extension.js +++ b/extension.js @@ -26,6 +26,7 @@ const St = imports.gi.St; const DEFAULT_EXEC = 'xdg-open'; /* Limit search results, since number of displayed items is limited */ const MAX_RESULTS = 12; +const MAX_SEARCH_RESULTS_ROWS = 2; const CategoryType = { FTS : 0, @@ -47,7 +48,6 @@ TrackerSearchProvider.prototype = { _init : function(title, categoryType) { this._categoryType = categoryType; Search.SearchProvider.prototype._init.call(this, title + " (from Tracker)"); - global.log(this.title + ": Created provider (type:" + String(this._categoryType) + ")"); }, getResultMetas: function(resultIds) { @@ -66,7 +66,6 @@ TrackerSearchProvider.prototype = { 'name' : name, 'createIcon' : function(size) { let icon = Gio.app_info_get_default_for_type(type,null).get_icon(); - return imports.gi.St.TextureCache.get_default().load_gicon(null, icon, size); } }; @@ -75,29 +74,27 @@ TrackerSearchProvider.prototype = { activateResult : function(result) { // Action executed when clicked on result var uri = result.id; - var f = Gio.file_new_for_uri(uri); - var fileName = f.get_path(); - + var f = Gio.file_new_for_uri(uri); + var fileName = f.get_path(); Util.spawn([DEFAULT_EXEC, fileName]); }, getQuery : function (terms) { - // terms holds array of search items - // check if 1st search term is >2 letters else drop the request var query = ""; if (this._categoryType == CategoryType.FTS) { var terms_in_sparql = ""; - for (var i = 0; i < terms.length; i++) { - if (terms_in_sparql.length > 0) - terms_in_sparql += " "; - - terms_in_sparql += terms[i] + "*"; - } + for (var i = 0; i < terms.length; i++) { + if (terms_in_sparql.length > 0) terms_in_sparql += " "; + terms_in_sparql += terms[i] + "*"; + } // Technically, the tag should really be matched // separately not as one phrase too. - query += "SELECT ?urn nie:url(?urn) tracker:coalesce(nie:title(?urn), nfo:fileName(?urn)) nie:url(?parent) nfo:fileLastModified(?urn) WHERE { { ?urn a nfo:FileDataObject . ?urn fts:match \"" + terms_in_sparql + "\" } UNION { ?urn nao:hasTag ?tag . FILTER (fn:contains (fn:lower-case (nao:prefLabel(?tag)), \"" + terms + "\")) } OPTIONAL { ?urn nfo:belongsToContainer ?parent . } } ORDER BY DESC(nfo:fileLastModified(?urn)) ASC(nie:title(?urn)) OFFSET 0 LIMIT " + String(MAX_RESULTS); + query += "SELECT ?urn nie:url(?urn) tracker:coalesce(nie:title(?urn), nfo:fileName(?urn)) nie:url(?parent) nfo:fileLastModified(?urn) WHERE { { "; + query += " ?urn a nfo:FileDataObject ."; + query += " ?urn fts:match \"" + terms_in_sparql + "\" } UNION { ?urn nao:hasTag ?tag . FILTER (fn:contains (fn:lower-case (nao:prefLabel(?tag)), \"" + terms + "\")) }"; + query += " OPTIONAL { ?urn nfo:belongsToContainer ?parent . ?r2 a nfo:Folder . FILTER(?r2 = ?urn). } . FILTER(!BOUND(?r2)). } ORDER BY DESC(nfo:fileLastModified(?urn)) ASC(nie:title(?urn)) OFFSET 0 LIMIT " + String(MAX_RESULTS); } else if (this._categoryType == CategoryType.FILES) { // TODO: Do we really want this? @@ -123,11 +120,10 @@ TrackerSearchProvider.prototype = { var title = cursor.get_string(2)[0]; var parentUri = cursor.get_string(3)[0]; - global.log (this.title + ": uri '" + uri + "', title '" + title + "', parent uri '" + parentUri + "'"); - // if file does not exist, it won't be shown - var f = Gio.file_new_for_uri(uri); - var fileName = f.get_path(); + var f = Gio.file_new_for_uri(uri); + if(!f.query_exists(null)) {continue;} + var fileName = f.get_path(); // contentType is an array, the index "1" set true, // if function is uncertain if type is the right one @@ -137,7 +133,6 @@ TrackerSearchProvider.prototype = { if(contentType[1]){ if(newContentType == "application/octet-stream") { let fileInfo = Gio.file_new_for_path(fileName).query_info('standard::type', 0, null); - // for some reason 'content_type_guess' returns a wrong mime type for folders if(fileInfo.get_file_type() == Gio.FileType.DIRECTORY) { newContentType = "inode/directory"; @@ -163,29 +158,29 @@ TrackerSearchProvider.prototype = { }, getInitialResultSet : function(terms) { + // terms holds array of search items + // check if 1st search term is >2 letters else drop the request if(terms[0].length < 3) { - global.log(this.title + ": Ignoring search term:'" + terms + "', length < 3"); return []; } - let conn = Tracker.SparqlConnection.get(null); - - var query = this.getQuery(terms); - global.log(this.title + ": Running query '" + query + "'"); - let cursor = conn.query(query, null); - - global.log(this.title + ": Filtering results..."); + try { + var conn = Tracker.SparqlConnection.get(null); + var query = this.getQuery(terms); + var cursor = conn.query(query, null); + } catch (error) { + global.log("Querying Tracker failed. Please make sure you have the --GObject Introspection-- package for Tracker installed."); + global.log(error.message); + return []; + } return this.filterResults(cursor); }, getSubsearchResultSet : function(previousResults, terms) { - if(terms[0].length < 3) { - global.log(this.title + ": Ignoring search term:'" + terms + "', length < 3"); + // check if 1st search term is >2 letters else drop the request + if(terms[0].length < 3) { return []; } - - global.log(this.title + ": Searching for '" + terms + "'"); - return this.getInitialResultSet(terms); }, }; From 28e8a3f601db2719c5b7cb79880fc214fde87f0a Mon Sep 17 00:00:00 2001 From: Christian Weber Date: Sat, 5 May 2012 21:51:58 +0200 Subject: [PATCH 07/17] reworked result displaying, using setup from GCalcSearch (https://github.com/war1025/GCalcSearch) --- extension.js | 119 ++++++++++++++++++++++++++++++++++++++++--------- stylesheet.css | 28 ++++++++++++ 2 files changed, 126 insertions(+), 21 deletions(-) create mode 100644 stylesheet.css diff --git a/extension.js b/extension.js index e86c3f9..ef539b6 100644 --- a/extension.js +++ b/extension.js @@ -7,26 +7,27 @@ * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * - * Version 1.4 + * Version 1.5 * * https://github.com/cewee/tracker-search */ -const Main = imports.ui.main; -const Search = imports.ui.search; -const Gio = imports.gi.Gio; -const GLib = imports.gi.GLib; -const Lang = imports.lang; -const Shell = imports.gi.Shell; -const Util = imports.misc.util; -const Tracker = imports.gi.Tracker; -const St = imports.gi.St; +const Main = imports.ui.main; +const Search = imports.ui.search; +const SearchDisplay = imports.ui.searchDisplay; +const Gio = imports.gi.Gio; +const GLib = imports.gi.GLib; +const IconGrid = imports.ui.iconGrid; +const Util = imports.misc.util; +const Tracker = imports.gi.Tracker; +const St = imports.gi.St; /* let xdg-open pick the appropriate program to open/execute the file */ const DEFAULT_EXEC = 'xdg-open'; /* Limit search results, since number of displayed items is limited */ -const MAX_RESULTS = 12; -const MAX_SEARCH_RESULTS_ROWS = 2; +const MAX_RESULTS = 20; +const MAX_ROWS =3; // this is currently ignored, but bug report is filed : https://bugzilla.gnome.org/show_bug.cgi?id=675527 +const ICON_SIZE = 50; const CategoryType = { FTS : 0, @@ -34,9 +35,50 @@ const CategoryType = { FOLDERS : 2 }; +function TrackerResult(result) { + this._init(result); +} + +TrackerResult.prototype = { + _init: function(resultMeta) { + // Building Result Items to display + this.actor = new St.Bin({ reactive: true, track_hover: true }); + let MainBox = new St.BoxLayout( { style_class: 'result-content', vertical: true }); + this.actor.set_child(MainBox); + // title bar + let title = new St.Label({ text: resultMeta.name, style_class: 'title' }); + MainBox.add(title, { x_fill: false, x_align: St.Align.START }); + //box for icon and detailed information about the file + let IconInfoFrame = new St.BoxLayout({ style_class: 'icon-info-frame', vertical: false }); + let IconBox = new St.BoxLayout({ vertical: false }); + + MainBox.add(IconInfoFrame, { x_fill: false, x_align: St.Align.START }); + var icon = resultMeta.createIcon(ICON_SIZE); + + if (resultMeta.contentType != "inode/directory" ) { // skip file infos for folders + IconBox.add(icon, { x_fill: false, y_fill: false, x_align: St.Align.START, y_align: St.Align.MIDDLE }); + IconInfoFrame.add(IconBox, { x_fill: false, x_align: St.Align.START }); + + let SideBox = new St.BoxLayout({ style_class: 'side-box', vertical: true }); + IconInfoFrame.add(SideBox, { x_fill: false, x_align: St.Align.START }); + let fileName = new St.Label({ text: resultMeta.filename, style_class: 'result-detail' }); + SideBox.add(fileName, { x_fill: false, x_align: St.Align.START }); + let lastMod = new St.Label({ text: resultMeta.lastMod, style_class: 'result-detail' }); + SideBox.add(lastMod, { x_fill: false, x_align: St.Align.START }); + } else { + IconBox.add(icon, { x_fill: false, y_fill: false, x_align: St.Align.MIDDLE, y_align: St.Align.MIDDLE }); + IconInfoFrame.add(IconBox, { x_fill: false, x_align: St.Align.MIDDLE }); + } + // add path information + let prettyPath = new St.Label({ text: resultMeta.prettyPath, style_class: 'result-path' }); + MainBox.add(prettyPath, { x_fill: false, x_align: St.Align.START }); + } +}; + var trackerSearchProviderFiles = null; var trackerSearchProviderFolders = null; + function TrackerSearchProvider(title, categoryType) { this._init(title, categoryType); } @@ -61,9 +103,19 @@ TrackerSearchProvider.prototype = { getResultMeta : function(resultId) { let type = resultId.contentType; let name = resultId.name; + let path = resultId.path; + let filename = resultId.filename; + let lastMod = resultId.lastMod; + let contentType = resultId.contentType; + let prettyPath = resultId.prettyPath; return { - 'id' : resultId, - 'name' : name, + 'id': resultId, + 'name': name, + 'path': path, + 'filename': filename, + 'lastMod': lastMod, + 'prettyPath': prettyPath, + 'contentType': contentType, 'createIcon' : function(size) { let icon = Gio.app_info_get_default_for_type(type,null).get_icon(); return imports.gi.St.TextureCache.get_default().load_gicon(null, icon, size); @@ -119,20 +171,24 @@ TrackerSearchProvider.prototype = { var uri = cursor.get_string(1)[0]; var title = cursor.get_string(2)[0]; var parentUri = cursor.get_string(3)[0]; - + var lastMod = cursor.get_string(4)[0]; + var filename = decodeURI(uri.split('/').pop()); + // if file does not exist, it won't be shown var f = Gio.file_new_for_uri(uri); if(!f.query_exists(null)) {continue;} - var fileName = f.get_path(); - + var path = f.get_path(); + // clean up path + var prettyPath = path.replace("/home/" + GLib.get_user_name() , "~"); + // contentType is an array, the index "1" set true, // if function is uncertain if type is the right one - let contentType = Gio.content_type_guess(fileName, null); + let contentType = Gio.content_type_guess(path, null); var newContentType = contentType[0]; if(contentType[1]){ if(newContentType == "application/octet-stream") { - let fileInfo = Gio.file_new_for_path(fileName).query_info('standard::type', 0, null); + let fileInfo = Gio.file_new_for_path(path).query_info('standard::type', 0, null); // for some reason 'content_type_guess' returns a wrong mime type for folders if(fileInfo.get_file_type() == Gio.FileType.DIRECTORY) { newContentType = "inode/directory"; @@ -146,6 +202,10 @@ TrackerSearchProvider.prototype = { results.push({ 'id' : uri, 'name' : title, + 'path' : path, + 'filename': filename, + 'lastMod' : lastMod, + 'prettyPath' : prettyPath, 'contentType' : newContentType }); } @@ -182,10 +242,27 @@ TrackerSearchProvider.prototype = { return []; } return this.getInitialResultSet(terms); + }, + + // Display overwrites + createResultActor: function(resultMeta, terms) { + let result = new TrackerResult(resultMeta); + return result.actor; }, -}; - + createResultContainerActor: function() { + let grid = new IconGrid.IconGrid({ rowLimit: MAX_ROWS, columnLimit: MAX_RESULTS, + xAlign: St.Align.START }); + // global.log(grid); + grid.actor.style_class = 'tracker-grid'; + // global.log(grid._rowLimit); + + let actor = new SearchDisplay.GridSearchResults(this, grid); + // global.log(actor._grid._rowLimit); +// global.log(actor._grid._colLimit); + return actor; + }, +}; function init(meta) { } diff --git a/stylesheet.css b/stylesheet.css new file mode 100644 index 0000000..6b8512b --- /dev/null +++ b/stylesheet.css @@ -0,0 +1,28 @@ +.title { + font-size: 1.2em; + font-weight: bold; +} +.result-path { + font-size: .7em; +} +.result-detail { + padding-left: 7px; + font-size: .8em; +} +.icon-info-frame{ + padding-top: 5px; +} +.result-content { + border-radius: 7px; + padding: 10px; + width: 220px; + height: 95px; + background-color: rgba(0.0, 0.0, 0.0, 0.3); + color: white; +} +.tracker-grid { + spacing: 8px; + -shell-grid-horizontal-item-size: 230px; + -shell-grid-vertical-item-size: 110px; +} + From 282a90346e17d7bb58d3101c765d7cc75f739168 Mon Sep 17 00:00:00 2001 From: cewee Date: Sat, 5 May 2012 22:56:12 +0300 Subject: [PATCH 08/17] Update README --- README | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/README b/README index 3b54860..249286d 100644 --- a/README +++ b/README @@ -1,7 +1,10 @@ Tracker-Search Extension for Gnome-Shell -Version: 1.3 +Version: 1.4 -TODO: + +Done: * Display File Location -* Display more than one row of results +* Display more than one row of results (as soon as bug is fixed) + +TODO: \ No newline at end of file From c277010a76769b60f1c14d87bb497763aed71e9a Mon Sep 17 00:00:00 2001 From: Christian Weber Date: Sat, 5 May 2012 22:39:20 +0200 Subject: [PATCH 09/17] css change, modified date fix --- extension.js | 3 ++- stylesheet.css | 2 ++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/extension.js b/extension.js index ef539b6..018fa27 100644 --- a/extension.js +++ b/extension.js @@ -172,6 +172,7 @@ TrackerSearchProvider.prototype = { var title = cursor.get_string(2)[0]; var parentUri = cursor.get_string(3)[0]; var lastMod = cursor.get_string(4)[0]; + var lastMod = "Modified: " + lastMod.split('T')[0]; var filename = decodeURI(uri.split('/').pop()); // if file does not exist, it won't be shown @@ -179,7 +180,7 @@ TrackerSearchProvider.prototype = { if(!f.query_exists(null)) {continue;} var path = f.get_path(); // clean up path - var prettyPath = path.replace("/home/" + GLib.get_user_name() , "~"); + var prettyPath = path.substr(0,path.length - filename.length).replace("/home/" + GLib.get_user_name() , "~"); // contentType is an array, the index "1" set true, // if function is uncertain if type is the right one diff --git a/stylesheet.css b/stylesheet.css index 6b8512b..1c21c7f 100644 --- a/stylesheet.css +++ b/stylesheet.css @@ -7,7 +7,9 @@ } .result-detail { padding-left: 7px; + padding-bottom: 4px; font-size: .8em; + color:rgb(200,200,200); } .icon-info-frame{ padding-top: 5px; From 3ea7a7ef1bb8d87891c49fa9e6be858f155bb4d5 Mon Sep 17 00:00:00 2001 From: Christian Weber Date: Sun, 6 May 2012 18:31:04 +0200 Subject: [PATCH 10/17] fix folder display, changes on css --- extension.js | 52 +++++++++++++++++++++++--------------------------- stylesheet.css | 31 ++++++++++++++++++++++++++++-- 2 files changed, 53 insertions(+), 30 deletions(-) diff --git a/extension.js b/extension.js index 018fa27..a5e106b 100644 --- a/extension.js +++ b/extension.js @@ -43,35 +43,33 @@ TrackerResult.prototype = { _init: function(resultMeta) { // Building Result Items to display this.actor = new St.Bin({ reactive: true, track_hover: true }); - let MainBox = new St.BoxLayout( { style_class: 'result-content', vertical: true }); + var MainBox = new St.BoxLayout( { style_class: 'result-content', vertical: true }); this.actor.set_child(MainBox); - // title bar - let title = new St.Label({ text: resultMeta.name, style_class: 'title' }); - MainBox.add(title, { x_fill: false, x_align: St.Align.START }); - //box for icon and detailed information about the file - let IconInfoFrame = new St.BoxLayout({ style_class: 'icon-info-frame', vertical: false }); - let IconBox = new St.BoxLayout({ vertical: false }); - - MainBox.add(IconInfoFrame, { x_fill: false, x_align: St.Align.START }); - var icon = resultMeta.createIcon(ICON_SIZE); - - if (resultMeta.contentType != "inode/directory" ) { // skip file infos for folders + var icon = resultMeta.createIcon(ICON_SIZE); + + if (resultMeta.contentType != "inode/directory" ) { + let title = new St.Label({ text: resultMeta.name, style_class: 'title' }); + MainBox.add(title, { x_fill: false, x_align: St.Align.START }); + let IconInfoFrame = new St.BoxLayout({ style_class: 'icon-info-frame', vertical: false }); + let IconBox = new St.BoxLayout({ vertical: false }); + MainBox.add(IconInfoFrame, { x_fill: false, x_align: St.Align.START, y_align: St.Align.MIDDLE }); IconBox.add(icon, { x_fill: false, y_fill: false, x_align: St.Align.START, y_align: St.Align.MIDDLE }); IconInfoFrame.add(IconBox, { x_fill: false, x_align: St.Align.START }); - let SideBox = new St.BoxLayout({ style_class: 'side-box', vertical: true }); IconInfoFrame.add(SideBox, { x_fill: false, x_align: St.Align.START }); let fileName = new St.Label({ text: resultMeta.filename, style_class: 'result-detail' }); SideBox.add(fileName, { x_fill: false, x_align: St.Align.START }); let lastMod = new St.Label({ text: resultMeta.lastMod, style_class: 'result-detail' }); SideBox.add(lastMod, { x_fill: false, x_align: St.Align.START }); - } else { - IconBox.add(icon, { x_fill: false, y_fill: false, x_align: St.Align.MIDDLE, y_align: St.Align.MIDDLE }); - IconInfoFrame.add(IconBox, { x_fill: false, x_align: St.Align.MIDDLE }); - } - // add path information - let prettyPath = new St.Label({ text: resultMeta.prettyPath, style_class: 'result-path' }); - MainBox.add(prettyPath, { x_fill: false, x_align: St.Align.START }); + let prettyPath = new St.Label({ text: resultMeta.prettyPath, style_class: 'result-path' }); + MainBox.add(prettyPath, { x_fill: false, x_align: St.Align.START }); + } else { + let titleDir = new St.Label({ text: resultMeta.name, style_class: 'titleDir' }); + MainBox.add(titleDir, { x_fill: false, y_fill: true, x_align: St.Align.START, y_align: St.Align.MIDDLE }); + let prettyPath = new St.Label({ text: resultMeta.prettyPath, style_class: 'result-pathDir' }); + MainBox.add(prettyPath, { x_fill: false, x_align: St.Align.START }); + MainBox.add(icon, { x_fill: false, y_fill: false, x_align: St.Align.MIDDLE, y_align: St.Align.MIDDLE }); + } } }; @@ -252,15 +250,13 @@ TrackerSearchProvider.prototype = { }, createResultContainerActor: function() { - let grid = new IconGrid.IconGrid({ rowLimit: MAX_ROWS, columnLimit: MAX_RESULTS, - xAlign: St.Align.START }); - // global.log(grid); - grid.actor.style_class = 'tracker-grid'; - // global.log(grid._rowLimit); - + let grid = new IconGrid.IconGrid({ rowLimit: MAX_ROWS, columnLimit: MAX_RESULTS, xAlign: St.Align.START }); + if (this._categoryType == CategoryType.FTS) { + grid.actor.style_class = 'tracker-grid'; + } else if (this._categoryType == CategoryType.FOLDERS){ + grid.actor.style_class = 'tracker-folder-grid'; + } let actor = new SearchDisplay.GridSearchResults(this, grid); - // global.log(actor._grid._rowLimit); -// global.log(actor._grid._colLimit); return actor; }, }; diff --git a/stylesheet.css b/stylesheet.css index 1c21c7f..f98d17e 100644 --- a/stylesheet.css +++ b/stylesheet.css @@ -2,6 +2,15 @@ font-size: 1.2em; font-weight: bold; } +.titleDir { + font-size: 1em; + padding-left: 7px; + font-weight: bold; +} +.result-pathDir { + padding-left: 7px; + font-size: .7em; +} .result-path { font-size: .7em; } @@ -14,6 +23,15 @@ .icon-info-frame{ padding-top: 5px; } + +.directory-content { + border-radius: 7px; + padding: 10px; + width: 170px; + height: 90px; + background-color: rgba(0.0, 0.0, 0.0, 0.55); + color: white; +} .result-content { border-radius: 7px; padding: 10px; @@ -24,7 +42,16 @@ } .tracker-grid { spacing: 8px; - -shell-grid-horizontal-item-size: 230px; + -shell-grid-horizontal-item-size: 200px; -shell-grid-vertical-item-size: 110px; + transition-duration: 100; +} +.tracker-folder-grid { + spacing: 8px; + -shell-grid-horizontal-item-size: 170px; + -shell-grid-vertical-item-size: 95px; +} +.tracker-grid:hover { + background-color: rgba(255,255,255,0.1); + transition-duration: 100; } - From 5f32f44342e79ac5c31de22ca1c7feab008f7202 Mon Sep 17 00:00:00 2001 From: Christian Weber Date: Sun, 6 May 2012 18:42:30 +0200 Subject: [PATCH 11/17] cleanup, update descriptio --- extension.js | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/extension.js b/extension.js index a5e106b..7b5f595 100644 --- a/extension.js +++ b/extension.js @@ -1,6 +1,6 @@ /* Tracker Search Provider for Gnome Shell * - * Copyright (c) 2012 Christian Weber, Felix Schultze + * 2012 Contributors Christian Weber, Felix Schultze, Martyn Russell * * This programm is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -39,14 +39,14 @@ function TrackerResult(result) { this._init(result); } +// Overwriting layout to display search results. TrackerResult.prototype = { _init: function(resultMeta) { - // Building Result Items to display this.actor = new St.Bin({ reactive: true, track_hover: true }); var MainBox = new St.BoxLayout( { style_class: 'result-content', vertical: true }); this.actor.set_child(MainBox); var icon = resultMeta.createIcon(ICON_SIZE); - + // View for regular files if (resultMeta.contentType != "inode/directory" ) { let title = new St.Label({ text: resultMeta.name, style_class: 'title' }); MainBox.add(title, { x_fill: false, x_align: St.Align.START }); @@ -63,7 +63,7 @@ TrackerResult.prototype = { SideBox.add(lastMod, { x_fill: false, x_align: St.Align.START }); let prettyPath = new St.Label({ text: resultMeta.prettyPath, style_class: 'result-path' }); MainBox.add(prettyPath, { x_fill: false, x_align: St.Align.START }); - } else { + } else { // View for folder elements let titleDir = new St.Label({ text: resultMeta.name, style_class: 'titleDir' }); MainBox.add(titleDir, { x_fill: false, y_fill: true, x_align: St.Align.START, y_align: St.Align.MIDDLE }); let prettyPath = new St.Label({ text: resultMeta.prettyPath, style_class: 'result-pathDir' }); @@ -145,6 +145,7 @@ TrackerSearchProvider.prototype = { query += " ?urn a nfo:FileDataObject ."; query += " ?urn fts:match \"" + terms_in_sparql + "\" } UNION { ?urn nao:hasTag ?tag . FILTER (fn:contains (fn:lower-case (nao:prefLabel(?tag)), \"" + terms + "\")) }"; query += " OPTIONAL { ?urn nfo:belongsToContainer ?parent . ?r2 a nfo:Folder . FILTER(?r2 = ?urn). } . FILTER(!BOUND(?r2)). } ORDER BY DESC(nfo:fileLastModified(?urn)) ASC(nie:title(?urn)) OFFSET 0 LIMIT " + String(MAX_RESULTS); + // ?r2 a nfo:Folder . FILTER(?r2 = ?urn). } . FILTER(!BOUND(?r2) is supposed to filter out folders, but this fails for 'root' folders in which is indexed (as 'Music', 'Documents' and so on ..) - WHY? } else if (this._categoryType == CategoryType.FILES) { // TODO: Do we really want this? @@ -172,19 +173,16 @@ TrackerSearchProvider.prototype = { var lastMod = cursor.get_string(4)[0]; var lastMod = "Modified: " + lastMod.split('T')[0]; var filename = decodeURI(uri.split('/').pop()); - // if file does not exist, it won't be shown var f = Gio.file_new_for_uri(uri); if(!f.query_exists(null)) {continue;} var path = f.get_path(); // clean up path - var prettyPath = path.substr(0,path.length - filename.length).replace("/home/" + GLib.get_user_name() , "~"); - + var prettyPath = path.substr(0,path.length - filename.length).replace("/home/" + GLib.get_user_name() , "~"); // contentType is an array, the index "1" set true, // if function is uncertain if type is the right one let contentType = Gio.content_type_guess(path, null); var newContentType = contentType[0]; - if(contentType[1]){ if(newContentType == "application/octet-stream") { let fileInfo = Gio.file_new_for_path(path).query_info('standard::type', 0, null); @@ -197,7 +195,6 @@ TrackerSearchProvider.prototype = { } } } - results.push({ 'id' : uri, 'name' : title, From 555bab3866cf4b204aef3194e9b813b88c72328b Mon Sep 17 00:00:00 2001 From: Christian Weber Date: Wed, 31 Oct 2012 07:38:22 +0100 Subject: [PATCH 12/17] updated extension to 3.6 (no longer compatible with lower GS versions!) --- README | 3 ++- extension.js | 25 ++++++++++++++----------- stylesheet.css | 44 +++++++++++++++++++++----------------------- 3 files changed, 37 insertions(+), 35 deletions(-) diff --git a/README b/README index 249286d..3cfd0a2 100644 --- a/README +++ b/README @@ -7,4 +7,5 @@ Done: * Display File Location * Display more than one row of results (as soon as bug is fixed) -TODO: \ No newline at end of file +TODO: +* Fix CSS, no more transitions on mouse hover ... diff --git a/extension.js b/extension.js index 7b5f595..f434b74 100644 --- a/extension.js +++ b/extension.js @@ -17,6 +17,7 @@ const Search = imports.ui.search; const SearchDisplay = imports.ui.searchDisplay; const Gio = imports.gi.Gio; const GLib = imports.gi.GLib; +const Shell = imports.gi.Shell; const IconGrid = imports.ui.iconGrid; const Util = imports.misc.util; const Tracker = imports.gi.Tracker; @@ -26,8 +27,8 @@ const St = imports.gi.St; const DEFAULT_EXEC = 'xdg-open'; /* Limit search results, since number of displayed items is limited */ const MAX_RESULTS = 20; -const MAX_ROWS =3; // this is currently ignored, but bug report is filed : https://bugzilla.gnome.org/show_bug.cgi?id=675527 -const ICON_SIZE = 50; +const MAX_ROWS = 3; // this is currently ignored, but bug report is filed : https://bugzilla.gnome.org/show_bug.cgi?id=675527 +const ICON_SIZE = 25; const CategoryType = { FTS : 0, @@ -42,7 +43,7 @@ function TrackerResult(result) { // Overwriting layout to display search results. TrackerResult.prototype = { _init: function(resultMeta) { - this.actor = new St.Bin({ reactive: true, track_hover: true }); + this.actor = new St.Bin({ reactive: true}); var MainBox = new St.BoxLayout( { style_class: 'result-content', vertical: true }); this.actor.set_child(MainBox); var icon = resultMeta.createIcon(ICON_SIZE); @@ -87,15 +88,16 @@ TrackerSearchProvider.prototype = { _init : function(title, categoryType) { this._categoryType = categoryType; - Search.SearchProvider.prototype._init.call(this, title + " (from Tracker)"); + Search.SearchProvider.prototype._init.call(this, title + " (from Tracker)"); }, - getResultMetas: function(resultIds) { + getResultMetas: function(resultIds,callback) { let metas = []; for (let i = 0; i < resultIds.length; i++) { metas.push(this.getResultMeta(resultIds[i])); } - return metas; + callback(metas); +// return metas; }, getResultMeta : function(resultId) { @@ -163,7 +165,6 @@ TrackerSearchProvider.prototype = { filterResults : function(cursor) { let results = []; - try { while (cursor != null && cursor.next(null)) { var urn = cursor.get_string(0)[0]; @@ -171,7 +172,7 @@ TrackerSearchProvider.prototype = { var title = cursor.get_string(2)[0]; var parentUri = cursor.get_string(3)[0]; var lastMod = cursor.get_string(4)[0]; - var lastMod = "Modified: " + lastMod.split('T')[0]; + var lastMod = lastMod.split('T')[0]; var filename = decodeURI(uri.split('/').pop()); // if file does not exist, it won't be shown var f = Gio.file_new_for_uri(uri); @@ -209,7 +210,6 @@ TrackerSearchProvider.prototype = { global.log(this.title + ": Could not traverse results cursor: " + error.message); return []; } - return (results.length > 0) ? results : []; }, @@ -229,7 +229,9 @@ TrackerSearchProvider.prototype = { global.log(error.message); return []; } - return this.filterResults(cursor); + +// return this.filterResults(cursor); +return this.searchSystem.pushResults(this, this.filterResults(cursor) ); }, getSubsearchResultSet : function(previousResults, terms) { @@ -247,7 +249,7 @@ TrackerSearchProvider.prototype = { }, createResultContainerActor: function() { - let grid = new IconGrid.IconGrid({ rowLimit: MAX_ROWS, columnLimit: MAX_RESULTS, xAlign: St.Align.START }); + let grid = new IconGrid.IconGrid({ rowLimit: MAX_ROWS, columnLimit: MAX_RESULTS, xAlign: St.Align.MIDDLE }); if (this._categoryType == CategoryType.FTS) { grid.actor.style_class = 'tracker-grid'; } else if (this._categoryType == CategoryType.FOLDERS){ @@ -276,3 +278,4 @@ function disable() { Main.overview.removeSearchProvider(trackerSearchProviderFolders); trackerSearchProviderFolders = null; } + diff --git a/stylesheet.css b/stylesheet.css index f98d17e..c87307d 100644 --- a/stylesheet.css +++ b/stylesheet.css @@ -1,18 +1,17 @@ .title { - font-size: 1.2em; - font-weight: bold; + font-size: .8em; + } .titleDir { - font-size: 1em; + font-size: .9em; padding-left: 7px; - font-weight: bold; } .result-pathDir { padding-left: 7px; font-size: .7em; } .result-path { - font-size: .7em; + font-size: .6em; } .result-detail { padding-left: 7px; @@ -27,31 +26,30 @@ .directory-content { border-radius: 7px; padding: 10px; - width: 170px; - height: 90px; + width: 100px; + height: 50px; background-color: rgba(0.0, 0.0, 0.0, 0.55); color: white; } .result-content { border-radius: 7px; - padding: 10px; - width: 220px; - height: 95px; + padding: 4px; + width: 100px; + height: 70px; background-color: rgba(0.0, 0.0, 0.0, 0.3); color: white; } + + + .tracker-grid { - spacing: 8px; - -shell-grid-horizontal-item-size: 200px; - -shell-grid-vertical-item-size: 110px; - transition-duration: 100; -} -.tracker-folder-grid { - spacing: 8px; - -shell-grid-horizontal-item-size: 170px; - -shell-grid-vertical-item-size: 95px; -} -.tracker-grid:hover { - background-color: rgba(255,255,255,0.1); - transition-duration: 100; + border-radius: 7px; + padding: 4px; + width: 200px; + height: 70px; + } + + + + From 6bdbb78a771609ebe5c2e3a7bd4824e434bca03d Mon Sep 17 00:00:00 2001 From: Christian Weber Date: Fri, 2 Nov 2012 20:27:20 +0100 Subject: [PATCH 13/17] updated extension to 3.6 (no longer compatible with lower GS versions!) --- extension.js | 18 ++++++------------ metadata.json | 15 ++++++--------- stylesheet.css | 4 ++-- 3 files changed, 14 insertions(+), 23 deletions(-) diff --git a/extension.js b/extension.js index f434b74..3f267ba 100644 --- a/extension.js +++ b/extension.js @@ -7,7 +7,7 @@ * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * - * Version 1.5 + * Version 1.7 * * https://github.com/cewee/tracker-search */ @@ -26,7 +26,7 @@ const St = imports.gi.St; /* let xdg-open pick the appropriate program to open/execute the file */ const DEFAULT_EXEC = 'xdg-open'; /* Limit search results, since number of displayed items is limited */ -const MAX_RESULTS = 20; +const MAX_RESULTS = 40; const MAX_ROWS = 3; // this is currently ignored, but bug report is filed : https://bugzilla.gnome.org/show_bug.cgi?id=675527 const ICON_SIZE = 25; @@ -88,6 +88,9 @@ TrackerSearchProvider.prototype = { _init : function(title, categoryType) { this._categoryType = categoryType; + var grid = new IconGrid.IconGrid({ rowLimit: MAX_ROWS, columnLimit: 8, xAlign: St.Align.MIDDLE }); + var actor = new SearchDisplay.GridSearchResults(this, grid); + this._grid = grid; Search.SearchProvider.prototype._init.call(this, title + " (from Tracker)"); }, @@ -248,16 +251,7 @@ return this.searchSystem.pushResults(this, this.filterResults(cursor) ); return result.actor; }, - createResultContainerActor: function() { - let grid = new IconGrid.IconGrid({ rowLimit: MAX_ROWS, columnLimit: MAX_RESULTS, xAlign: St.Align.MIDDLE }); - if (this._categoryType == CategoryType.FTS) { - grid.actor.style_class = 'tracker-grid'; - } else if (this._categoryType == CategoryType.FOLDERS){ - grid.actor.style_class = 'tracker-folder-grid'; - } - let actor = new SearchDisplay.GridSearchResults(this, grid); - return actor; - }, + }; function init(meta) { diff --git a/metadata.json b/metadata.json index 52bf189..510e3f5 100644 --- a/metadata.json +++ b/metadata.json @@ -1,13 +1,10 @@ { - "description": "Search Provider for Tracker", + "description": "Integrates Tracker-Search into the Gnome-Shell desktop.\r\nDepends on Tracker beeing installed and running (http://projects.gnome.org/tracker/) , as well as the GObject Introspection package for Tracker (for Ubuntu that is gir1.2-tracker).", "name": "Tracker Search", "shell-version": [ - "3.2", - "3.4" - ], - "url": "https://github.com/cewee/tracker-search", - "uuid": "tracker-search@cewee", - "version": 3 + "3.6" + ], + "url": "https://github.com/cewee/tracker-search", + "uuid": "tracker-search@cewee", + "version": 8 } - - diff --git a/stylesheet.css b/stylesheet.css index c87307d..d51a90d 100644 --- a/stylesheet.css +++ b/stylesheet.css @@ -34,7 +34,7 @@ .result-content { border-radius: 7px; padding: 4px; - width: 100px; + width: 200px; height: 70px; background-color: rgba(0.0, 0.0, 0.0, 0.3); color: white; @@ -45,7 +45,7 @@ .tracker-grid { border-radius: 7px; padding: 4px; - width: 200px; + width: 300px; height: 70px; } From 239e19f653847963358f0f5d84e42daeab18217d Mon Sep 17 00:00:00 2001 From: Christian Weber Date: Fri, 2 Nov 2012 20:38:32 +0100 Subject: [PATCH 14/17] Added Bug-Report number for ignores multi-row property. --- extension.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extension.js b/extension.js index 3f267ba..0f7c276 100644 --- a/extension.js +++ b/extension.js @@ -27,7 +27,7 @@ const St = imports.gi.St; const DEFAULT_EXEC = 'xdg-open'; /* Limit search results, since number of displayed items is limited */ const MAX_RESULTS = 40; -const MAX_ROWS = 3; // this is currently ignored, but bug report is filed : https://bugzilla.gnome.org/show_bug.cgi?id=675527 +const MAX_ROWS = 3; // this is currently ignored, but bug report is filed : https://bugzilla.gnome.org/show_bug.cgi?id=687474 const ICON_SIZE = 25; const CategoryType = { From 838e25d280ff89977eeddaca80d6645ea3359ee2 Mon Sep 17 00:00:00 2001 From: Richard Henwood Date: Wed, 7 Nov 2012 22:39:47 -0600 Subject: [PATCH 15/17] FIX: hack to make tracker search work with 3.6.1 Ubuntu 12.10 ships with gnome-shell 3.6.1. This hack makes the extension work on 12.10. Technical Debt: the uuid of the extension has been changed to match the folder that is defined by the project. This doesn't look like other extensions that are commonly available so fixing the folder name and then the uuid in the metadata.json remains an open task. --- metadata.json | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/metadata.json b/metadata.json index 510e3f5..6d05c30 100644 --- a/metadata.json +++ b/metadata.json @@ -2,9 +2,10 @@ "description": "Integrates Tracker-Search into the Gnome-Shell desktop.\r\nDepends on Tracker beeing installed and running (http://projects.gnome.org/tracker/) , as well as the GObject Introspection package for Tracker (for Ubuntu that is gir1.2-tracker).", "name": "Tracker Search", "shell-version": [ - "3.6" + "3.6", + "3.6.1" ], "url": "https://github.com/cewee/tracker-search", - "uuid": "tracker-search@cewee", + "uuid": "tracker-search", "version": 8 } From b4dcb658b438fd0a745a0bbff9105203befb66f7 Mon Sep 17 00:00:00 2001 From: cewee Date: Thu, 8 Nov 2012 09:49:36 +0100 Subject: [PATCH 16/17] Update metadata.json --- metadata.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/metadata.json b/metadata.json index 6d05c30..757b6d7 100644 --- a/metadata.json +++ b/metadata.json @@ -6,6 +6,6 @@ "3.6.1" ], "url": "https://github.com/cewee/tracker-search", - "uuid": "tracker-search", + "uuid": "tracker-search@cewee", "version": 8 } From b27919893ff4358a044db6bd77f11375ba2457c3 Mon Sep 17 00:00:00 2001 From: Summers Pittman Date: Sun, 10 Feb 2013 13:24:55 -0500 Subject: [PATCH 17/17] Added styling and support for navigating items via keyboard --- extension.js | 7 ++++++- stylesheet.css | 22 ++++++++++++++++++++++ 2 files changed, 28 insertions(+), 1 deletion(-) diff --git a/extension.js b/extension.js index 0f7c276..9c37393 100644 --- a/extension.js +++ b/extension.js @@ -22,6 +22,7 @@ const IconGrid = imports.ui.iconGrid; const Util = imports.misc.util; const Tracker = imports.gi.Tracker; const St = imports.gi.St; +const Atk = imports.gi.Atk; /* let xdg-open pick the appropriate program to open/execute the file */ const DEFAULT_EXEC = 'xdg-open'; @@ -43,7 +44,11 @@ function TrackerResult(result) { // Overwriting layout to display search results. TrackerResult.prototype = { _init: function(resultMeta) { - this.actor = new St.Bin({ reactive: true}); + this.actor = new St.Bin({ style_class: 'result', + reactive: true, + can_focus: true, + track_hover: true, + accessible_role: Atk.Role.PUSH_BUTTON}); var MainBox = new St.BoxLayout( { style_class: 'result-content', vertical: true }); this.actor.set_child(MainBox); var icon = resultMeta.createIcon(ICON_SIZE); diff --git a/stylesheet.css b/stylesheet.css index d51a90d..131b248 100644 --- a/stylesheet.css +++ b/stylesheet.css @@ -31,6 +31,16 @@ background-color: rgba(0.0, 0.0, 0.0, 0.55); color: white; } + +.result { + width: 272px; /* Same width as two normal results + spacing */ + height: 118px; /* Aspect ratio = 1.75. Normal US business card ratio */ + border-radius: 4px; + padding: 3px; + border: 1px rgba(0,0,0,0); + transition-duration: 100; +} + .result-content { border-radius: 7px; padding: 4px; @@ -40,7 +50,19 @@ color: white; } +.result:hover { + background-color: rgba(255,255,255,0.1); + transition-duration: 100; +} +.result:focus, +.app-well-app:focus > .overview-icon, +.search-result-content:focus > .overview-icon, +.result:selected, +.app-well-app:selected > .overview-icon, +.search-result-content:selected > .overview-icon { + background-color: rgba(255,255,255,0.33); +} .tracker-grid { border-radius: 7px;