~ubuntu-branches/ubuntu/saucy/indicator-appmenu/saucy-updates

« back to all changes in this revision

Viewing changes to src/hudresult.c

  • Committer: Package Import Robot
  • Author(s): Automatic PS uploader, Mathieu Trudel-Lapierre, Automatic PS uploader
  • Date: 2013-02-20 09:41:54 UTC
  • mfrom: (1.1.40)
  • Revision ID: package-import@ubuntu.com-20130220094154-zrxsx0vgay436wyt
Tags: 13.01.0daily13.02.20-0ubuntu1
[ Mathieu Trudel-Lapierre ]
* Artificially bump upstream major version to please hud.

[ Automatic PS uploader ]
* Automatic snapshot from revision 234

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/*
2
 
 * Copyright © 2012 Canonical Ltd.
3
 
 *
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.
7
 
 *
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.
12
 
 *
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/>.
15
 
 *
16
 
 * Author: Ryan Lortie <desrt@desrt.ca>
17
 
 */
18
 
 
19
 
#include "hudresult.h"
20
 
 
21
 
#include <string.h>
22
 
 
23
 
#include "hudsettings.h"
24
 
#include "hudtoken.h"
25
 
 
26
 
/**
27
 
 * SECTION:hudresult
28
 
 * @title: HudResult
29
 
 * @short_description: a search result: a #HudItem plus metadata about
30
 
 *   why it matched
31
 
 *
32
 
 * A #HudResult is a wrapper around a #HudItem plus information about
33
 
 * why (and how closely) it matched a particular search.
34
 
 **/
35
 
 
36
 
/**
37
 
 * HudResult:
38
 
 *
39
 
 * This is an opaque structure type.
40
 
 **/
41
 
 
42
 
typedef GObjectClass HudResultClass;
43
 
 
44
 
struct _HudResult
45
 
{
46
 
  GObject parent_instance;
47
 
 
48
 
  HudItem *item;
49
 
 
50
 
  guint   distance;
51
 
  gchar  *description;
52
 
};
53
 
 
54
 
G_DEFINE_TYPE (HudResult, hud_result, G_TYPE_OBJECT)
55
 
 
56
 
static void
57
 
hud_result_finalize (GObject *object)
58
 
{
59
 
  HudResult *result = HUD_RESULT (object);
60
 
 
61
 
  g_object_unref (result->item);
62
 
  g_free (result->description);
63
 
 
64
 
  G_OBJECT_CLASS (hud_result_parent_class)
65
 
    ->finalize (object);
66
 
}
67
 
 
68
 
static void
69
 
hud_result_init (HudResult *result)
70
 
{
71
 
}
72
 
 
73
 
static void
74
 
hud_result_class_init (HudResultClass *class)
75
 
{
76
 
  class->finalize = hud_result_finalize;
77
 
}
78
 
 
79
 
/**
80
 
 * hud_result_get_if_matched:
81
 
 * @item: a #HudItem
82
 
 * @search_string: the search string used
83
 
 * @penalty: a penalty value
84
 
 *
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.
88
 
 *
89
 
 * This is the same as hud_result_new() except that it will return %NULL
90
 
 * if the distance is too great.
91
 
 *
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
95
 
 * maximum distance.
96
 
 *
97
 
 * Returns: a new #HudResult, or %NULL in event of a poor match
98
 
 **/
99
 
HudResult *
100
 
hud_result_get_if_matched (HudItem      *item,
101
 
                           HudTokenList *search_tokens,
102
 
                           guint         penalty)
103
 
{
104
 
  if (!hud_item_get_enabled (item))
105
 
    return NULL;
106
 
 
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);
110
 
  else
111
 
    return NULL;
112
 
}
113
 
 
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:
117
 
 *
118
 
 *   - first is that it allow us to avoid prepending to the description
119
 
 *     string
120
 
 *
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.
124
 
 */
125
 
static void
126
 
hud_result_format_tokens (GString          *string,
127
 
                          HudStringList    *tokens,
128
 
                          const HudToken ***matches)
129
 
{
130
 
  HudStringList *tail;
131
 
  const gchar *head;
132
 
  guint head_length;
133
 
  gchar *escaped;
134
 
 
135
 
  tail = hud_string_list_get_tail (tokens);
136
 
 
137
 
  if (tail)
138
 
    {
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, " &gt; ");
142
 
    }
143
 
 
144
 
  head = hud_string_list_get_head (tokens);
145
 
  head_length = strlen (head);
146
 
 
147
 
  while (**matches)
