12
12
using System.Collections;
13
13
using System.Collections.Generic;
17
18
public class PhotoQuery : FSpot.IBrowsableCollection {
18
private Photo [] photos;
21
static int SIZE = 100;
26
Dictionary <int, Photo []> cache;
30
public PhotoCache (PhotoStore store, string temp_table)
32
this.temp_table = temp_table;
34
cache = new Dictionary<int, Photo[]> ();
37
public bool TryGetPhoto (int index, out Photo photo)
41
int offset = index - index % SIZE;
42
if (!cache.TryGetValue (offset, out val))
44
photo = val [index - offset];
48
public Photo Get (int index)
51
int offset = index - index % SIZE;
52
if (!cache.TryGetValue (offset, out val)) {
53
val = store.QueryFromTemp (temp_table, offset, SIZE);
56
return val [index - offset];
19
61
private PhotoStore store;
20
62
private Term terms;
21
63
private Tag [] tags;
22
64
private string extra_condition;
66
static int query_count = 0;
67
static int QueryCount {
68
get {return query_count ++;}
71
Dictionary<uint, int> reverse_lookup;
75
string temp_table = String.Format ("photoquery_temp_{0}", QueryCount);
25
public PhotoQuery (PhotoStore store)
78
public PhotoQuery (PhotoStore store, params IQueryCondition [] conditions)
27
80
this.store = store;
28
81
// Note: this is to let the query pick up
29
82
// photos that were added or removed over dbus
30
83
this.store.ItemsAddedOverDBus += delegate { RequestReload(); };
31
84
this.store.ItemsRemovedOverDBus += delegate { RequestReload(); };
33
photos = store.Query ((Tag [])null, null, Range, RollSet, RatingRange);
85
this.store.ItemsChanged += MarkChanged;
86
cache = new PhotoCache (store, temp_table);
87
reverse_lookup = new Dictionary<uint, int> ();
88
SetCondition (OrderByTime.OrderByTimeDesc);
90
foreach (IQueryCondition condition in conditions)
91
SetCondition (condition);
93
store.QueryToTemp (temp_table, (Tag [])null, null, Range, RollSet, RatingRange, OrderByTime);
37
get { return photos.Length;}
99
count = store.Count (temp_table);
40
104
public bool Contains (IBrowsableItem item) {
44
108
// IPhotoCollection Interface
45
109
public event FSpot.IBrowsableCollectionChangedHandler Changed;
46
public event FSpot.IBrowsableCollectionChangedHandler PreChanged;
47
110
public event FSpot.IBrowsableCollectionItemsChangedHandler ItemsChanged;
49
112
public IBrowsableItem this [int index] {
50
get { return photos [index]; }
113
get { return cache.Get (index); }
116
[Obsolete ("DO NOT USE THIS, IT'S TOO SLOW")]
53
117
public Photo [] Photos {
54
get { return photos; }
118
get { return store.QueryFromTemp (temp_table); }
121
[Obsolete ("DO NOT USE Items on PhotoQuery")]
57
122
public IBrowsableItem [] Items {
58
get { return (IBrowsableItem [])photos; }
123
get { throw new NotImplementedException (); }
61
126
public PhotoStore Store {
62
127
get { return store; }
66
130
//Query Conditions
67
131
private Dictionary<Type, IQueryCondition> conditions;
68
132
private Dictionary<Type, IQueryCondition> Conditions {
159
223
public RatingRange RatingRange {
160
get { return GetCondition<RatingRange> () as RatingRange; }
224
get { return GetCondition<RatingRange> (); }
162
226
if (value == null && UnSetCondition<RatingRange>() || value != null && SetCondition (value))
163
227
RequestReload ();
231
public OrderByTime OrderByTime {
232
get { return GetCondition<OrderByTime> (); }
234
if (value != null && SetCondition (value))
239
public bool TimeOrderAsc {
240
get { return OrderByTime.Asc; }
242
if (value != OrderByTime.Asc)
243
OrderByTime = new OrderByTime (value);
167
247
public void RequestReload ()
249
uint timer = Log.DebugTimerStart ();
170
photos = store.Query (new UntaggedCondition (), Range, RollSet, RatingRange);
251
store.QueryToTemp (temp_table, new UntaggedCondition (), Range, RollSet, RatingRange, OrderByTime);
172
photos = store.Query (terms, extra_condition, Range, RollSet, RatingRange);
253
store.QueryToTemp (temp_table, terms, extra_condition, Range, RollSet, RatingRange, OrderByTime);
174
//this event will allow resorting the query content
175
if (PreChanged != null)
256
cache = new PhotoCache (store, temp_table);
257
reverse_lookup = new Dictionary<uint,int> ();
178
259
if (Changed != null)
261
Log.DebugTimerPrint (timer, "Reloading the query took {0}");
182
264
public int IndexOf (IBrowsableItem photo)
184
return System.Array.IndexOf (photos, photo);
187
public void Commit (int index)
189
store.Commit (photos[index]);
193
public void MarkChanged (int index)
195
ItemsChanged (this, new BrowsableEventArgs (index));
266
if (photo == null || !(photo is Photo))
268
return store.IndexOf (temp_table, photo as Photo);
271
private int [] IndicesOf (DbItem [] dbitems)
273
uint timer = Log.DebugTimerStart ();
274
List<int> indices = new List<int> ();
275
List<uint> items_to_search = new List<uint> ();
277
foreach (DbItem dbitem in dbitems) {
278
if (reverse_lookup.TryGetValue (dbitem.Id, out cur))
281
items_to_search.Add (dbitem.Id);
284
if (items_to_search.Count > 0)
285
indices.AddRange (store.IndicesOf (temp_table, items_to_search.ToArray ()));
286
Log.DebugTimerPrint (timer, "IndicesOf took {0}");
287
return indices.ToArray ();
290
public int LookupItem (System.DateTime date)
292
return LookupItem (date, TimeOrderAsc);
295
private int LookupItem (System.DateTime date, bool asc)
297
uint timer = Log.DebugTimerStart ();
299
int high = Count - 1;
300
int mid = (low + high) / 2;
302
while (low <= high) {
303
mid = (low + high) / 2;
304
if (!cache.TryGetPhoto (mid, out current))
305
//the item we're looking for is not in the cache
306
//a binary search could take up to ln2 (N/cache.SIZE) request
307
//lets reduce that number to 1
308
return store.IndexOf (temp_table, date, asc);
310
int comp = this [mid].Time.CompareTo (date);
311
if (!asc && comp < 0 || asc && comp > 0)
313
else if (!asc && comp > 0 || asc && comp < 0)
318
Log.DebugTimerPrint (timer, "LookupItem took {0}");
320
return this[mid].Time < date ? mid + 1 : mid;
321
return this[mid].Time > date ? mid + 1 : mid;
325
public void Commit (int index)
327
Commit (new int [] {index});
330
public void Commit (int [] indexes)
332
List<Photo> to_commit = new List<Photo>();
333
foreach (int index in indexes) {
334
to_commit.Add (this [index] as Photo);
335
reverse_lookup [(this [index] as Photo).Id] = index;
337
store.Commit (to_commit.ToArray ());
340
private void MarkChanged (object sender, DbItemEventArgs args)
342
int [] indexes = IndicesOf (args.Items);
344
if (indexes.Length > 0 && ItemsChanged != null)
345
ItemsChanged (this, new BrowsableEventArgs(indexes, (args as PhotoEventArgs).Changes));
348
public void MarkChanged (int index, IBrowsableItemChanges changes)
350
MarkChanged (new int [] {index}, changes);
353
public void MarkChanged (int [] indexes, IBrowsableItemChanges changes)
355
ItemsChanged (this, new BrowsableEventArgs (indexes, changes));