cvsimport
[beagle.git] / Util / DigikamTags.cs
blob8cd444164f01c988935ae06c10b27693cc031686
1 //
2 // DigikamTags.cs
3 //
4 // Copyright (C) 2006 Debajyoti Bera <dbera.web@gmail.com>
5 // Copyright (C) 2006 Novell, Inc.
6 //
8 //
9 // Permission is hereby granted, free of charge, to any person obtaining a
10 // copy of this software and associated documentation files (the "Software"),
11 // to deal in the Software without restriction, including without limitation
12 // the rights to use, copy, modify, merge, publish, distribute, sublicense,
13 // and/or sell copies of the Software, and to permit persons to whom the
14 // Software is furnished to do so, subject to the following conditions:
16 // The above copyright notice and this permission notice shall be included in
17 // all copies or substantial portions of the Software.
19 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
24 // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
25 // DEALINGS IN THE SOFTWARE.
28 // Big FIXME: There is a basic problem in retrieving information from Digikam DB.
29 // If some metadata is added to the DB, the DB will be changed and beagle
30 // will pick up the changed information _only_ when it indexes the file in
31 // question. Which means, under normal circumstances, if a user adds some
32 // information/tags to an image and the image file is not modified on disk,
33 // beagle will _not_ get the updated information for that file.
34 // Is there any way to force beagle to re-index the file ? Maybe send an
35 // IndexableChange message or something like that ... simply doing that
36 // might cause double indexing of the file.
38 using System;
39 using System.Collections;
40 using System.IO;
41 using Mono.Data.SqliteClient;
43 namespace Beagle.Util {
45 public static class DigikamTags {
47 public class DigikamData {
48 public string caption;
49 private ArrayList tags = null;
50 // FIXME: Icon ? KdeIcon ?
52 public IEnumerable Tags {
53 get { return tags; }
56 internal void AddTag (string tag) {
57 if (tags == null)
58 tags = new ArrayList ();
59 tags.Add (tag);
63 private static string album_path = null;
64 private static string db_path = null;
65 private static string digikamrc = null;
66 private const string tags_sql_string = @"SELECT images.caption, tags.name, tags.pid
67 FROM albums, images, imagetags, tags
68 WHERE images.id=imagetags.imageid AND imagetags.tagid=tags.id AND
69 albums.url=@AlbumsUrl AND images.name=@ImagesName";
70 private const string tags_parenttags_sql_string = @"SELECT t1.name, t2.name
71 FROM tags t1, tags t2
72 WHERE t1.pid=t2.id";
74 // need to cache a lot of things
75 private static DateTime db_last_modified_date;
76 private static SqliteConnection connection = null;
77 private static Hashtable tag_parent_cache = null;
79 // Every value has to be a property since they need to be checked everytime.
80 // User may install/start using digikam in the middle of running beagle.
81 private static string DBPath {
82 get {
83 if (db_path != null)
84 return db_path;
86 // FIXME: Also check the last write time of digikamrc.
87 string digikamrc = Path.Combine (PathFinder.HomeDir, ".kde");
88 digikamrc = Path.Combine (digikamrc, "share");
89 digikamrc = Path.Combine (digikamrc, "config");
90 digikamrc = Path.Combine (digikamrc, "digikamrc");
92 //Console.WriteLine ("Checking digikamrc at :" + digikamrc);
93 if ( ! File.Exists (digikamrc))
94 return null;
96 StreamReader reader = new StreamReader (digikamrc);
97 string section = "";
98 string line;
99 while ((line = reader.ReadLine ()) != null) {
100 if (line.StartsWith ("[") && line.EndsWith ("]")) {
101 section = line;
103 if (section == "[Album Settings]") {
104 if (line.StartsWith ("Album Path=") && line.Length > 11) {
105 album_path = StringFu.ExpandEnvVariables (line.Substring(11));
110 // FIXME: Also support the old-age sqlite-2 based digikam.db ?
111 db_path = Path.Combine (album_path, "digikam3.db");
113 // remove trailing '/'
114 if (album_path.EndsWith ("/"))
115 album_path = album_path.Substring (0, album_path.LastIndexOf ("/"));
117 //Console.WriteLine ("db should be at:" + db_path);
118 return db_path;
122 private static SqliteConnection Connection {
123 get {
124 if (connection != null) {
126 // FIXME: Following lines will enable refreshing cache information
127 // if digikam3.db is modified. Not sure how beagled will be able
128 // to handle the situation when a user is on a marathon tagging
129 // mission. Beware fragile! Take care.
130 if (File.GetLastWriteTimeUtc (album_path) <= db_last_modified_date)
131 return connection;
132 else {
133 connection.Close ();
134 connection = null;
135 tag_parent_cache.Clear ();
136 tag_parent_cache = null;
139 return connection;
142 if (File.Exists (DBPath)) {
143 db_last_modified_date = File.GetLastWriteTimeUtc(db_path);
144 connection = new SqliteConnection ();
145 connection.ConnectionString = "URI=file:" + db_path + ",version=3";
146 connection.Open ();
149 return connection;
153 private static bool IsPresent {
154 get { return (Connection != null); }
157 public static DigikamData GetDigikamData (string path)
159 //Console.WriteLine ("Fetching digikam information about:" + path);
160 if (! IsPresent)
161 return null;
163 if (! path.StartsWith (album_path))
164 return null;
166 string filename = Path.GetFileName (path);
167 string dirname = Path.GetDirectoryName (path);
168 string relative_path = dirname.Remove (0, album_path.Length);
169 //Console.WriteLine ("location=[" + relative_path + "]/[" + filename + "]");
171 SqliteCommand command = new SqliteCommand ();
172 command.Connection = Connection;
173 command.CommandText = tags_sql_string;
174 command.Parameters.Add ("@AlbumsUrl", relative_path);
175 command.Parameters.Add ("@ImagesName", filename);
177 SqliteDataReader reader = command.ExecuteReader ();
179 DigikamData imagedata = null;
180 ArrayList original_tags = null;
181 if (reader.Read ()) {
182 imagedata = new DigikamData ();
183 original_tags = new ArrayList ();
184 imagedata.caption = (string) reader [0];
185 original_tags.Add ((string) reader [1]);
186 //Console.WriteLine ("Found caption:" + imagedata.caption);
188 while (reader.Read ()) {
189 original_tags.Add ((string) reader [1]);
192 reader.Close ();
193 reader = null;
194 command.Dispose ();
195 command = null;
197 if (imagedata == null)
198 return null;
199 SortedList s_list = new SortedList ();
200 foreach (string orig_tag in original_tags) {
201 string tag = orig_tag;
202 while ( tag != null && tag != String.Empty) {
203 if (s_list.ContainsKey (tag)) {
204 break;
206 //Console.WriteLine ("Found tag: " + tag);
207 s_list.Add (tag, null);
208 imagedata.AddTag (tag);
209 tag = GetParentTag (tag);
213 return imagedata;
216 private static string GetParentTag (string tag)
218 if (! IsPresent)
219 return null;
221 if (tag_parent_cache != null)
222 return (string) tag_parent_cache [tag];
224 tag_parent_cache = new Hashtable ();
225 SqliteCommand command = new SqliteCommand ();
226 command.Connection = Connection;
227 command.CommandText = tags_parenttags_sql_string;
229 SqliteDataReader reader = command.ExecuteReader ();
230 while (reader.Read ()) {
231 string name = (string) reader [0];
232 string parent_name = (string) reader [1];
233 tag_parent_cache [name] = parent_name;
236 command.Dispose ();
238 return (string) tag_parent_cache [tag];