diff options
-rw-r--r-- | libnautilus-private/Makefile.am | 2 | ||||
-rw-r--r-- | libnautilus-private/nautilus-column-utilities.c | 20 | ||||
-rw-r--r-- | libnautilus-private/nautilus-file-private.h | 2 | ||||
-rw-r--r-- | libnautilus-private/nautilus-file.c | 102 | ||||
-rw-r--r-- | libnautilus-private/nautilus-file.h | 6 | ||||
-rw-r--r-- | libnautilus-private/nautilus-search-directory.c | 18 | ||||
-rw-r--r-- | libnautilus-private/nautilus-search-engine-simple.c | 72 | ||||
-rw-r--r-- | libnautilus-private/nautilus-search-engine-tracker.c | 38 | ||||
-rw-r--r-- | libnautilus-private/nautilus-search-engine.c | 14 | ||||
-rw-r--r-- | libnautilus-private/nautilus-search-hit.c | 327 | ||||
-rw-r--r-- | libnautilus-private/nautilus-search-hit.h | 63 | ||||
-rw-r--r-- | libnautilus-private/nautilus-search-provider.h | 1 |
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 |