2
* Copyright © 2012 Canonical Ltd.
4
* This program is free software: you can redistribute it and/or modify it
5
* under the terms of the GNU General Public License version 3, as
6
* published by the Free Software Foundation.
8
* This program is distributed in the hope that it will be useful, but
9
* WITHOUT ANY WARRANTY; without even the implied warranties of
10
* MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
11
* PURPOSE. See the GNU General Public License for more details.
13
* You should have received a copy of the GNU General Public License along
14
* with this program. If not, see <http://www.gnu.org/licenses/>.
16
* Author: Ryan Lortie <desrt@desrt.ca>
19
#include "hudresult.h"
23
#include "hudsettings.h"
29
* @short_description: a search result: a #HudItem plus metadata about
32
* A #HudResult is a wrapper around a #HudItem plus information about
33
* why (and how closely) it matched a particular search.
39
* This is an opaque structure type.
42
typedef GObjectClass HudResultClass;
46
GObject parent_instance;
54
G_DEFINE_TYPE (HudResult, hud_result, G_TYPE_OBJECT)
57
hud_result_finalize (GObject *object)
59
HudResult *result = HUD_RESULT (object);
61
g_object_unref (result->item);
62
g_free (result->description);
64
G_OBJECT_CLASS (hud_result_parent_class)
69
hud_result_init (HudResult *result)
74
hud_result_class_init (HudResultClass *class)
76
class->finalize = hud_result_finalize;
80
* hud_result_get_if_matched:
82
* @search_string: the search string used
83
* @penalty: a penalty value
85
* Creates a #HudResult for @item, only if the resulting unadjusted
86
* distance would be less than or equal to the maximum distance
87
* specified in the HUD settings.
89
* This is the same as hud_result_new() except that it will return %NULL
90
* if the distance is too great.
92
* The penalty value is ignored when checking the maximum distance but
93
* will impact the distance of the created result. As a result, the
94
* returned #HudResult may have an effective distance greater than the
97
* Returns: a new #HudResult, or %NULL in event of a poor match
100
hud_result_get_if_matched (HudItem *item,
101
HudTokenList *search_tokens,
104
if (!hud_item_get_enabled (item))
107
/* ignore the penalty in the max-distance calculation */
108
if (hud_token_list_distance (hud_item_get_token_list (item), search_tokens, NULL) <= hud_settings.max_distance)
109
return hud_result_new (item, search_tokens, penalty);
114
/* We recurse instead of iterating because we want to visit the tokens
115
* in the "user visible order" (which is backwards from the way the
116
* stack was constructed). This allows for two nice properties:
118
* - first is that it allow us to avoid prepending to the description
121
* - second is that the token-matching algorithm always returns the
122
* results in this order, so we can always just look at the head
123
* of the queue for our match.
126
hud_result_format_tokens (GString *string,
127
HudStringList *tokens,
128
const HudToken ***matches)
135
tail = hud_string_list_get_tail (tokens);
139
/* The tail will get a chance to consume some 'matches' first... */
140
hud_result_format_tokens (string, tail, matches);
141
g_string_append (string, " > ");
144
head = hud_string_list_get_head (tokens);
145
head_length = strlen (head);
149
const gchar *matched_string;
152
matched_string = hud_token_get_original (**matches, &match_length);
154
if (head <= matched_string && matched_string + match_length <= head + head_length)
156
/* The matched string is a substring of the string that we
157
* were just about to append.
159
* Append the part before the match.
161
escaped = g_markup_escape_text (head, matched_string - head);
162
g_string_append (string, escaped);
165
/* Append the matched part, in bold. */
166
escaped = g_markup_escape_text (matched_string, match_length);
167
g_string_append (string, "<b>");
168
g_string_append (string, escaped);
169
g_string_append (string, "</b>");
172
/* Fast-forward the head string. There may be multiple
173
* matches here (so we go another time around the 'while').
175
head = matched_string + match_length;
177
/* That's it for this match. */
182
/* Didn't match? Stop. */
186
/* Append whatever is left of the string after dealing with the
189
escaped = g_markup_escape_text (head, -1);
190
g_string_append (string, escaped);
195
hud_result_format_description (HudStringList *tokens,
196
const HudToken **matches)
198
GString *description;
200
description = g_string_new (NULL);
201
hud_result_format_tokens (description, tokens, &matches);
202
return g_string_free (description, FALSE);
208
* @search_string: the search string used
209
* @penalty: a penalty value
211
* Creates a #HudResult for @item as search for using @search_string.
213
* If @penalty is non-zero then it is used to increase the distance of
214
* the result. This is used to decrease the ranking of matches from the
217
* Returns: the new #HudResult
220
hud_result_new (HudItem *item,
221
HudTokenList *search_tokens,
224
const HudToken **matched;
227
g_return_val_if_fail (HUD_IS_ITEM (item), NULL);
228
g_return_val_if_fail (search_tokens != NULL, NULL);
230
result = g_object_new (HUD_TYPE_RESULT, NULL);
231
result->item = g_object_ref (item);
232
result->distance = hud_token_list_distance (hud_item_get_token_list (item), search_tokens, &matched);
233
result->description = hud_result_format_description (hud_item_get_tokens (item), matched);
236
result->distance += (result->distance * penalty) / 100;
238
if (result->distance == 0 && penalty > 0)
239
result->distance = 1;
245
* hud_result_get_distance:
246
* @result: a #HudResult
247
* @max_usage: the maximum usage count we consider
249
* Returns the "adjusted" distance of @result.
251
* If @max_usage is zero then the returned value is equal to the
252
* distance between the #HudItem used to create the result and the
255
* If @max_usage is non-zero then it is taken to be the usage count of
256
* the most-used item in the same query as this result. The distance is
257
* adjusted for this fact to penalise less-frequently-used item.
259
* Returns: the adjusted distance
262
hud_result_get_distance (HudResult *result,
267
g_return_val_if_fail (HUD_IS_RESULT (result), G_MAXINT);
269
distance = result->distance;
273
guint usage, inverse_usage;
275
usage = hud_item_get_usage (result->item);
276
inverse_usage = max_usage - usage;
277
distance += (distance * inverse_usage) / max_usage;
284
* hud_result_get_item:
285
* @result: a #HudResult
287
* Gets the #HudItem for @result.
289
* Returns: (transfer none): a #HudItem
292
hud_result_get_item (HudResult *result)
298
* hud_result_get_html_description:
299
* @result: a #HudResult
301
* Returns a textual description of @result with the parts of the text
302
* that matched the search string strenghtened (ie: in bold).
304
* Returns: the description
307
hud_result_get_html_description (HudResult *result)
309
return result->description;