Simplify vflist_get_formatted()
[geeqie.git] / src / cache-loader.c
1 /*
2  * Copyright (C) 2004 John Ellis
3  * Copyright (C) 2008 - 2016 The Geeqie Team
4  *
5  * Author: John Ellis
6  *
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 2 of the License, or
10  * (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License along
18  * with this program; if not, write to the Free Software Foundation, Inc.,
19  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20  */
21
22 #include "main.h"
23 #include "cache-loader.h"
24 #include "cache.h"
25
26 #include "filedata.h"
27 #include "exif.h"
28 #include "metadata.h"
29 #include "md5-util.h"
30 #include "ui_fileops.h"
31
32
33 static gboolean cache_loader_phase2_idle_cb(gpointer data);
34
35 static void cache_loader_phase1_done_cb(ImageLoader *il, gpointer data)
36 {
37         CacheLoader *cl = data;
38
39         cl->idle_id = g_idle_add(cache_loader_phase2_idle_cb, cl);
40 }
41
42 static void cache_loader_phase1_error_cb(ImageLoader *il, gpointer data)
43 {
44         CacheLoader *cl = data;
45
46         cl->error = TRUE;
47         cl->idle_id = g_idle_add(cache_loader_phase2_idle_cb, cl);
48 }
49
50 static gboolean cache_loader_phase1_process(CacheLoader *cl)
51 {
52         if (cl->todo_mask & CACHE_LOADER_SIMILARITY && !cl->cd->similarity)
53                 {
54
55                 if (!cl->il && !cl->error)
56                         {
57                         cl->il = image_loader_new(cl->fd);
58                         g_signal_connect(G_OBJECT(cl->il), "error", (GCallback)cache_loader_phase1_error_cb, cl);
59                         g_signal_connect(G_OBJECT(cl->il), "done", (GCallback)cache_loader_phase1_done_cb, cl);
60                         if (image_loader_start(cl->il))
61                                 {
62                                 return FALSE;
63                                 }
64
65                         cl->error = TRUE;
66                         }
67                 }
68
69         cl->idle_id = g_idle_add(cache_loader_phase2_idle_cb, cl);
70
71         return FALSE;
72 }
73
74 static gboolean cache_loader_phase2_process(CacheLoader *cl)
75 {
76         if (cl->todo_mask & CACHE_LOADER_SIMILARITY && !cl->cd->similarity && cl->il)
77                 {
78                 GdkPixbuf *pixbuf;
79                 pixbuf = image_loader_get_pixbuf(cl->il);
80                 if (pixbuf)
81                         {
82                         if (!cl->error)
83                                 {
84                                 ImageSimilarityData *sim;
85
86                                 sim = image_sim_new_from_pixbuf(pixbuf);
87                                 cache_sim_data_set_similarity(cl->cd, sim);
88                                 image_sim_free(sim);
89
90                                 cl->todo_mask &= ~CACHE_LOADER_SIMILARITY;
91                                 cl->done_mask |= CACHE_LOADER_SIMILARITY;
92                                 }
93
94                         /* we have the dimensions via pixbuf */
95                         if (!cl->cd->dimensions)
96                                 {
97                                 cache_sim_data_set_dimensions(cl->cd, gdk_pixbuf_get_width(pixbuf),
98                                                                       gdk_pixbuf_get_height(pixbuf));
99                                 if (cl->todo_mask & CACHE_LOADER_DIMENSIONS)
100                                         {
101                                         cl->todo_mask &= ~CACHE_LOADER_DIMENSIONS;
102                                         cl->done_mask |= CACHE_LOADER_DIMENSIONS;
103                                         }
104                                 }
105                         }
106
107                 image_loader_free(cl->il);
108                 cl->il = NULL;
109
110                 cl->todo_mask &= ~CACHE_LOADER_SIMILARITY;
111                 }
112         else if (cl->todo_mask & CACHE_LOADER_DIMENSIONS &&
113                  !cl->cd->dimensions)
114                 {
115                 if (!cl->error &&
116                     image_load_dimensions(cl->fd, &cl->cd->width, &cl->cd->height))
117                         {
118                         cl->cd->dimensions = TRUE;
119                         cl->done_mask |= CACHE_LOADER_DIMENSIONS;
120                         }
121                 else
122                         {
123                         cl->error = TRUE;
124                         }
125
126                 cl->todo_mask &= ~CACHE_LOADER_DIMENSIONS;
127                 }
128         else if (cl->todo_mask & CACHE_LOADER_MD5SUM &&
129                  !cl->cd->have_md5sum)
130                 {
131                 if (md5_get_digest_from_file_utf8(cl->fd->path, cl->cd->md5sum))
132                         {
133                         cl->cd->have_md5sum = TRUE;
134                         cl->done_mask |= CACHE_LOADER_MD5SUM;
135                         }
136                 else
137                         {
138                         cl->error = TRUE;
139                         }
140
141                 cl->todo_mask &= ~CACHE_LOADER_MD5SUM;
142                 }
143         else if (cl->todo_mask & CACHE_LOADER_DATE &&
144                  !cl->cd->have_date)
145                 {
146                 time_t date = -1;
147                 gchar *text;
148
149                 text =  metadata_read_string(cl->fd, "Exif.Image.DateTime", METADATA_FORMATTED);
150                 if (text)
151                         {
152                         struct tm t;
153
154                         memset(&t, 0, sizeof(t));
155
156                         if (sscanf(text, "%d:%d:%d %d:%d:%d", &t.tm_year, &t.tm_mon, &t.tm_mday,
157                                    &t.tm_hour, &t.tm_min, &t.tm_sec) == 6)
158                                 {
159                                 t.tm_year -= 1900;
160                                 t.tm_mon -= 1;
161                                 t.tm_isdst = -1;
162                                 date = mktime(&t);
163                                 }
164                         g_free(text);
165                         }
166
167                 cl->cd->date = date;
168                 cl->cd->have_date = TRUE;
169
170                 cl->done_mask |= CACHE_LOADER_DATE;
171                 cl->todo_mask &= ~CACHE_LOADER_DATE;
172                 }
173         else
174                 {
175                 /* done, save then call done function */
176                 if (options->thumbnails.enable_caching &&
177                     cl->done_mask != CACHE_LOADER_NONE)
178                         {
179                         gchar *base;
180                         mode_t mode = 0755;
181
182                         base = cache_get_location(CACHE_TYPE_SIM, cl->fd->path, FALSE, &mode);
183                         if (recursive_mkdir_if_not_exists(base, mode))
184                                 {
185                                 g_free(cl->cd->path);
186                                 cl->cd->path = cache_get_location(CACHE_TYPE_SIM, cl->fd->path, TRUE, NULL);
187                                 if (cache_sim_data_save(cl->cd))
188                                         {
189                                         filetime_set(cl->cd->path, filetime(cl->fd->path));
190                                         }
191                                 }
192                         g_free(base);
193                         }
194
195                 cl->idle_id = 0;
196
197                 if (cl->done_func)
198                         {
199                         cl->done_func(cl, cl->error, cl->done_data);
200                         }
201
202                 return FALSE;
203                 }
204
205         return TRUE;
206 }
207
208 static gboolean cache_loader_phase1_idle_cb(gpointer data)
209 {
210         CacheLoader *cl = data;
211
212         return cache_loader_phase1_process(cl);
213 }
214
215 static gboolean cache_loader_phase2_idle_cb(gpointer data)
216 {
217         CacheLoader *cl = data;
218
219         return cache_loader_phase2_process(cl);
220 }
221
222 CacheLoader *cache_loader_new(FileData *fd, CacheDataType load_mask,
223                               CacheLoaderDoneFunc done_func, gpointer done_data)
224 {
225         CacheLoader *cl;
226         gchar *found;
227
228         if (!fd || !isfile(fd->path)) return NULL;
229
230         cl = g_new0(CacheLoader, 1);
231         cl->fd = file_data_ref(fd);
232
233         cl->done_func = done_func;
234         cl->done_data = done_data;
235
236         found = cache_find_location(CACHE_TYPE_SIM, cl->fd->path);
237         if (found && filetime(found) == filetime(cl->fd->path))
238                 {
239                 cl->cd = cache_sim_data_load(found);
240                 }
241         g_free(found);
242
243         if (!cl->cd) cl->cd = cache_sim_data_new();
244
245         cl->todo_mask = load_mask;
246         cl->done_mask = CACHE_LOADER_NONE;
247
248         cl->il = NULL;
249         cl->idle_id = g_idle_add(cache_loader_phase1_idle_cb, cl);
250
251         cl->error = FALSE;
252
253         return cl;
254 }
255
256 void cache_loader_free(CacheLoader *cl)
257 {
258         if (!cl) return;
259
260         if (cl->idle_id)
261                 {
262                 g_source_remove_by_user_data(cl);
263                 cl->idle_id = 0;
264                 }
265
266         image_loader_free(cl->il);
267         cache_sim_data_free(cl->cd);
268
269         file_data_unref(cl->fd);
270         g_free(cl);
271 }
272 /* vim: set shiftwidth=8 softtabstop=0 cindent cinoptions={1s: */