summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--libnautilus-private/Makefile.am2
-rw-r--r--libnautilus-private/nautilus-column-utilities.c20
-rw-r--r--libnautilus-private/nautilus-file-private.h2
-rw-r--r--libnautilus-private/nautilus-file.c102
-rw-r--r--libnautilus-private/nautilus-file.h6
-rw-r--r--libnautilus-private/nautilus-search-directory.c18
-rw-r--r--libnautilus-private/nautilus-search-engine-simple.c72
-rw-r--r--libnautilus-private/nautilus-search-engine-tracker.c38
-rw-r--r--libnautilus-private/nautilus-search-engine.c14
-rw-r--r--libnautilus-private/nautilus-search-hit.c327
-rw-r--r--libnautilus-private/nautilus-search-hit.h63
-rw-r--r--libnautilus-private/nautilus-search-provider.h1
12 files changed, 614 insertions, 51 deletions
diff --git a/libnautilus-private/Makefile.am b/libnautilus-private/Makefile.am
index ee613e066..6512a1c67 100644
--- a/libnautilus-private/Makefile.am
+++ b/libnautilus-private/Makefile.am
@@ -162,6 +162,8 @@ libnautilus_private_la_SOURCES = \
nautilus-search-engine.h \
nautilus-search-engine-simple.c \
nautilus-search-engine-simple.h \
+ nautilus-search-hit.c \
+ nautilus-search-hit.h \
nautilus-selection-canvas-item.c \
nautilus-selection-canvas-item.h \
nautilus-signaller.h \
diff --git a/libnautilus-private/nautilus-column-utilities.c b/libnautilus-private/nautilus-column-utilities.c
index 9302738ef..8380a9432 100644
--- a/libnautilus-private/nautilus-column-utilities.c
+++ b/libnautilus-private/nautilus-column-utilities.c
@@ -191,6 +191,24 @@ get_trash_columns (void)
return nautilus_column_list_copy (columns);
}
+static GList *
+get_search_columns (void)
+{
+ static GList *columns = NULL;
+
+ if (columns == NULL) {
+ columns = g_list_append (columns,
+ g_object_new (NAUTILUS_TYPE_COLUMN,
+ "name", "search_relevance",
+ "attribute", "search_relevance",
+ "label", _("Relevance"),
+ "description", _("Relevance rank for search"),
+ NULL));
+ }
+
+ return nautilus_column_list_copy (columns);
+}
+
GList *
nautilus_get_common_columns (void)
{
@@ -211,6 +229,8 @@ nautilus_get_all_columns (void)
columns = g_list_concat (nautilus_get_common_columns (),
get_trash_columns ());
+ columns = g_list_concat (columns,
+ get_search_columns ());
return columns;
}
diff --git a/libnautilus-private/nautilus-file-private.h b/libnautilus-private/nautilus-file-private.h
index 09ecc8aa1..ff58386ce 100644
--- a/libnautilus-private/nautilus-file-private.h
+++ b/libnautilus-private/nautilus-file-private.h
@@ -220,6 +220,8 @@ struct NautilusFileDetails
time_t trash_time; /* 0 is unknown */
+ gdouble search_relevance;
+
guint64 free_space; /* (guint)-1 for unknown */
time_t free_space_read; /* The time free_space was updated, or 0 for never */
};
diff --git a/libnautilus-private/nautilus-file.c b/libnautilus-private/nautilus-file.c
index 01ffa78d5..6d704e49f 100644
--- a/libnautilus-private/nautilus-file.c
+++ b/libnautilus-private/nautilus-file.c
@@ -130,6 +130,7 @@ static GQuark attribute_name_q,
attribute_deep_file_count_q,
attribute_deep_directory_count_q,
attribute_deep_total_count_q,
+ attribute_search_relevance_q,
attribute_trashed_on_q,
attribute_trashed_on_full_q,
attribute_trash_orig_path_q,
@@ -2986,6 +2987,49 @@ compare_by_type (NautilusFile *file_1, NautilusFile *file_2)
return result;
}
+static Knowledge
+get_search_relevance (NautilusFile *file,
+ gdouble *relevance_out)
+{
+ if (!nautilus_file_is_in_search (file)) {
+ return UNKNOWABLE;
+ }
+
+ *relevance_out = file->details->search_relevance;
+
+ return KNOWN;
+}
+
+static int
+compare_by_search_relevance (NautilusFile *file_1, NautilusFile *file_2)
+{
+ gdouble r_1, r_2;
+ Knowledge known_1, known_2;
+
+ known_1 = get_search_relevance (file_1, &r_1);
+ known_2 = get_search_relevance (file_2, &r_2);
+
+ if (known_1 > known_2) {
+ return -1;
+ }
+ if (known_1 < known_2) {
+ return +1;
+ }
+
+ if (known_1 == UNKNOWABLE || known_1 == UNKNOWN) {
+ return 0;
+ }
+
+ if (r_1 < r_2) {
+ return -1;
+ }
+ if (r_1 > r_2) {
+ return +1;
+ }
+
+ return 0;
+}
+
static int
compare_by_time (NautilusFile *file_1, NautilusFile *file_2, NautilusDateType type)
{
@@ -3145,6 +3189,12 @@ nautilus_file_compare_for_sort (NautilusFile *file_1,
result = compare_by_full_path (file_1, file_2);
}
break;
+ case NAUTILUS_FILE_SORT_BY_SEARCH_RELEVANCE:
+ result = compare_by_search_relevance (file_1, file_2);
+ if (result == 0) {
+ result = compare_by_full_path (file_1, file_2);
+ }
+ break;
default:
g_return_val_if_reached (0);
}
@@ -3203,6 +3253,11 @@ nautilus_file_compare_for_sort_by_attribute_q (NautilusFile
NAUTILUS_FILE_SORT_BY_TRASHED_TIME,
directories_first,
reversed);
+ } else if (attribute == attribute_search_relevance_q) {
+ return nautilus_file_compare_for_sort (file_1, file_2,
+ NAUTILUS_FILE_SORT_BY_SEARCH_RELEVANCE,
+ directories_first,
+ reversed);
}
/* it is a normal attribute, compare by strings */
@@ -3332,6 +3387,19 @@ nautilus_file_is_in_desktop (NautilusFile *file)
return FALSE;
}
+gboolean
+nautilus_file_is_in_search (NautilusFile *file)
+{
+ char *uri;
+ gboolean ret;
+
+ uri = nautilus_file_get_uri (file);
+ ret = eel_uri_is_search (uri);
+ g_free (uri);
+
+ return ret;
+}
+
static gboolean
filter_hidden_partition_callback (gpointer data,
gpointer callback_data)
@@ -4772,6 +4840,12 @@ nautilus_file_set_attributes (NautilusFile *file,
g_object_unref (location);
}
+void
+nautilus_file_set_search_relevance (NautilusFile *file,
+ gdouble relevance)
+{
+ file->details->search_relevance = relevance;
+}
/**
* nautilus_file_can_get_permissions:
@@ -7415,13 +7489,15 @@ static gboolean
get_attributes_for_default_sort_type (NautilusFile *file,
gboolean *is_recent,
gboolean *is_download,
- gboolean *is_trash)
+ gboolean *is_trash,
+ gboolean *is_search)
{
- gboolean is_recent_dir, is_download_dir, is_desktop_dir, is_trash_dir, retval;
+ gboolean is_recent_dir, is_download_dir, is_desktop_dir, is_trash_dir, is_search_dir, retval;
*is_recent = FALSE;
*is_download = FALSE;
*is_trash = FALSE;
+ *is_search = FALSE;
retval = FALSE;
/* special handling for certain directories */
@@ -7434,6 +7510,8 @@ get_attributes_for_default_sort_type (NautilusFile *file,
nautilus_file_is_user_special_directory (file, G_USER_DIRECTORY_DESKTOP);
is_trash_dir =
nautilus_file_is_in_trash (file);
+ is_search_dir =
+ nautilus_file_is_in_search (file);
if (is_download_dir && !is_desktop_dir) {
*is_download = TRUE;
@@ -7444,6 +7522,9 @@ get_attributes_for_default_sort_type (NautilusFile *file,
} else if (is_recent_dir) {
*is_recent = TRUE;
retval = TRUE;
+ } else if (is_search_dir) {
+ *is_search = TRUE;
+ retval = TRUE;
}
}
@@ -7455,17 +7536,19 @@ nautilus_file_get_default_sort_type (NautilusFile *file,
gboolean *reversed)
{
NautilusFileSortType retval;
- gboolean is_recent, is_download, is_trash, res;
+ gboolean is_recent, is_download, is_trash, is_search, res;
retval = NAUTILUS_FILE_SORT_NONE;
- is_recent = is_download = is_trash = FALSE;
- res = get_attributes_for_default_sort_type (file, &is_recent, &is_download, &is_trash);
+ is_recent = is_download = is_trash = is_search = FALSE;
+ res = get_attributes_for_default_sort_type (file, &is_recent, &is_download, &is_trash, &is_search);
if (res) {
if (is_recent || is_download) {
retval = NAUTILUS_FILE_SORT_BY_MTIME;
} else if (is_trash) {
retval = NAUTILUS_FILE_SORT_BY_TRASHED_TIME;
+ } else if (is_search) {
+ retval = NAUTILUS_FILE_SORT_BY_SEARCH_RELEVANCE;
}
if (reversed != NULL) {
@@ -7481,17 +7564,19 @@ nautilus_file_get_default_sort_attribute (NautilusFile *file,
gboolean *reversed)
{
const gchar *retval;
- gboolean is_recent, is_download, is_trash, res;
+ gboolean is_recent, is_download, is_trash, is_search, res;
retval = NULL;
- is_download = is_trash = FALSE;
- res = get_attributes_for_default_sort_type (file, &is_recent, &is_download, &is_trash);
+ is_download = is_trash = is_search = FALSE;
+ res = get_attributes_for_default_sort_type (file, &is_recent, &is_download, &is_trash, &is_search);
if (res) {
if (is_recent || is_download) {
retval = g_quark_to_string (attribute_date_modified_q);
} else if (is_trash) {
retval = g_quark_to_string (attribute_trashed_on_q);
+ } else if (is_search) {
+ retval = g_quark_to_string (attribute_search_relevance_q);
}
if (reversed != NULL) {
@@ -7869,6 +7954,7 @@ nautilus_file_class_init (NautilusFileClass *class)
attribute_deep_file_count_q = g_quark_from_static_string ("deep_file_count");
attribute_deep_directory_count_q = g_quark_from_static_string ("deep_directory_count");
attribute_deep_total_count_q = g_quark_from_static_string ("deep_total_count");
+ attribute_search_relevance_q = g_quark_from_static_string ("search_relevance");
attribute_trashed_on_q = g_quark_from_static_string ("trashed_on");
attribute_trashed_on_full_q = g_quark_from_static_string ("trashed_on_full");
attribute_trash_orig_path_q = g_quark_from_static_string ("trash_orig_path");
diff --git a/libnautilus-private/nautilus-file.h b/libnautilus-private/nautilus-file.h
index 7ab7e0cef..a1bedf1b0 100644
--- a/libnautilus-private/nautilus-file.h
+++ b/libnautilus-private/nautilus-file.h
@@ -60,7 +60,8 @@ typedef enum {
NAUTILUS_FILE_SORT_BY_TYPE,
NAUTILUS_FILE_SORT_BY_MTIME,
NAUTILUS_FILE_SORT_BY_ATIME,
- NAUTILUS_FILE_SORT_BY_TRASHED_TIME
+ NAUTILUS_FILE_SORT_BY_TRASHED_TIME,
+ NAUTILUS_FILE_SORT_BY_SEARCH_RELEVANCE
} NautilusFileSortType;
typedef enum {
@@ -187,6 +188,7 @@ gboolean nautilus_file_is_directory (Nautilu
gboolean nautilus_file_is_user_special_directory (NautilusFile *file,
GUserDirectory special_directory);
gboolean nautilus_file_is_archive (NautilusFile *file);
+gboolean nautilus_file_is_in_search (NautilusFile *file);
gboolean nautilus_file_is_in_trash (NautilusFile *file);
gboolean nautilus_file_is_in_recent (NautilusFile *file);
gboolean nautilus_file_is_in_desktop (NautilusFile *file);
@@ -214,6 +216,8 @@ char * nautilus_file_peek_top_left_text (Nautilu
gboolean nautilus_file_get_directory_item_mime_types (NautilusFile *file,
GList **mime_list);
+void nautilus_file_set_search_relevance (NautilusFile *file,
+ gdouble relevance);
void nautilus_file_set_attributes (NautilusFile *file,
GFileInfo *attributes,
NautilusFileOperationCallback callback,
diff --git a/libnautilus-private/nautilus-search-directory.c b/libnautilus-private/nautilus-search-directory.c
index bb8233799..a5733b4f0 100644
--- a/libnautilus-private/nautilus-search-directory.c
+++ b/libnautilus-private/nautilus-search-directory.c
@@ -468,22 +468,26 @@ search_engine_hits_added (NautilusSearchEngine *engine, GList *hits,
GList *hit_list;
GList *file_list;
NautilusFile *file;
- char *uri;
SearchMonitor *monitor;
GList *monitor_list;
file_list = NULL;
for (hit_list = hits; hit_list != NULL; hit_list = hit_list->next) {
- uri = hit_list->data;
+ NautilusSearchHit *hit = hit_list->data;
+ const char *uri;
+ uri = nautilus_search_hit_get_uri (hit);
if (g_str_has_suffix (uri, NAUTILUS_SAVED_SEARCH_EXTENSION)) {
/* Never return saved searches themselves as hits */
continue;
}
-
+
+ nautilus_search_hit_compute_scores (hit, search->details->query);
+
file = nautilus_file_get_by_uri (uri);
-
+ nautilus_file_set_search_relevance (file, nautilus_search_hit_get_relevance (hit));
+
for (monitor_list = search->details->monitor_list; monitor_list; monitor_list = monitor_list->next) {
monitor = monitor_list->data;
@@ -513,13 +517,15 @@ search_engine_hits_subtracted (NautilusSearchEngine *engine, GList *hits,
GList *monitor_list;
SearchMonitor *monitor;
GList *file_list;
- char *uri;
NautilusFile *file;
file_list = NULL;
for (hit_list = hits; hit_list != NULL; hit_list = hit_list->next) {
- uri = hit_list->data;
+ NautilusSearchHit *hit = hit_list->data;
+ const char *uri;
+
+ uri = nautilus_search_hit_get_uri (hit);
file = nautilus_file_get_by_uri (uri);
for (monitor_list = search->details->monitor_list; monitor_list;
diff --git a/libnautilus-private/nautilus-search-engine-simple.c b/libnautilus-private/nautilus-search-engine-simple.c
index 6f875ee41..09684c3fa 100644
--- a/libnautilus-private/nautilus-search-engine-simple.c
+++ b/libnautilus-private/nautilus-search-engine-simple.c
@@ -22,6 +22,7 @@
*/
#include <config.h>
+#include "nautilus-search-hit.h"
#include "nautilus-search-provider.h"
#include "nautilus-search-engine-simple.h"
@@ -50,7 +51,7 @@ typedef struct {
gboolean recursive;
gint n_processed_files;
- GList *uri_hits;
+ GList *hits;
} SearchThreadData;
@@ -137,7 +138,7 @@ search_thread_data_free (SearchThreadData *data)
g_object_unref (data->cancellable);
g_strfreev (data->words);
g_list_free_full (data->mime_types, g_free);
- g_list_free_full (data->uri_hits, g_free);
+ g_list_free_full (data->hits, g_object_unref);
g_free (data);
}
@@ -159,43 +160,41 @@ search_thread_done_idle (gpointer user_data)
}
typedef struct {
- GList *uris;
+ GList *hits;
SearchThreadData *thread_data;
-} SearchHits;
+} SearchHitsData;
static gboolean
search_thread_add_hits_idle (gpointer user_data)
{
- SearchHits *hits;
+ SearchHitsData *data = user_data;
- hits = user_data;
-
- if (!g_cancellable_is_cancelled (hits->thread_data->cancellable)) {
- nautilus_search_provider_hits_added (NAUTILUS_SEARCH_PROVIDER (hits->thread_data->engine),
- hits->uris);
+ if (!g_cancellable_is_cancelled (data->thread_data->cancellable)) {
+ nautilus_search_provider_hits_added (NAUTILUS_SEARCH_PROVIDER (data->thread_data->engine),
+ data->hits);
}
- g_list_free_full (hits->uris, g_free);
- g_free (hits);
+ g_list_free_full (data->hits, g_object_unref);
+ g_free (data);
return FALSE;
}
static void
-send_batch (SearchThreadData *data)
+send_batch (SearchThreadData *thread_data)
{
- SearchHits *hits;
+ SearchHitsData *data;
- data->n_processed_files = 0;
+ thread_data->n_processed_files = 0;
- if (data->uri_hits) {
- hits = g_new (SearchHits, 1);
- hits->uris = data->uri_hits;
- hits->thread_data = data;
- g_idle_add (search_thread_add_hits_idle, hits);
+ if (thread_data->hits) {
+ data = g_new (SearchHitsData, 1);
+ data->hits = thread_data->hits;
+ data->thread_data = thread_data;
+ g_idle_add (search_thread_add_hits_idle, data);
}
- data->uri_hits = NULL;
+ thread_data->hits = NULL;
}
#define STD_ATTRIBUTES \
@@ -203,6 +202,7 @@ send_batch (SearchThreadData *data)
G_FILE_ATTRIBUTE_STANDARD_DISPLAY_NAME "," \
G_FILE_ATTRIBUTE_STANDARD_IS_HIDDEN "," \
G_FILE_ATTRIBUTE_STANDARD_TYPE "," \
+ G_FILE_ATTRIBUTE_TIME_MODIFIED "," \
G_FILE_ATTRIBUTE_ID_FILE
static void
@@ -213,7 +213,7 @@ visit_directory (GFile *dir, SearchThreadData *data)
GFile *child;
const char *mime_type, *display_name;
char *lower_name, *normalized;
- gboolean hit;
+ gboolean found;
int i;
GList *l;
const char *id;
@@ -246,22 +246,22 @@ visit_directory (GFile *dir, SearchThreadData *data)
lower_name = g_utf8_strdown (normalized, -1);
g_free (normalized);
- hit = TRUE;
+ found = TRUE;
for (i = 0; data->words[i] != NULL; i++) {
if (strstr (lower_name, data->words[i]) == NULL) {
- hit = FALSE;
+ found = FALSE;
break;
}
}
g_free (lower_name);
- if (hit && data->mime_types) {
+ if (found && data->mime_types) {
mime_type = g_file_info_get_content_type (info);
- hit = FALSE;
+ found = FALSE;
for (l = data->mime_types; mime_type != NULL && l != NULL; l = l->next) {
if (g_content_type_equals (mime_type, l->data)) {
- hit = TRUE;
+ found = TRUE;
break;
}
}
@@ -269,8 +269,22 @@ visit_directory (GFile *dir, SearchThreadData *data)
child = g_file_get_child (dir, g_file_info_get_name (info));
- if (hit) {
- data->uri_hits = g_list_prepend (data->uri_hits, g_file_get_uri (child));
+ if (found) {
+ NautilusSearchHit *hit;
+ GTimeVal tv;
+ GDateTime *dt;
+ char *uri;
+
+ uri = g_file_get_uri (child);
+ hit = nautilus_search_hit_new (uri);
+ g_free (uri);
+ nautilus_search_hit_set_fts_rank (hit, 10.0);
+ g_file_info_get_modification_time (info, &tv);
+ dt = g_date_time_new_from_timeval_local (&tv);
+ nautilus_search_hit_set_modification_time (hit, dt);
+ g_date_time_unref (dt);
+
+ data->hits = g_list_prepend (data->hits, hit);
}
data->n_processed_files++;
diff --git a/libnautilus-private/nautilus-search-engine-tracker.c b/libnautilus-private/nautilus-search-engine-tracker.c
index fc9c5ecf7..95919859d 100644
--- a/libnautilus-private/nautilus-search-engine-tracker.c
+++ b/libnautilus-private/nautilus-search-engine-tracker.c
@@ -22,6 +22,7 @@
*/
#include <config.h>
+#include "nautilus-search-hit.h"
#include "nautilus-search-provider.h"
#include "nautilus-search-engine-tracker.h"
#include <string.h>
@@ -85,6 +86,12 @@ cursor_callback (GObject *object,
NautilusSearchEngineTracker *tracker;
GError *error = NULL;
TrackerSparqlCursor *cursor;
+ NautilusSearchHit *hit;
+ const char *uri;
+ const char *mtime_str;
+ const char *atime_str;
+ GTimeVal tv;
+ gdouble rank;
GList *hits;
gboolean success;
@@ -108,9 +115,34 @@ cursor_callback (GObject *object,
}
/* We iterate result by result, not n at a time. */
- hits = g_list_append (NULL, (gchar*) tracker_sparql_cursor_get_string (cursor, 0, NULL));
+ uri = tracker_sparql_cursor_get_string (cursor, 0, NULL);
+ rank = tracker_sparql_cursor_get_double (cursor, 1);
+ mtime_str = tracker_sparql_cursor_get_string (cursor, 2, NULL);
+ atime_str = tracker_sparql_cursor_get_string (cursor, 3, NULL);
+
+ hit = nautilus_search_hit_new (uri);
+ nautilus_search_hit_set_fts_rank (hit, rank);
+ if (g_time_val_from_iso8601 (mtime_str, &tv)) {
+ GDateTime *dt;
+ dt = g_date_time_new_from_timeval_local (&tv);
+ nautilus_search_hit_set_modification_time (hit, dt);
+ g_date_time_unref (dt);
+ } else {
+ g_warning ("unable to parse mtime: %s", mtime_str);
+ }
+ if (g_time_val_from_iso8601 (atime_str, &tv)) {
+ GDateTime *dt;
+ dt = g_date_time_new_from_timeval_local (&tv);
+ nautilus_search_hit_set_access_time (hit, dt);
+ g_date_time_unref (dt);
+ } else {
+ g_warning ("unable to parse atime: %s", atime_str);
+ }
+
+ hits = g_list_append (NULL, hit);
nautilus_search_provider_hits_added (NAUTILUS_SEARCH_PROVIDER (tracker), hits);
g_list_free (hits);
+ g_object_unref (hit);
/* Get next */
cursor_next (tracker, cursor);
@@ -178,7 +210,7 @@ nautilus_search_engine_tracker_start (NautilusSearchProvider *provider)
mime_count = g_list_length (mimetypes);
- sparql = g_string_new ("SELECT DISTINCT nie:url(?urn) "
+ sparql = g_string_new ("SELECT DISTINCT nie:url(?urn) fts:rank(?urn) tracker:coalesce(nfo:fileLastModified(?urn), nie:contentLastModified(?urn)) AS ?mtime tracker:coalesce(nfo:fileLastAccessed(?urn), nie:contentAccessed(?urn)) AS ?atime "
"WHERE {"
" ?urn a nfo:FileDataObject ;"
" tracker:available true ; ");
@@ -212,7 +244,7 @@ nautilus_search_engine_tracker_start (NautilusSearchProvider *provider)
g_string_append (sparql, ")");
}
- g_string_append (sparql, ")}");
+ g_string_append (sparql, ")} ORDER BY DESC (fts:rank(?urn))");
tracker->details->cancellable = g_cancellable_new ();
tracker->details->query_pending = TRUE;
diff --git a/libnautilus-private/nautilus-search-engine.c b/libnautilus-private/nautilus-search-engine.c
index 946a86306..d5d90d204 100644
--- a/libnautilus-private/nautilus-search-engine.c
+++ b/libnautilus-private/nautilus-search-engine.c
@@ -96,11 +96,14 @@ search_provider_hits_added (NautilusSearchProvider *provider,
GList *l;
for (l = hits; l != NULL; l = l->next) {
- char *uri = l->data;
+ NautilusSearchHit *hit = l->data;
int count;
+ const char *uri;
+
+ uri = nautilus_search_hit_get_uri (hit);
count = GPOINTER_TO_INT (g_hash_table_lookup (engine->details->uris, uri));
if (count == 0)
- added = g_list_prepend (added, uri);
+ added = g_list_prepend (added, hit);
g_hash_table_replace (engine->details->uris, g_strdup (uri), GINT_TO_POINTER (count++));
}
if (added != NULL) {
@@ -118,12 +121,15 @@ search_provider_hits_subtracted (NautilusSearchProvider *provider,
GList *l;
for (l = hits; l != NULL; l = l->next) {
- char *uri = l->data;
+ NautilusSearchHit *hit = l->data;
int count;
+ const char *uri;
+
+ uri = nautilus_search_hit_get_uri (hit);
count = GPOINTER_TO_INT (g_hash_table_lookup (engine->details->uris, uri));
g_assert (count > 0);
if (count == 1) {
- removed = g_list_prepend (removed, uri);
+ removed = g_list_prepend (removed, hit);
g_hash_table_remove (engine->details->uris, uri);
} else {
g_hash_table_replace (engine->details->uris, g_strdup (uri), GINT_TO_POINTER (count--));
diff --git a/libnautilus-private/nautilus-search-hit.c b/libnautilus-private/nautilus-search-hit.c
new file mode 100644
index 000000000..7e7d8f119
--- /dev/null
+++ b/libnautilus-private/nautilus-search-hit.c
@@ -0,0 +1,327 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*-
+ *
+ * Copyright (C) 2012 Red Hat, Inc.
+ *
+ * Nautilus is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * Nautilus is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this program; see the file COPYING. If not,
+ * write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ */
+
+#include <config.h>
+
+#include <string.h>
+
+#include "nautilus-search-hit.h"
+#include "nautilus-query.h"
+
+struct NautilusSearchHitDetails
+{
+ char *uri;
+
+ GDateTime *modification_time;
+ GDateTime *access_time;
+ gdouble fts_rank;
+
+ gdouble relevance;
+};
+
+enum {
+ PROP_URI = 1,
+ PROP_RELEVANCE,
+ PROP_MODIFICATION_TIME,
+ PROP_ACCESS_TIME,
+ PROP_FTS_RANK,
+ NUM_PROPERTIES
+};
+
+G_DEFINE_TYPE (NautilusSearchHit, nautilus_search_hit, G_TYPE_OBJECT)
+
+void
+nautilus_search_hit_compute_scores (NautilusSearchHit *hit,
+ NautilusQuery *query)
+{
+ GDateTime *now;
+ char *query_uri;
+ char *query_path;
+ int i;
+ GTimeSpan m_diff = G_MAXINT64;
+ GTimeSpan a_diff = G_MAXINT64;
+ GTimeSpan t_diff = G_MAXINT64;
+ gdouble recent_bonus = 0.0;
+ gdouble proximity_bonus = 0.0;
+ gdouble match_bonus = 0.0;
+
+ query_uri = nautilus_query_get_location (query);
+ query_path = g_filename_from_uri (query_uri, NULL, NULL);
+ g_free (query_uri);
+ if (query_path != NULL) {
+ char *hit_path;
+ char *hit_parent;
+ guint dir_count;
+
+ hit_path = g_filename_from_uri (hit->details->uri, NULL, NULL);
+ hit_parent = g_path_get_dirname (hit_path);
+ g_free (hit_path);
+
+ dir_count = 0;
+ for (i = strlen (query_path); hit_parent[i] != '\0'; i++) {
+ if (G_IS_DIR_SEPARATOR (hit_parent[i]))
+ dir_count++;
+ }
+ g_free (hit_parent);
+
+ if (dir_count < 10) {
+ proximity_bonus = 100.0 - 10 * dir_count;
+ } else {
+ proximity_bonus = 0.0;
+ }
+ }
+ g_free (query_path);
+
+ now = g_date_time_new_now_local ();
+ if (hit->details->modification_time != NULL)
+ m_diff = g_date_time_difference (now, hit->details->modification_time);
+ if (hit->details->access_time != NULL)
+ a_diff = g_date_time_difference (now, hit->details->access_time);
+ m_diff /= G_TIME_SPAN_DAY;
+ a_diff /= G_TIME_SPAN_DAY;
+ t_diff = MIN (m_diff, a_diff);
+ if (t_diff > 90) {
+ recent_bonus = 0.0;
+ } else if (t_diff > 30) {
+ recent_bonus = 10.0;
+ } else if (t_diff > 14) {
+ recent_bonus = 30.0;
+ } else if (t_diff > 7) {
+ recent_bonus = 50.0;
+ } else if (t_diff > 1) {
+ recent_bonus = 70.0;
+ } else {
+ recent_bonus = 100.0;
+ }
+
+ if (hit->details->fts_rank > 0) {
+ match_bonus = 10.0 * hit->details->fts_rank;
+ } else {
+ match_bonus = 0.0;
+ }
+
+ hit->details->relevance = recent_bonus + proximity_bonus + match_bonus;
+
+ g_date_time_unref (now);
+}
+
+const char *
+nautilus_search_hit_get_uri (NautilusSearchHit *hit)
+{
+ return hit->details->uri;
+}
+
+gdouble
+nautilus_search_hit_get_relevance (NautilusSearchHit *hit)
+{
+ return hit->details->relevance;
+}
+
+static void
+nautilus_search_hit_set_uri (NautilusSearchHit *hit,
+ const char *uri)
+{
+ g_free (hit->details->uri);
+ hit->details->uri = g_strdup (uri);
+}
+
+void
+nautilus_search_hit_set_fts_rank (NautilusSearchHit *hit,
+ gdouble rank)
+{
+ hit->details->fts_rank = rank;
+}
+
+void
+nautilus_search_hit_set_modification_time (NautilusSearchHit *hit,
+ GDateTime *date)
+{
+ if (hit->details->modification_time != NULL)
+ g_date_time_unref (hit->details->modification_time);
+ if (date != NULL)
+ hit->details->modification_time = g_date_time_ref (date);
+ else
+ hit->details->modification_time = NULL;
+}
+
+void
+nautilus_search_hit_set_access_time (NautilusSearchHit *hit,
+ GDateTime *date)
+{
+ if (hit->details->access_time != NULL)
+ g_date_time_unref (hit->details->access_time);
+ if (date != NULL)
+ hit->details->access_time = g_date_time_ref (date);
+ else
+ hit->details->access_time = NULL;
+}
+
+static void
+nautilus_search_hit_set_property (GObject *object,
+ guint arg_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ NautilusSearchHit *hit;
+
+ hit = NAUTILUS_SEARCH_HIT (object);
+
+ switch (arg_id) {
+ case PROP_RELEVANCE:
+ hit->details->relevance = g_value_get_double (value);
+ case PROP_FTS_RANK:
+ nautilus_search_hit_set_fts_rank (hit, g_value_get_double (value));
+ break;
+ case PROP_URI:
+ nautilus_search_hit_set_uri (hit, g_value_get_string (value));
+ break;
+ case PROP_MODIFICATION_TIME:
+ nautilus_search_hit_set_modification_time (hit, g_value_get_boxed (value));
+ break;
+ case PROP_ACCESS_TIME:
+ nautilus_search_hit_set_access_time (hit, g_value_get_boxed (value));
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, arg_id, pspec);
+ break;
+ }
+}
+
+static void
+nautilus_search_hit_get_property (GObject *object,
+ guint arg_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ NautilusSearchHit *hit;
+
+ hit = NAUTILUS_SEARCH_HIT (object);
+
+ switch (arg_id) {
+ case PROP_RELEVANCE:
+ g_value_set_double (value, hit->details->relevance);
+ break;
+ case PROP_FTS_RANK:
+ g_value_set_double (value, hit->details->fts_rank);
+ break;
+ case PROP_URI:
+ g_value_set_string (value, hit->details->uri);
+ break;
+ case PROP_MODIFICATION_TIME:
+ g_value_set_boxed (value, hit->details->modification_time);
+ break;
+ case PROP_ACCESS_TIME:
+ g_value_set_boxed (value, hit->details->access_time);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, arg_id, pspec);
+ break;
+ }
+}
+
+static void
+nautilus_search_hit_finalize (GObject *object)
+{
+ NautilusSearchHit *hit = NAUTILUS_SEARCH_HIT (object);
+
+ g_free (hit->details->uri);
+
+ if (hit->details->access_time != NULL) {
+ g_date_time_unref (hit->details->access_time);
+ }
+ if (hit->details->modification_time != NULL) {
+ g_date_time_unref (hit->details->modification_time);
+ }
+
+ G_OBJECT_CLASS (nautilus_search_hit_parent_class)->finalize (object);
+}
+
+static void
+nautilus_search_hit_class_init (NautilusSearchHitClass *class)
+{
+ GObjectClass *object_class;
+
+ object_class = (GObjectClass *) class;
+
+ object_class->finalize = nautilus_search_hit_finalize;
+ object_class->get_property = nautilus_search_hit_get_property;
+ object_class->set_property = nautilus_search_hit_set_property;
+
+ g_object_class_install_property (object_class,
+ PROP_URI,
+ g_param_spec_string ("uri",
+ "URI",
+ "URI",
+ NULL,
+ G_PARAM_CONSTRUCT_ONLY | G_PARAM_WRITABLE | G_PARAM_READABLE));
+ g_object_class_install_property (object_class,
+ PROP_MODIFICATION_TIME,
+ g_param_spec_boxed ("modification-time",
+ "Modification time",
+ "Modification time",
+ G_TYPE_DATE_TIME,
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
+ g_object_class_install_property (object_class,
+ PROP_ACCESS_TIME,
+ g_param_spec_boxed ("access-time",
+ "acess time",
+ "access time",
+ G_TYPE_DATE_TIME,
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
+ g_object_class_install_property (object_class,
+ PROP_RELEVANCE,
+ g_param_spec_double ("relevance",
+ NULL,
+ NULL,
+ -G_MAXDOUBLE, G_MAXDOUBLE,
+ 0,
+ G_PARAM_READWRITE));
+ g_object_class_install_property (object_class,
+ PROP_FTS_RANK,
+ g_param_spec_double ("fts-rank",
+ NULL,
+ NULL,
+ -G_MAXDOUBLE, G_MAXDOUBLE,
+ 0,
+ G_PARAM_READWRITE));
+
+ g_type_class_add_private (class, sizeof (NautilusSearchHitDetails));
+}
+
+static void
+nautilus_search_hit_init (NautilusSearchHit *hit)
+{
+ hit->details = G_TYPE_INSTANCE_GET_PRIVATE (hit,
+ NAUTILUS_TYPE_SEARCH_HIT,
+ NautilusSearchHitDetails);
+}
+
+NautilusSearchHit *
+nautilus_search_hit_new (const char *uri)
+{
+ NautilusSearchHit *hit;
+
+ hit = g_object_new (NAUTILUS_TYPE_SEARCH_HIT,
+ "uri", uri,
+ NULL);
+
+ return hit;
+}
diff --git a/libnautilus-private/nautilus-search-hit.h b/libnautilus-private/nautilus-search-hit.h
new file mode 100644
index 000000000..005990a65
--- /dev/null
+++ b/libnautilus-private/nautilus-search-hit.h
@@ -0,0 +1,63 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*-
+ *
+ * Copyright (C) 2012 Red Hat, Inc.
+ *
+ * Nautilus is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * Nautilus is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this program; see the file COPYING. If not,
+ * write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ */
+
+#ifndef NAUTILUS_SEARCH_HIT_H
+#define NAUTILUS_SEARCH_HIT_H
+
+#include <glib-object.h>
+#include "nautilus-query.h"
+
+#define NAUTILUS_TYPE_SEARCH_HIT (nautilus_search_hit_get_type ())
+#define NAUTILUS_SEARCH_HIT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NAUTILUS_TYPE_SEARCH_HIT, NautilusSearchHit))
+#define NAUTILUS_SEARCH_HIT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NAUTILUS_TYPE_SEARCH_HIT, NautilusSearchHitClass))
+#define NAUTILUS_IS_SEARCH_HIT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NAUTILUS_TYPE_SEARCH_HIT))
+#define NAUTILUS_IS_SEARCH_HIT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NAUTILUS_TYPE_SEARCH_HIT))
+#define NAUTILUS_SEARCH_HIT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NAUTILUS_TYPE_SEARCH_HIT, NautilusSearchHitClass))
+
+typedef struct NautilusSearchHitDetails NautilusSearchHitDetails;
+
+typedef struct NautilusSearchHit {
+ GObject parent;
+ NautilusSearchHitDetails *details;
+} NautilusSearchHit;
+
+typedef struct {
+ GObjectClass parent_class;
+} NautilusSearchHitClass;
+
+GType nautilus_search_hit_get_type (void);
+
+NautilusSearchHit * nautilus_search_hit_new (const char *uri);
+
+void nautilus_search_hit_set_fts_rank (NautilusSearchHit *hit,
+ gdouble fts_rank);
+void nautilus_search_hit_set_modification_time (NautilusSearchHit *hit,
+ GDateTime *date);
+void nautilus_search_hit_set_access_time (NautilusSearchHit *hit,
+ GDateTime *date);
+
+void nautilus_search_hit_compute_scores (NautilusSearchHit *hit,
+ NautilusQuery *query);
+
+const char * nautilus_search_hit_get_uri (NautilusSearchHit *hit);
+gdouble nautilus_search_hit_get_relevance (NautilusSearchHit *hit);
+
+#endif /* NAUTILUS_SEARCH_HIT_H */
diff --git a/libnautilus-private/nautilus-search-provider.h b/libnautilus-private/nautilus-search-provider.h
index 07f2bff92..abd37a959 100644
--- a/libnautilus-private/nautilus-search-provider.h
+++ b/libnautilus-private/nautilus-search-provider.h
@@ -21,6 +21,7 @@
#include <glib-object.h>
#include <libnautilus-private/nautilus-query.h>
+#include <libnautilus-private/nautilus-search-hit.h>
G_BEGIN_DECLS