4 // Copyright (C) 2004 Novell, Inc.
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.
28 using System
.Collections
;
30 using Mono
.Data
.SqliteClient
;
32 namespace Beagle
.Util
{
34 public class FSpotTools
{
39 public uint CategoryId
;
40 public bool IsCategory
;
41 public int SortPriority
;
49 public string Description
;
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
{
61 string home
= Environment
.GetEnvironmentVariable ("HOME");
62 return Path
.Combine (home
, ".gnome2/f-spot/photos.db");
66 static private SqliteConnection PhotoStoreConnection
{
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
78 } catch (ApplicationException
) {
79 Logger
.Log
.Warn ("Unable to open F-Spot database: sqlite version mismatch");
82 tried_connection
= true;
89 static private bool HavePhotoStore
{
91 return PhotoStoreConnection
!= null;
95 // FIXME: We should expire this cache if the underlying db has changed.
96 static private Tag
GetTagById (uint id
)
101 if (tagCache
== null) {
102 tagCache
= new Hashtable ();
104 SqliteCommand command
= new SqliteCommand ();
105 command
.Connection
= PhotoStoreConnection
;
106 command
.CommandText
= "SELECT id, name, category_id, is_category, sort_priority FROM tags";
108 SqliteDataReader reader
= command
.ExecuteReader ();
109 while (reader
.Read ()) {
110 Tag tag
= new Tag ();
111 tag
.Id
= Convert
.ToUInt32 (reader
[0]);
112 tag
.Name
= (string) reader
[1];
113 tag
.CategoryId
= Convert
.ToUInt32 (reader
[2]);
114 tag
.IsCategory
= (((string)reader
[3]) == "1");
115 tag
.SortPriority
= Convert
.ToInt32 (reader
[4]);
116 tagCache
[tag
.Id
] = tag
;
119 // Walk across all tags, linking to the category's Tag
120 // object. Since the tagCache is fully populated, it is
121 // safe to call GetTagById here.
122 foreach (Tag tag
in tagCache
.Values
)
123 tag
.Category
= GetTagById (tag
.CategoryId
);
128 return (Tag
) tagCache
[id
];
131 // FIXME: We should expire this cache if the underlying db has changed.
132 static bool IsPossibleDirectory (string directory
)
134 if (! HavePhotoStore
)
137 if (directoryCache
== null) {
138 directoryCache
= new Hashtable ();
140 SqliteCommand command
= new SqliteCommand ();
141 command
.Connection
= PhotoStoreConnection
;
142 command
.CommandText
= "SELECT DISTINCT directory_path FROM photos";
144 SqliteDataReader reader
= command
.ExecuteReader ();
145 while (reader
.Read ()) {
146 directoryCache
[reader
[0]] = true;
152 return directoryCache
.Contains (directory
);
155 static public Photo
GetPhoto (string path
)
157 if (! HavePhotoStore
)
160 path
= Path
.GetFullPath (path
);
161 string dir
= Path
.GetDirectoryName (path
);
162 string name
= Path
.GetFileName (path
);
164 if (! IsPossibleDirectory (dir
))
167 SqliteCommand command
;
168 SqliteDataReader reader
;
170 command
= new SqliteCommand ();
171 command
.Connection
= PhotoStoreConnection
;
172 command
.CommandText
= String
.Format ("SELECT id, description " +
174 "WHERE directory_path = \"{0}\" " +
175 " AND name = \"{1}\"",
179 reader
= command
.ExecuteReader ();
180 if (reader
.Read ()) {
181 photo
= new Photo ();
183 photo
.Id
= Convert
.ToUInt32 (reader
[0]);
184 photo
.Description
= (string) reader
[1];
190 command
= new SqliteCommand ();
191 command
.Connection
= PhotoStoreConnection
;
192 command
.CommandText
= String
.Format ("SELECT tag_id " +
194 "WHERE photo_id = {0}",
197 Hashtable tagHash
= new Hashtable ();
199 // Mark the photo with both any tags and all parents.
200 // Maybe this isn't the right thing to do, but it seems
201 // to most closely mirror the tag semantics implied by f-spot.
202 reader
= command
.ExecuteReader ();
203 while (reader
.Read ()) {
204 uint id
= Convert
.ToUInt32 (reader
[0]);
205 Tag tag
= GetTagById (id
);
206 while (tag
!= null) {
212 photo
.Tags
= new Tag
[tagHash
.Count
];
214 foreach (Tag t
in tagHash
.Values
) {