4 // Copyright (C) 2006 Debajyoti Bera <dbera.web@gmail.com>
5 // Copyright (C) 2006 Novell, Inc.
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.
39 using System
.Collections
;
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
{
56 internal void AddTag (string tag
) {
58 tags
= new ArrayList ();
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 LIKE '{0}' and images.name LIKE '{1}'";
70 private const string tags_parenttags_sql_string
= @"SELECT t1.name, t2.name
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
{
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
))
96 StreamReader reader
= new StreamReader (digikamrc
);
99 while ((line
= reader
.ReadLine ()) != null) {
100 if (line
.StartsWith ("[") && line
.EndsWith ("]")) {
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);
122 private static SqliteConnection Connection
{
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)
135 tag_parent_cache.Clear ();
136 tag_parent_cache = null;
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";
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);
163 if (! path
.StartsWith (album_path
))
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
= String
.Format (tags_sql_string
, relative_path
, filename
);
174 //Console.WriteLine ("SQL string: " + command.CommandText);
176 SqliteDataReader reader
= command
.ExecuteReader ();
177 DigikamData imagedata
= null;
179 if (reader
.Read ()) {
180 imagedata
= new DigikamData ();
181 imagedata
.caption
= (string) reader
[0];
182 tag
= ((string) reader
[1]);
183 //Console.WriteLine ("Found caption:" + imagedata.caption);
191 if (imagedata
== null)
193 while (tag
!= null && tag
!= String
.Empty
) {
194 //Console.WriteLine ("Found tag: " + tag);
195 imagedata
.AddTag (tag
);
196 tag
= GetParentTag (tag
);
202 private static string GetParentTag (string tag
)
207 if (tag_parent_cache
!= null)
208 return (string) tag_parent_cache
[tag
];
210 tag_parent_cache
= new Hashtable ();
211 SqliteCommand command
= new SqliteCommand ();
212 command
.Connection
= Connection
;
213 command
.CommandText
= tags_parenttags_sql_string
;
215 SqliteDataReader reader
= command
.ExecuteReader ();
216 while (reader
.Read ()) {
217 string name
= (string) reader
[0];
218 string parent_name
= (string) reader
[1];
219 tag_parent_cache
[name
] = parent_name
;
224 return (string) tag_parent_cache
[tag
];