~ubuntu-branches/ubuntu/lucid/gnome-do/lucid

« back to all changes in this revision

Viewing changes to Do/src/Do.Core/RelevanceProvider.cs

  • Committer: Bazaar Package Importer
  • Author(s): Christopher James Halse Rogers, Christopher James Halse Rogers, Iain Lane
  • Date: 2009-02-04 15:30:25 UTC
  • mfrom: (1.1.5 upstream)
  • Revision ID: james.westby@ubuntu.com-20090204153025-dhb2pm7dgbtmoib6
Tags: 0.8.0-1~ubuntu1
[ Christopher James Halse Rogers ]
* New upstream release.  (LP: #323048)
  + Fixes text input problems (LP: #288517)
  + No longer grabs plugins from internet repositories (LP: #294808)
  + Preferences dialog is resizable (LP: #305419)
* Build against gtk, gnome mono packages from Experimental. (Closes: #510836)
* debian/control:
  + Bump versioned dep on libgtk2.0-cil to ensure
    Gdk.Screen.IsComposited exists (Closes: #510973)
  + Add libwnck2.20-cil build-dep
  + gnome-sharp2 transition.
* debian/patches/04_fix_locale_dir
* debian/patches/05_fix_localised_theme_setting
* debian/patches/06_expand_homedir_in_open
  + Drop; fixed in new upstream  
* debian/patches/02_use_cli_for_wrapper
  + Update for new upstream
  + Add dpatch comments
* debian/gnome-do.1
  + Fix broken formatting (LP: #291654).  Thank you to Frédéric Grosshans
    for spotting it, and the patch.
  + Update for new version.

[ Iain Lane ]
* Tag pkg-cli-apps SVN revision into Jaunty, to get in before Feature
  Freeze. Should be a sync after the next Debian upload.

Show diffs side-by-side

added added

removed removed

Lines of Context:
19
19
 */
20
20
 
21
21
using System;
 
22
using System.IO;
22
23
using System.Collections.Generic;
 
24
using System.Runtime.Serialization;
 
25
using System.Runtime.Serialization.Formatters.Binary;
23
26
 
 
27
using Do.Platform;
24
28
using Do.Universe;
25
29
 
26
30
namespace Do.Core {
27
31
 
28
 
        class RelevanceProvider {
29
 
 
30
 
                public static RelevanceProvider GetProvider ()
31
 
                {
32
 
            return new HistogramRelevanceProvider ();
 
32
        public interface IRelevanceProvider
 
33
        {
 
34
                void IncreaseRelevance (Element target, string match, Element other);
 
35
                void DecreaseRelevance (Element target, string match, Element other);
 
36
                float GetRelevance (Element target, string match, Element other);
 
37
        }
 
38
 
 
39
        [Serializable]
 
40
        public abstract class RelevanceProvider : IRelevanceProvider {
 
41
 
 
42
                const int SerializeInterval = 10 * 60 * 1000;
 
43
 
 
44
                static RelevanceProvider ()
 
45
                {
 
46
                        DefaultProvider = Deserialize () ?? new HistogramRelevanceProvider ();
 
47
                        GLib.Timeout.Add (SerializeInterval, OnSerializeTimer);
 
48
                }
 
49
                
 
50
                public static IRelevanceProvider DefaultProvider { get; private set; }
 
51
 
 
52
                public static string RelevanceFile {
 
53
                        get {
 
54
                                return Path.Combine (Services.Paths.UserDataDirectory, "relevance8");
 
55
                        }
 
56
                }
 
57
 
 
58
                static bool OnSerializeTimer () {
 
59
                        Gtk.Application.Invoke ((sender, args) => Serialize (DefaultProvider));
 
60
                        return true;
 
61
                }
 
62
 
 
63
                /// <summary>
 
64
                /// Deserializes relevance data.
 
65
                /// </summary>
 
66
                private static IRelevanceProvider Deserialize ()
 
67
                {
 
68
                        IRelevanceProvider provider = null;
 
69
                        
 
70
                        try {
 
71
                                using (Stream s = File.OpenRead (RelevanceFile)) {
 
72
                                        BinaryFormatter f = new BinaryFormatter ();
 
73
                                        provider = f.Deserialize (s) as IRelevanceProvider;
 
74
                                }
 
75
                                Log<RelevanceProvider>.Debug ("Successfully loaded learned usage data.");
 
76
                        } catch (FileNotFoundException) {
 
77
                        } catch (Exception e) {
 
78
                                Log<RelevanceProvider>.Error ("Failed to load learned usage data: {0}", e.Message);
 
79
                        }
 
80
                        return provider;
 
81
                }
 
82
 
 
83
                /// <summary>
 
84
                /// Serializes relevance data.
 
85
                /// </summary>
 
86
                private static void Serialize (IRelevanceProvider provider)
 
87
                {
 
88
                        try {
 
89
                                using (Stream s = File.OpenWrite (RelevanceFile)) {
 
90
                                        BinaryFormatter f = new BinaryFormatter ();
 
91
                                        f.Serialize (s, provider);
 
92
                                }
 
93
                                Log<RelevanceProvider>.Debug ("Successfully saved learned usage data.");
 
94
                        } catch (Exception e) {
 
95
                                Log<RelevanceProvider>.Error ("Failed to save learned usage data: {0}", e.Message);
 
96
                        }
33
97
                }
34
98
 
35
99
                /// <summary>
54
118
                                return 1;
55
119
                        
56
120
                        float score;
57
 
                        string ls = s.ToLower();
 
121
                        string ls = s.ToLower ();
58
122
 
59
123
                        //Find the shortest possible substring that matches the query
60
124
                        //and get the ration of their lengths for a base score
61
 
                        int[] match = findBestSubstringMatchIndices(ls, query);
 
125
                        int[] match = findBestSubstringMatchIndices (ls, query);
62
126
                        if ((match[1] - match[0]) == 0) return 0;
63
127
                        score = query.Length / (float)(match[1] - match[0]);
64
128
                        if (score == 0) return 0;
65
129
                        
66
130
                        //Now we weight by string length so shorter strings are better
67
131
                        score = score * .7F + query.Length / s.Length * .3F;
68
 
                        
69
132
                        //Bonus points if the characters start words
70
133
                        float good = 0, bad = 1;
71
134
                        int firstCount = 0;
72
 
                        for(int i=match[0]; i<match[1]-1; i++)
 
135
                        for(int i=Math.Max (match[0]-1,0); i<match[1]-1; i++)
73
136
                        {
74
 
                                if(s[i] == ' ')
 
137
                                if (char.IsWhiteSpace (s[i]))
75
138
                                {
76
 
                                        if(query.Contains(ls[i+1].ToString()))
 
139
                                        if (query.Contains (ls[i + 1].ToString ()))
77
140
                                                firstCount++;
78
141
                                        else
79
142
                                                bad++;
82
145
                                                
83
146
                        //A first character match counts extra
84
147
                        if(query[0] == ls[0])
85
 
                                firstCount += 2;
 
148
                                firstCount ++;
86
149
                        
87
150
                        //The longer the acronym, the better it scores
88
 
                        good += firstCount*firstCount*4;
89
 
                        
90
 
                        //Better yet if the match itself started there
91
 
                        if(match[0] == 0)
92
 
                                good += 2;
93
 
                        
94
 
                        //Super bonus if the whole match is at the beginning
95
 
                        if(match[1] == (query.Length - 1))
96
 
                                good += match[1] + 4;
 
151
                        good += firstCount * firstCount * 4;
97
152
                        
98
153
                        //Super-duper bonus if it is a perfect match
99
154
                        if(query == ls)
130
185
                /// A two item array containing the start and end indices of the match.
131
186
                /// No match returns {-1.-1}
132
187
                /// </returns>
133
 
                protected static int[] findBestSubstringMatchIndices(string s, string query)
 
188
                protected static int[] findBestSubstringMatchIndices (string s, string query)
134
189
                {
135
 
                        if(query.Length == 0)
136
 
                                return new int[] {0,0};
 
190
                        if (query.Length == 0)
 
191
                                return new int[] {0, 0};
137
192
                        
138
 
                        int index=-1;
139
 
                        int[] bestMatch = {-1,-1};
 
193
                        int index = -1;
 
194
                        int[] bestMatch = {-1, -1};
140
195
                        
141
196
                        //Find the last instance of the last character of the query
142
197
                        //since we never need to search beyond that
143
198
                        int lastChar = s.Length - 1;
144
 
                        while((lastChar >= 0) && (s[lastChar] != query[query.Length - 1]))
 
199
                        while (0 <= lastChar && s[lastChar] != query[query.Length - 1])
145
200
                                lastChar--;
146
201
                        
147
202
                        //No instance of the character?
148
 
                        if(lastChar == -1)
 
203
                        if (lastChar == -1)
149
204
                                return bestMatch;
150
205
                        
151
206
                        //Loop through each instance of the first character in query
152
 
                        while ((index = s.IndexOf(query[0], index+1, lastChar-index)) >= 0) {
 
207
                        while ( 0 <= (index = s.IndexOf (query[0], index + 1, lastChar - index))) {
153
208
                                //Is there even room for a match?
154
 
                                if(index > lastChar + 1 - query.Length) break;
 
209
                                if (index > lastChar + 1 - query.Length) break;
155
210
                                
156
211
                                //Look for the best match in the tail
157
212
                                //We know the first char matches, so we dont check it.
158
213
                                int cur  = index + 1;
159
214
                                int qcur = 1;
160
 
                                while(qcur < query.Length && cur < s.Length)
161
 
                                        if(query[qcur] == s[cur++])
 
215
                                while (qcur < query.Length && cur < s.Length)
 
216
                                        if (query[qcur] == s[cur++])
162
217
                                                qcur++;
163
218
                                
164
 
                                if((qcur == query.Length) && (((cur - index) < (bestMatch[1] - bestMatch[0])) || (bestMatch[0] == -1))) {
 
219
                                if (qcur == query.Length && (cur - index < bestMatch[1] - bestMatch[0] || bestMatch[0] == -1)) {
165
220
                                        bestMatch[0] = index;
166
221
                                        bestMatch[1] = cur;
167
222
                                }
168
223
                                
169
 
                                if(index == s.Length - 1)
 
224
                                if (index == s.Length - 1)
170
225
                                        break;
171
226
                        }
172
227
                        
173
228
                        return bestMatch;
174
229
                }
175
230
 
176
 
                public virtual void IncreaseRelevance (DoObject r, string match, DoObject other)
177
 
                {
178
 
                }
179
 
 
180
 
                public virtual void DecreaseRelevance (DoObject r, string match, DoObject other)
181
 
                {
182
 
                }
183
 
 
184
 
                public virtual float GetRelevance (DoObject r, string match, DoObject other)
185
 
                {
186
 
                        return StringScoreForAbbreviation (r.Name, match);
187
 
                }
188
 
 
189
 
                public virtual bool CanBeFirstResultForKeypress (DoObject r, char a)
190
 
                {
191
 
                        return true;
 
231
                public virtual void IncreaseRelevance (Element r, string match, Element other)
 
232
                {
 
233
                }
 
234
 
 
235
                public virtual void DecreaseRelevance (Element r, string match, Element other)
 
236
                {
 
237
                }
 
238
 
 
239
                public virtual float GetRelevance (Element r, string match, Element other)
 
240
                {
 
241
                        return StringScoreForAbbreviation (r.Safe.Name, match);
192
242
                }
193
243
        }
194
244
}