Dont reindex already indexed files. Yet another bug uncovered by the DateTime fixes.
[beagle.git] / Util / FSpotTools.cs
blob559f305b758f8a0fa7748fbba86f5ec34dbf7e12
1 //
2 // FSpotTools.cs
3 //
4 // Copyright (C) 2004 Novell, Inc.
5 //
7 //
8 // Permission is hereby granted, free of charge, to any person obtaining a
9 // copy of this software and associated documentation files (the "Software"),
10 // to deal in the Software without restriction, including without limitation
11 // the rights to use, copy, modify, merge, publish, distribute, sublicense,
12 // and/or sell copies of the Software, and to permit persons to whom the
13 // Software is furnished to do so, subject to the following conditions:
15 // The above copyright notice and this permission notice shall be included in
16 // all copies or substantial portions of the Software.
18 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
23 // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
24 // DEALINGS IN THE SOFTWARE.
27 using System;
28 using System.Collections;
29 using System.IO;
30 using Mono.Data.SqliteClient;
32 namespace Beagle.Util {
34 public class FSpotTools {
36 public class Tag {
37 public uint Id;
38 public string Name;
39 public uint CategoryId;
40 public bool IsCategory;
41 public int SortPriority;
42 public Tag Category;
43 // FIXME: Icon
46 public class Photo {
47 public uint Id;
48 public string Path;
49 public string Description;
50 public Tag[] Tags;
53 static private bool tried_connection;
54 static private SqliteConnection connection;
55 static Hashtable tagCache = null;
56 static Hashtable directoryCache = null;
59 static private string PhotoStorePath {
60 get {
61 string home = Environment.GetEnvironmentVariable ("HOME");
62 return Path.Combine (home, ".gnome2/f-spot/photos.db");
66 static private SqliteConnection PhotoStoreConnection {
67 get {
68 if (! tried_connection && File.Exists (PhotoStorePath)) {
69 connection = new SqliteConnection ();
70 connection.ConnectionString = "version=" + ExternalStringsHack.SqliteVersion
71 + ",URI=file:" + PhotoStorePath;
73 // Try to open the f-spot store. This
74 // will fail if there is a version
75 // mismatch.
76 try {
77 connection.Open ();
78 } catch (ApplicationException) {
79 Logger.Log.Warn ("Unable to open F-Spot database: sqlite version mismatch");
80 connection = null;
83 tried_connection = true;
86 return connection;
90 static private bool HavePhotoStore {
91 get {
92 return PhotoStoreConnection != null;
96 // FIXME: We should expire this cache if the underlying db has changed.
97 static private Tag GetTagById (uint id)
99 if (! HavePhotoStore)
100 return null;
102 if (tagCache == null) {
103 tagCache = new Hashtable ();
105 SqliteCommand command = new SqliteCommand ();
106 command.Connection = PhotoStoreConnection;
107 command.CommandText = "SELECT id, name, category_id, is_category, sort_priority FROM tags";
109 SqliteDataReader reader = command.ExecuteReader ();
110 while (reader.Read ()) {
111 Tag tag = new Tag ();
112 tag.Id = Convert.ToUInt32 (reader [0]);
113 tag.Name = (string) reader [1];
114 tag.CategoryId = Convert.ToUInt32 (reader [2]);
115 tag.IsCategory = (((string)reader [3]) == "1");
116 tag.SortPriority = Convert.ToInt32 (reader [4]);
117 tagCache [tag.Id] = tag;
120 // Walk across all tags, linking to the category's Tag
121 // object. Since the tagCache is fully populated, it is
122 // safe to call GetTagById here.
123 foreach (Tag tag in tagCache.Values)
124 tag.Category = GetTagById (tag.CategoryId);
126 command.Dispose ();
129 return (Tag) tagCache [id];
132 // FIXME: We should expire this cache if the underlying db has changed.
133 static bool IsPossibleDirectory (string directory)
135 if (! HavePhotoStore)
136 return false;
138 if (directoryCache == null) {
139 directoryCache = new Hashtable ();
141 SqliteCommand command = new SqliteCommand ();
142 command.Connection = PhotoStoreConnection;
143 command.CommandText = "SELECT DISTINCT directory_path FROM photos";
145 SqliteDataReader reader = command.ExecuteReader ();
146 while (reader.Read ()) {
147 directoryCache [reader [0]] = true;
150 command.Dispose ();
153 return directoryCache.Contains (directory);
156 static public Photo GetPhoto (string path)
158 if (! HavePhotoStore)
159 return null;
161 path = Path.GetFullPath (path);
162 string dir = Path.GetDirectoryName (path);
163 string name = Path.GetFileName (path);
165 if (! IsPossibleDirectory (dir))
166 return null;
168 SqliteCommand command;
169 SqliteDataReader reader;
171 command = new SqliteCommand ();
172 command.Connection = PhotoStoreConnection;
173 command.CommandText = String.Format ("SELECT id, description " +
174 "FROM photos " +
175 "WHERE directory_path = \"{0}\" " +
176 " AND name = \"{1}\"",
177 dir, name);
179 Photo photo = null;
180 reader = command.ExecuteReader ();
181 if (reader.Read ()) {
182 photo = new Photo ();
183 photo.Path = path;
184 photo.Id = Convert.ToUInt32 (reader [0]);
185 photo.Description = (string) reader [1];
188 command.Dispose ();
190 if (photo != null) {
191 command = new SqliteCommand ();
192 command.Connection = PhotoStoreConnection;
193 command.CommandText = String.Format ("SELECT tag_id " +
194 "FROM photo_tags " +
195 "WHERE photo_id = {0}",
196 photo.Id);
198 Hashtable tagHash = new Hashtable ();
200 // Mark the photo with both any tags and all parents.
201 // Maybe this isn't the right thing to do, but it seems
202 // to most closely mirror the tag semantics implied by f-spot.
203 reader = command.ExecuteReader ();
204 while (reader.Read ()) {
205 uint id = Convert.ToUInt32 (reader [0]);
206 Tag tag = GetTagById (id);
207 while (tag != null) {
208 tagHash [tag] = tag;
209 tag = tag.Category;
213 photo.Tags = new Tag [tagHash.Count];
214 int i = 0;
215 foreach (Tag t in tagHash.Values) {
216 photo.Tags [i] = t;
217 ++i;
221 return photo;