~ubuntu-branches/ubuntu/precise/gnome-do/precise-proposed

« back to all changes in this revision

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

  • Committer: Bazaar Package Importer
  • Author(s): Christopher James Halse Rogers
  • Date: 2008-09-14 10:09:40 UTC
  • mto: (0.1.8 sid)
  • mto: This revision was merged to the branch mainline in revision 7.
  • Revision ID: james.westby@ubuntu.com-20080914100940-kyghudg7py14bu2z
Tags: upstream-0.6.0.0
ImportĀ upstreamĀ versionĀ 0.6.0.0

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
// SimpleUniverseManager.cs
 
2
// 
 
3
// GNOME Do is the legal property of its developers. Please refer to the
 
4
// COPYRIGHT file distributed with this source distribution.
 
5
//
 
6
// This program is free software: you can redistribute it and/or modify
 
7
// it under the terms of the GNU General Public License as published by
 
8
// the Free Software Foundation, either version 3 of the License, or
 
9
// (at your option) any later version.
 
10
//
 
11
// This program is distributed in the hope that it will be useful,
 
12
// but WITHOUT ANY WARRANTY; without even the implied warranty of
 
13
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
14
// GNU General Public License for more details.
 
15
//
 
16
// You should have received a copy of the GNU General Public License
 
17
// along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
18
//
 
19
 
 
20
using System;
 
21
using System.IO;
 
22
using System.Collections.Generic;
 
23
using System.Threading;
 
24
 
 
25
using Do;
 
26
using Do.Addins;
 
27
using Do.Universe;
 
28
 
 
29
namespace Do.Core
 