148
 
    {
149
 
      const gchar *matched_string;
150
 
      guint match_length;
151
 
 
152
 
      matched_string = hud_token_get_original (**matches, &match_length);
153
 
 
154
 
      if (head <= matched_string && matched_string + match_length <= head + head_length)
155
 
        {
156
 
          /* The matched string is a substring of the string that we
157
 
           * were just about to append.
158
 
           *
159
 
           * Append the part before the match.
160
 
           */
161
 
          escaped = g_markup_escape_text (head, matched_string - head);
162
 
          g_string_append (string, escaped);
163
 
          g_free (escaped);
164
 
 
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>");
170
 
          g_free (escaped);
171
 
 
172
 
          /* Fast-forward the head string.  There may be multiple
173
 
           * matches here (so we go another time around the 'while').
174
 
           */
175
 
          head = matched_string + match_length;
176
 
 
177
 
          /* That's it for this match. */
178
 
          (*matches)++;
179
 
        }
180
 
 
181
 
      else
182
 
        /* Didn't match?  Stop. */
183
 
        break;
184
 
    }
185
 
 
186
 
  /* Append whatever is left of the string after dealing with the
187
 
   * matches
188
 
   */
189
 
  escaped = g_markup_escape_text (head, -1);
190
 
  g_string_append (string, escaped);
191
 
  g_free (escaped);
192
 
}
193
 
 
194
 
static gchar *
195
 
hud_result_format_description (HudStringList   *tokens,
196
 
                               const HudToken **matches)
197
 
{
198
 
  GString *description;
199
 
 
200
 
  description = g_string_new (NULL);
201
 
  hud_result_format_tokens (description, tokens, &matches);
202
 
  return g_string_free (description, FALSE);
203
 
}
204
 
 
205
 
/**
206
 
 * hud_result_new:
207
 
 * @item: a #HudItem
208
 
 * @search_string: the search string used
209
 
 * @penalty: a penalty value
210
 
 *
211
 
 * Creates a #HudResult for @item as search for using @search_string.
212
 
 *
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
215
 
 * indicators.
216
 
 *
217
 
 * Returns: the new #HudResult
218
 
 **/
219
 
HudResult *
220
 
hud_result_new (HudItem      *item,
221
 
                HudTokenList *search_tokens,
222
 
                guint         penalty)
223
 
{
224
 
  const HudToken **matched;
225
 
  HudResult *result;
226
 
 
227
 
  g_return_val_if_fail (HUD_IS_ITEM (item), NULL);
228
 
  g_return_val_if_fail (search_tokens != NULL, NULL);
229
 
 
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);
234
 
  g_free (matched);
235
 
 
236
 
  result->distance += (result->distance * penalty) / 100;
237
 
 
238
 
  if (result->distance == 0 && penalty > 0)
239
 
    result->distance = 1;
240
 
 
241
 
  return result;
242
 
}
243
 
 
244
 
/**
245
 
 * hud_result_get_distance:
246
 
 * @result: a #HudResult
247
 
 * @max_usage: the maximum usage count we consider
248
 
 *
249
 
 * Returns the "adjusted" distance of @result.
250
 
 *
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
253
 
 * search string.
254
 
 *
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.
258
 
 *
259
 
 * Returns: the adjusted distance
260
 
 **/
261
 
guint
262
 
hud_result_get_distance (HudResult *result,
263
 
                         guint      max_usage)
264
 
{
265
 
  guint distance;
266
 
 
267
 
  g_return_val_if_fail (HUD_IS_RESULT (result), G_MAXINT);
268
 
 
269
 
  distance = result->distance;
270
 
 
271
 
  if (max_usage != 0)
272
 
    {
273
 
      guint usage, inverse_usage;
274
 
 
275
 
      usage = hud_item_get_usage (result->item);
276
 
      inverse_usage = max_usage - usage;
277
 
      distance += (distance * inverse_usage) / max_usage;
278
 
    }
279
 
 
280
 
  return distance;
281
 
}
282
 
 
283
 
/**
284
 
 * hud_result_get_item:
285
 
 * @result: a #HudResult
286
 
 *
287
 
 * Gets the #HudItem for @result.
288
 
 *
289
 
 * Returns: (transfer none): a #HudItem
290
 
 **/
291
 
HudItem *
292
 
hud_result_get_item (HudResult *result)
293
 
{
294
 
  return result->item;
295
 
}
296
 
 
297
 
/**
298
 
 * hud_result_get_html_description:
299
 
 * @result: a #HudResult
300
 
 *
301
 
 * Returns a textual description of @result with the parts of the text
302
 
 * that matched the search string strenghtened (ie: in bold).
303
 
 *
304
 
 * Returns: the description
305
 
 **/
306
 
const gchar *
307
 
hud_result_get_html_description (HudResult *result)
308
 
{
309
 
  return result->description;
310
 
}