30
{
 
31
        // Threading Heirarchy:
 
32
        // universeLock may be locked within quickResultsLock and actionLock
 
33
        // No other nested locks should be allowed
 
34
        
 
35
        public class SimpleUniverseManager : IUniverseManager
 
36
        {
 
37
                private Dictionary<string, IObject> universe;
 
38
                private Dictionary<char, Dictionary<string, IObject>> quickResults;
 
39
                private List<IObject> actions;
 
40
                private Thread thread;
 
41
                private DateTime last_update = DateTime.Now;
 
42
                
 
43
                private object universeLock = new object ();
 
44
                private object quickResultsLock = new object ();
 
45
                private object actionLock = new object ();
 
46
                
 
47
                private float epsilon = 0.00001f;
 
48
                
 
49
                public SimpleUniverseManager()
 
50
                {
 
51
                        universe = new Dictionary<string, IObject> ();
 
52
                        quickResults = new Dictionary<char,Dictionary<string,IObject>> ();
 
53
                        actions = new List<IObject> ();
 
54
                        
 
55
                        for (char key = 'a'; key <= 'z'; key++) {
 
56
                                quickResults [key] = new Dictionary<string,IObject> ();
 
57
                        }
 
58
                }
 
59
 
 
60
                public IObject[] Search (string query, Type[] searchFilter)
 
61
                {
 
62
                        //Do.PrintPerf ("Search2 Start");
 
63
                        if (query.Length == 1) {
 
64
                                lock (quickResultsLock) {
 
65
                                        char key = Convert.ToChar (query.ToLower ());
 
66
                                        if (quickResults.ContainsKey (key)) {
 
67
                                                //Do.PrintPerf ("Search2 End");
 
68
                                                return Search (query, searchFilter, quickResults[key].Values, null);
 
69
                                        }
 
70
                                }
 
71
                        }
 
72
                        
 
73
                        if (searchFilter.Length == 1 && searchFilter[0] == typeof (IAction))
 
74
                                lock (actionLock)
 
75
                                        return Search (query, searchFilter, actions, null);
 
76
                        
 
77
                        lock (universeLock) 
 
78
                                return Search (query, searchFilter, universe.Values, null);
 
79
                }
 
80
                
 
81
                public IObject[] Search (string query, Type[] searchFilter, IObject otherObj)
 
82
                {
 
83
                        if (searchFilter.Length == 1 && searchFilter[0] == typeof (IAction))
 
84
                                lock (actionLock)
 
85
                                        return Search (query, searchFilter, actions, otherObj);
 
86
                        
 
87
                        if (query.Length == 1) {
 
88
                                lock (quickResultsLock) {
 
89
                                        char key = Convert.ToChar (query.ToLower ());
 
90
                                        if (quickResults.ContainsKey (key))
 
91
                                                return Search (query, searchFilter, quickResults[key].Values, null);
 
92
                                }
 
93
                        }
 
94
                        
 
95
                        lock (universeLock) 
 
96
                                return Search (query, searchFilter, universe.Values, otherObj);
 
97
                }
 
98
                
 
99
                public IObject[] Search (string query, Type[] searchFilter, IEnumerable<IObject> baseArray)
 
100
                {
 
101
                        return Search (query, searchFilter, baseArray, null);
 
102
                }
 
103
                
 
104
                public IObject[] Search (string query, Type[] searchFilter, IEnumerable<IObject> baseArray, IObject compareObj)
 
105
                {
 
106
                        List<IObject> results = new List<IObject> ();
 
107
                        query = query.ToLower ();
 
108
                        
 
109
                        foreach (DoObject obj in baseArray) {
 
110
                                obj.UpdateRelevance (query, compareObj as DoObject);
 
111
                                if (Math.Abs (obj.Relevance) > epsilon) {
 
112
                                        if (searchFilter.Length == 0) {
 
113
                                                results.Add (obj);
 
114
                                        } else {
 
115
                                                foreach (Type t in searchFilter) {
 
116
                                                        if (t.IsInstanceOfType (obj.Inner)) {
 
117
                                                                results.Add (obj);
 
118
                                                                break;
 
119
                                                        }
 
120
                                                }
 
121
                                        }
 
122
                                }
 
123
                        }
 
124
                        
 
125
                        // Ideally we would do stable sorts all the time, but quicksort is... quickest
 
126
                        // so we do a stable sort only on small lists
 
127
                        if (results.Count < 40)
 
128
                                InsertionSort (results);
 
129
                        else
 
130
                                results.Sort ();
 
131
                        
 
132
                        return results.ToArray ();
 
133
                }
 
134
                
 
135
                private void InsertionSort (List<IObject> list)
 
136
                {
 
137
                        if (list == null)
 
138
                                throw new ArgumentNullException( "list" );
 
139
                        
 
140
                        IObject key;
 
141
                        for (int j = 1; j < list.Count; j++) {
 
142
                                key = list[j];
 
143
                                
 
144
                                int i = j - 1;
 
145
                                for (; i >= 0 && (list[i] as DoObject).CompareTo (key as DoObject) > 0; i--) {
 
146
                                        list[i + 1] = list[i];
 
147
                                }
 
148
                                list[i + 1] = key;
 
149
                        }
 
150
                }
 
151
                
 
152
                /// <summary>
 
153
                /// Threaded universe building
 
154
                /// </summary>
 
155
                private void BuildUniverse ()
 
156
                {
 
157
                        //Originally i had threaded the loading of each plugin, but they dont seem to like this...
 
158
                        if (thread != null && thread.IsAlive) return;
 
159
                        
 
160
                        thread = new Thread (new ThreadStart (LoadUniverse));
 
161
                        thread.IsBackground = true;
 
162
                        thread.Start ();
 
163
                }
 
164
                
 
165
                
 
166
                /// <summary>
 
167
                /// Do not call inside main thread unless you really like a locked Do.
 
168
                /// </summary>
 
169
                private void LoadUniverse ()
 
170
                {
 
171
                        Dictionary<string, IObject> loc_universe;
 
172
                        Dictionary<char, Dictionary<string, IObject>> loc_quick;
 
173
                        List<IObject> loc_actions;
 
174
                        if (universe.Values.Count > 0) {
 
175
                                loc_universe = new Dictionary<string,IObject> ();
 
176
                                loc_quick    = new Dictionary<char,Dictionary<string,IObject>> ();
 
177
                                for (char key = 'a'; key <= 'z'; key++) {
 
178
                                        loc_quick [key] = new Dictionary<string,IObject> ();
 
179
                                }
 
180
                                loc_actions  = new List<IObject> ();
 
181
                        } else {
 
182
                                loc_universe = universe;
 
183
                                loc_quick    = quickResults;
 
184
                                loc_actions  = actions;
 
185
                        }
 
186
                        
 
187
                        foreach (DoAction action in PluginManager.GetActions ()) {
 
188
                                lock (universeLock)
 
189
                                        loc_universe[action.UID] = action;
 
190
                                RegisterQuickResults (loc_quick, action);
 
191
                                lock (actionLock)
 
192
                                        loc_actions.Add (action);
 
193
                        }
 
194
                        
 
195
                        foreach (DoItemSource source in PluginManager.GetItemSources ()) {
 
196
                                source.UpdateItems ();
 
197
                                foreach (DoItem item in source.Items) {
 
198
                                        lock (universeLock)
 
199
                                                loc_universe[item.UID] = item;
 
200
                                        RegisterQuickResults (loc_quick, item);
 
201
                                }
 
202
                        }
 
203
                        
 
204
                        lock (universeLock)
 
205
                                universe = loc_universe;
 
206
                        lock (quickResultsLock)
 
207
                                quickResults = loc_quick;
 
208
                        lock (actionLock)
 
209
                                actions = loc_actions;
 
210
                        
 
211
                        loc_universe = null;
 
212
                        loc_quick    = null;
 
213
                        loc_actions  = null;
 
214
                        
 
215
                        //maxResults = (int)universe.Count/7;
 
216
                        last_update = DateTime.Now;
 
217
                        Console.WriteLine ("Universe contains {0} items.", universe.Count);
 
218
                }
 
219
                
 
220
                /// <summary>
 
221
                /// Registers quickResults into the passed dictionary of the result passed
 
222
                /// </summary>
 
223
                /// <param name="quickResults">
 
224
                /// A <see cref="Dictionary`2"/>
 
225
                /// </param>
 
226
                /// <param name="result">
 
227
                /// A <see cref="IObject"/>
 
228
                /// </param>
 
229
                private void RegisterQuickResults (Dictionary<char, Dictionary<string, IObject>> quickResults, IObject result)
 
230
                {
 
231
                        if (quickResults == null) return;
 
232
                        
 
233
                        DoObject do_result;
 
234
                        if (result is DoObject)
 
235
                                do_result = result as DoObject;
 
236
                        else
 
237
                                do_result = new DoObject (result);
 
238
                        
 
239
                        lock (quickResultsLock) {
 
240
                                foreach (char key in quickResults.Keys) {
 
241
                                        do_result.UpdateRelevance (key.ToString (), null);
 
242
                                        if (do_result.Relevance > epsilon)
 
243
                                                quickResults[key][do_result.UID] = do_result;
 
244
                                }
 
245
                        }
 
246
                }
 
247
                
 
248
                /// <summary>
 
249
                /// Deletes a result from the global quickresults dictionary
 
250
                /// </summary>
 
251
                /// <param name="result">
 
252
                /// A <see cref="IObject"/>
 
253
                /// </param>
 
254
                private void DeleteQuickResult (IObject result)
 
255
                {
 
256
                        string UID = new DoObject (result).UID;
 
257
                        lock (quickResultsLock) {
 
258
                                foreach (Dictionary<string, IObject> list in quickResults.Values)
 
259
                                        list.Remove (UID);
 
260
                        }
 
261
                }
 
262
                
 
263
                /// <summary>
 
264
                /// Add a list of IItems to the universe
 
265
                /// </summary>
 
266
                /// <param name="items">
 
267
                /// A <see cref="IEnumerable`1"/>
 
268
                /// </param>
 
269
                public void AddItems (IEnumerable<IItem> items)
 
270
                {
 
271
                        foreach (IItem i in items) {
 
272
                                if (i is DoItem && !universe.ContainsKey ((i as DoItem).UID)) {
 
273
                                        lock (universeLock) {
 
274
                                                universe.Add ((i as DoItem).UID, i);
 
275
                                        }
 
276
                                        RegisterQuickResults (quickResults, i);
 
277
                                } else {
 
278
                                        DoItem di = new DoItem (i);
 
279
                                        if (!universe.ContainsKey (di.UID)) {
 
280
                                                lock (universeLock) {
 
281
                                                        universe.Add (di.UID, di);
 
282
                                                }
 
283
                                                RegisterQuickResults (quickResults, di);
 
284
                                        }
 
285
                                }
 
286
                        }
 
287
                }
 
288
 
 
289
                /// <summary>
 
290
                /// Remove a list of IItems from the universe.  This removal does not prevent these
 
291
                /// items from returning to the universe at a future date.
 
292
                /// </summary>
 
293
                /// <param name="items">
 
294
                /// A <see cref="IEnumerable`1"/>
 
295
                /// </param>
 
296
                public void DeleteItems (IEnumerable<IItem> items)
 
297
                {
 
298
                        foreach (IItem i in items) {
 
299
                                if (i is DoItem) {
 
300
                                        lock (universeLock) {
 
301
                                                universe.Remove ((i as DoItem).UID);
 
302
                                        }
 
303
                                } else {
 
304
                                        lock (universeLock) {
 
305
                                                universe.Remove (new DoItem (i).UID);
 
306
                                        }
 
307
                                }
 
308
                                DeleteQuickResult (i);
 
309
                        }
 
310
                }
 
311
 
 
312
                /// <summary>
 
313
                /// Returns the UID for an object
 
314
                /// </summary>
 
315
                /// <param name="o">
 
316
                /// A <see cref="IObject"/>
 
317
                /// </param>
 
318
                /// <returns>
 
319
                /// A <see cref="System.String"/>
 
320
                /// </returns>
 
321
                public string UIDForObject (IObject o)
 
322
                {
 
323
                        if (o is DoObject)
 
324
                                return (o as DoObject).UID;
 
325
                        return new DoObject (o).UID;
 
326
                }
 
327
                
 
328
                /// <summary>
 
329
                /// Attempts to get an Object for a given UID.
 
330
                /// </summary>
 
331
                /// <param name="UID">
 
332
                /// A <see cref="System.String"/>
 
333
                /// </param>
 
334
                /// <param name="item">
 
335
                /// A <see cref="IObject"/>
 
336
                /// </param>
 
337
                public void TryGetObjectForUID (string UID, out IObject item)
 
338
                {
 
339
                        if (universe.ContainsKey (UID)) {
 
340
                                item = (universe[UID] as DoObject).Inner;
 
341
                        } else {
 
342
                                item = null;
 
343
                        }
 
344
                        
 
345
                }
 
346
                
 
347
                /// <summary>
 
348
                /// Causes the universe to be rebuilt in the background
 
349
                /// </summary>
 
350
                public void Reload ()
 
351
                {
 
352
                        Console.WriteLine ("Reload");
 
353
                        BuildUniverse ();
 
354
                }
 
355
                
 
356
                public void Initialize ()
 
357
                {
 
358
                        BuildUniverse ();
 
359
                        GLib.Timeout.Add (5 * 60 * 1000, delegate {
 
360
                                if (DBus.PowerState.OnBattery () && 
 
361
                                    DateTime.Now.Subtract (last_update).TotalMinutes < 15) 
 
362
                                        return true;
 
363
                                BuildUniverse ();
 
364
                                return true;
 
365
                        });
 
366
                }
 
367
        }
 
368
}