Mercurial > geeqie.yaz
annotate src/bar_info.c @ 276:4f526d436873
Implement secure rc file saving.
First data is written to a temporary file, then if nothing
was wrong, this file is renamed to the final name.
This way the risk of corrupted rc file is greatly reduced.
The code is borrowed from ELinks (http://elinks.cz).
author | zas_ |
---|---|
date | Tue, 08 Apr 2008 21:55:58 +0000 |
parents | 9faf34f047b1 |
children | 9995c5fb202a |
rev | line source |
---|---|
9 | 1 /* |
196 | 2 * Geeqie |
9 | 3 * (C) 2004 John Ellis |
4 * | |
5 * Author: John Ellis | |
6 * | |
7 * This software is released under the GNU General Public License (GNU GPL). | |
8 * Please read the included file COPYING for more information. | |
9 * This software comes with no warranty of any kind, use at your own risk! | |
10 */ | |
11 | |
12 | |
13 #include "gqview.h" | |
188
0584cb78aa14
write comment and keywords to xmp, sidecars are used if exist
nadvornik
parents:
138
diff
changeset
|
14 #include "exif.h" |
0584cb78aa14
write comment and keywords to xmp, sidecars are used if exist
nadvornik
parents:
138
diff
changeset
|
15 |
9 | 16 #include "bar_info.h" |
17 | |
18 #include "cache.h" | |
19 #include "filelist.h" | |
20 #include "info.h" | |
21 #include "utilops.h" | |
22 #include "ui_bookmark.h" | |
23 #include "ui_fileops.h" | |
24 #include "ui_misc.h" | |
25 #include "ui_utildlg.h" | |
26 | |
27 | |
28 #define BAR_KEYWORD_AUTOSAVE_TIME 10000 | |
29 | |
30 | |
31 static const gchar *keyword_favorite_defaults[] = { | |
32 N_("Favorite"), | |
33 N_("Todo"), | |
34 N_("People"), | |
35 N_("Places"), | |
36 N_("Art"), | |
37 N_("Nature"), | |
38 N_("Possessions"), | |
39 NULL | |
40 }; | |
41 | |
42 | |
43 static void bar_info_keyword_update_all(void); | |
44 | |
45 | |
46 /* | |
47 *------------------------------------------------------------------- | |
48 * keyword / comment utils | |
49 *------------------------------------------------------------------- | |
50 */ | |
51 | |
188
0584cb78aa14
write comment and keywords to xmp, sidecars are used if exist
nadvornik
parents:
138
diff
changeset
|
52 static gint comment_file_write(gchar *path, GList *keywords, const gchar *comment) |
9 | 53 { |
54 FILE *f; | |
55 | |
56 f = fopen(path, "w"); | |
57 if (!f) return FALSE; | |
58 | |
196 | 59 fprintf(f, "#Geeqie comment (%s)\n\n", VERSION); |
9 | 60 |
61 fprintf(f, "[keywords]\n"); | |
62 while (keywords) | |
63 { | |
64 const gchar *word = keywords->data; | |
65 keywords = keywords->next; | |
66 | |
67 fprintf(f, "%s\n", word); | |
68 } | |
69 fprintf(f, "\n"); | |
70 | |
71 fprintf(f, "[comment]\n"); | |
72 fprintf(f, "%s\n", (comment) ? comment : ""); | |
73 | |
74 fprintf(f, "#end\n"); | |
75 | |
76 fclose(f); | |
77 | |
78 return TRUE; | |
79 } | |
80 | |
188
0584cb78aa14
write comment and keywords to xmp, sidecars are used if exist
nadvornik
parents:
138
diff
changeset
|
81 static gint comment_legacy_write(FileData *fd, GList *keywords, const gchar *comment) |
9 | 82 { |
83 gchar *comment_path; | |
84 gint success = FALSE; | |
85 | |
86 /* If an existing metadata file exists, we will try writing to | |
87 * it's location regardless of the user's preference. | |
88 */ | |
138 | 89 comment_path = cache_find_location(CACHE_TYPE_METADATA, fd->path); |
9 | 90 if (comment_path && !access_file(comment_path, W_OK)) |
91 { | |
92 g_free(comment_path); | |
93 comment_path = NULL; | |
94 } | |
95 | |
96 if (!comment_path) | |
97 { | |
98 gchar *comment_dir; | |
99 mode_t mode = 0755; | |
100 | |
138 | 101 comment_dir = cache_get_location(CACHE_TYPE_METADATA, fd->path, FALSE, &mode); |
9 | 102 if (cache_ensure_dir_exists(comment_dir, mode)) |
103 { | |
138 | 104 comment_path = g_strconcat(comment_dir, "/", fd->name, |
9 | 105 GQVIEW_CACHE_EXT_METADATA, NULL); |
106 } | |
107 g_free(comment_dir); | |
108 } | |
109 | |
110 if (comment_path) | |
111 { | |
112 gchar *comment_pathl; | |
113 | |
114 if (debug) printf("Saving comment: %s\n", comment_path); | |
115 | |
116 comment_pathl = path_from_utf8(comment_path); | |
117 | |
188
0584cb78aa14
write comment and keywords to xmp, sidecars are used if exist
nadvornik
parents:
138
diff
changeset
|
118 success = comment_file_write(comment_pathl, keywords, comment); |
9 | 119 |
120 g_free(comment_pathl); | |
121 g_free(comment_path); | |
122 } | |
123 | |
124 return success; | |
125 } | |
126 | |
188
0584cb78aa14
write comment and keywords to xmp, sidecars are used if exist
nadvornik
parents:
138
diff
changeset
|
127 static gint comment_file_read(gchar *path, GList **keywords, gchar **comment) |
9 | 128 { |
129 FILE *f; | |
130 gchar s_buf[1024]; | |
131 gchar *key = NULL; | |
132 GList *list = NULL; | |
133 GString *comment_build = NULL; | |
134 | |
135 f = fopen(path, "r"); | |
136 if (!f) return FALSE; | |
137 | |
138 while (fgets(s_buf,sizeof(s_buf), f)) | |
139 { | |
140 if (s_buf[0]=='#') continue; | |
141 if (s_buf[0]=='[') | |
142 { | |
143 gint c = 0; | |
144 gchar *ptr = s_buf + 1; | |
145 | |
146 while(ptr[c] != ']' && ptr[c] != '\n' && ptr[c] != '\0') c++; | |
147 | |
148 g_free(key); | |
149 key = g_strndup(ptr, c); | |
150 } | |
151 else if (key) | |
152 { | |
153 gint newline = FALSE; | |
154 gchar *ptr = s_buf; | |
155 | |
156 while (*ptr != '\n' && *ptr != '\0') ptr++; | |
157 if (*ptr == '\n') | |
158 { | |
159 *ptr = '\0'; | |
160 newline = TRUE; | |
161 } | |
162 | |
163 if (strcasecmp(key, "keywords") == 0) | |
164 { | |
165 if (strlen(s_buf) > 0) list = g_list_prepend(list, g_strdup(s_buf)); | |
166 } | |
167 else if (strcasecmp(key, "comment") == 0) | |
168 { | |
169 if (!comment_build) comment_build = g_string_new(""); | |
170 g_string_append(comment_build, s_buf); | |
171 if (strlen(s_buf) > 0 && newline) g_string_append_c(comment_build, '\n'); | |
172 } | |
173 } | |
174 } | |
175 | |
176 fclose(f); | |
177 g_free(key); | |
178 | |
179 *keywords = g_list_reverse(list); | |
180 if (comment_build) | |
181 { | |
182 if (comment) *comment = g_strdup(comment_build->str); | |
183 g_string_free(comment_build, TRUE); | |
184 } | |
185 | |
186 return TRUE; | |
187 } | |
188 | |
204 | 189 static gint comment_delete_legacy(FileData *fd) |
190 { | |
191 gchar *comment_path; | |
192 gchar *comment_pathl; | |
193 gint success = FALSE; | |
194 if (!fd) return FALSE; | |
195 | |
196 comment_path = cache_find_location(CACHE_TYPE_METADATA, fd->path); | |
197 if (!comment_path) return FALSE; | |
198 | |
199 comment_pathl = path_from_utf8(comment_path); | |
200 | |
201 success = !unlink(comment_pathl); | |
202 | |
203 g_free(comment_pathl); | |
204 g_free(comment_path); | |
205 | |
206 return success; | |
207 } | |
208 | |
188
0584cb78aa14
write comment and keywords to xmp, sidecars are used if exist
nadvornik
parents:
138
diff
changeset
|
209 static gint comment_legacy_read(FileData *fd, GList **keywords, gchar **comment) |
9 | 210 { |
211 gchar *comment_path; | |
212 gchar *comment_pathl; | |
213 gint success = FALSE; | |
138 | 214 if (!fd) return FALSE; |
9 | 215 |
138 | 216 comment_path = cache_find_location(CACHE_TYPE_METADATA, fd->path); |
9 | 217 if (!comment_path) return FALSE; |
218 | |
219 comment_pathl = path_from_utf8(comment_path); | |
220 | |
188
0584cb78aa14
write comment and keywords to xmp, sidecars are used if exist
nadvornik
parents:
138
diff
changeset
|
221 success = comment_file_read(comment_pathl, keywords, comment); |
9 | 222 |
223 g_free(comment_pathl); | |
224 g_free(comment_path); | |
225 | |
226 return success; | |
227 } | |
228 | |
188
0584cb78aa14
write comment and keywords to xmp, sidecars are used if exist
nadvornik
parents:
138
diff
changeset
|
229 gchar *comment_key = "Xmp.dc.description"; |
0584cb78aa14
write comment and keywords to xmp, sidecars are used if exist
nadvornik
parents:
138
diff
changeset
|
230 gchar *keyword_key = "Xmp.dc.subject"; |
0584cb78aa14
write comment and keywords to xmp, sidecars are used if exist
nadvornik
parents:
138
diff
changeset
|
231 |
0584cb78aa14
write comment and keywords to xmp, sidecars are used if exist
nadvornik
parents:
138
diff
changeset
|
232 static gint comment_xmp_read(FileData *fd, GList **keywords, gchar **comment) |
0584cb78aa14
write comment and keywords to xmp, sidecars are used if exist
nadvornik
parents:
138
diff
changeset
|
233 { |
0584cb78aa14
write comment and keywords to xmp, sidecars are used if exist
nadvornik
parents:
138
diff
changeset
|
234 ExifData *exif = exif_read_fd(fd, FALSE); |
204 | 235 gint success; |
188
0584cb78aa14
write comment and keywords to xmp, sidecars are used if exist
nadvornik
parents:
138
diff
changeset
|
236 if (!exif) return FALSE; |
0584cb78aa14
write comment and keywords to xmp, sidecars are used if exist
nadvornik
parents:
138
diff
changeset
|
237 |
0584cb78aa14
write comment and keywords to xmp, sidecars are used if exist
nadvornik
parents:
138
diff
changeset
|
238 if (comment) |
0584cb78aa14
write comment and keywords to xmp, sidecars are used if exist
nadvornik
parents:
138
diff
changeset
|
239 { |
0584cb78aa14
write comment and keywords to xmp, sidecars are used if exist
nadvornik
parents:
138
diff
changeset
|
240 ExifItem *item = exif_get_item(exif, comment_key); |
0584cb78aa14
write comment and keywords to xmp, sidecars are used if exist
nadvornik
parents:
138
diff
changeset
|
241 *comment = exif_item_get_string(item, 0); |
0584cb78aa14
write comment and keywords to xmp, sidecars are used if exist
nadvornik
parents:
138
diff
changeset
|
242 } |
0584cb78aa14
write comment and keywords to xmp, sidecars are used if exist
nadvornik
parents:
138
diff
changeset
|
243 |
0584cb78aa14
write comment and keywords to xmp, sidecars are used if exist
nadvornik
parents:
138
diff
changeset
|
244 if (keywords) |
0584cb78aa14
write comment and keywords to xmp, sidecars are used if exist
nadvornik
parents:
138
diff
changeset
|
245 { |
0584cb78aa14
write comment and keywords to xmp, sidecars are used if exist
nadvornik
parents:
138
diff
changeset
|
246 ExifItem *item = exif_get_item(exif, keyword_key); |
0584cb78aa14
write comment and keywords to xmp, sidecars are used if exist
nadvornik
parents:
138
diff
changeset
|
247 int count = exif_item_get_elements(item); |
0584cb78aa14
write comment and keywords to xmp, sidecars are used if exist
nadvornik
parents:
138
diff
changeset
|
248 int i = 0; |
0584cb78aa14
write comment and keywords to xmp, sidecars are used if exist
nadvornik
parents:
138
diff
changeset
|
249 GList *work = NULL; |
0584cb78aa14
write comment and keywords to xmp, sidecars are used if exist
nadvornik
parents:
138
diff
changeset
|
250 char *kw = NULL; |
0584cb78aa14
write comment and keywords to xmp, sidecars are used if exist
nadvornik
parents:
138
diff
changeset
|
251 |
0584cb78aa14
write comment and keywords to xmp, sidecars are used if exist
nadvornik
parents:
138
diff
changeset
|
252 while (i < count && (kw = exif_item_get_string(item, i++))) |
0584cb78aa14
write comment and keywords to xmp, sidecars are used if exist
nadvornik
parents:
138
diff
changeset
|
253 { |
0584cb78aa14
write comment and keywords to xmp, sidecars are used if exist
nadvornik
parents:
138
diff
changeset
|
254 work = g_list_append(work, (gpointer) kw); |
0584cb78aa14
write comment and keywords to xmp, sidecars are used if exist
nadvornik
parents:
138
diff
changeset
|
255 } |
0584cb78aa14
write comment and keywords to xmp, sidecars are used if exist
nadvornik
parents:
138
diff
changeset
|
256 |
0584cb78aa14
write comment and keywords to xmp, sidecars are used if exist
nadvornik
parents:
138
diff
changeset
|
257 *keywords = work; |
0584cb78aa14
write comment and keywords to xmp, sidecars are used if exist
nadvornik
parents:
138
diff
changeset
|
258 } |
0584cb78aa14
write comment and keywords to xmp, sidecars are used if exist
nadvornik
parents:
138
diff
changeset
|
259 |
0584cb78aa14
write comment and keywords to xmp, sidecars are used if exist
nadvornik
parents:
138
diff
changeset
|
260 exif_free(exif); |
204 | 261 |
262 success = *comment || *keywords; | |
263 | |
264 return success; | |
188
0584cb78aa14
write comment and keywords to xmp, sidecars are used if exist
nadvornik
parents:
138
diff
changeset
|
265 } |
0584cb78aa14
write comment and keywords to xmp, sidecars are used if exist
nadvornik
parents:
138
diff
changeset
|
266 |
0584cb78aa14
write comment and keywords to xmp, sidecars are used if exist
nadvornik
parents:
138
diff
changeset
|
267 static gint comment_xmp_write(FileData *fd, GList *keywords, const gchar *comment) |
0584cb78aa14
write comment and keywords to xmp, sidecars are used if exist
nadvornik
parents:
138
diff
changeset
|
268 { |
0584cb78aa14
write comment and keywords to xmp, sidecars are used if exist
nadvornik
parents:
138
diff
changeset
|
269 gint success = FALSE; |
0584cb78aa14
write comment and keywords to xmp, sidecars are used if exist
nadvornik
parents:
138
diff
changeset
|
270 GList *work = keywords; |
0584cb78aa14
write comment and keywords to xmp, sidecars are used if exist
nadvornik
parents:
138
diff
changeset
|
271 ExifData *exif = exif_read_fd(fd, FALSE); |
0584cb78aa14
write comment and keywords to xmp, sidecars are used if exist
nadvornik
parents:
138
diff
changeset
|
272 if (!exif) return FALSE; |
0584cb78aa14
write comment and keywords to xmp, sidecars are used if exist
nadvornik
parents:
138
diff
changeset
|
273 |
0584cb78aa14
write comment and keywords to xmp, sidecars are used if exist
nadvornik
parents:
138
diff
changeset
|
274 ExifItem *item = exif_get_item(exif, comment_key); |
0584cb78aa14
write comment and keywords to xmp, sidecars are used if exist
nadvornik
parents:
138
diff
changeset
|
275 |
0584cb78aa14
write comment and keywords to xmp, sidecars are used if exist
nadvornik
parents:
138
diff
changeset
|
276 if (item && !(comment && comment[0])) |
0584cb78aa14
write comment and keywords to xmp, sidecars are used if exist
nadvornik
parents:
138
diff
changeset
|
277 { |
0584cb78aa14
write comment and keywords to xmp, sidecars are used if exist
nadvornik
parents:
138
diff
changeset
|
278 exif_item_delete(exif, item); |
0584cb78aa14
write comment and keywords to xmp, sidecars are used if exist
nadvornik
parents:
138
diff
changeset
|
279 item = NULL; |
0584cb78aa14
write comment and keywords to xmp, sidecars are used if exist
nadvornik
parents:
138
diff
changeset
|
280 } |
0584cb78aa14
write comment and keywords to xmp, sidecars are used if exist
nadvornik
parents:
138
diff
changeset
|
281 |
0584cb78aa14
write comment and keywords to xmp, sidecars are used if exist
nadvornik
parents:
138
diff
changeset
|
282 if (!item && comment && comment[0]) item = exif_add_item(exif, comment_key); |
0584cb78aa14
write comment and keywords to xmp, sidecars are used if exist
nadvornik
parents:
138
diff
changeset
|
283 if (item) exif_item_set_string(item, comment); |
0584cb78aa14
write comment and keywords to xmp, sidecars are used if exist
nadvornik
parents:
138
diff
changeset
|
284 |
0584cb78aa14
write comment and keywords to xmp, sidecars are used if exist
nadvornik
parents:
138
diff
changeset
|
285 |
0584cb78aa14
write comment and keywords to xmp, sidecars are used if exist
nadvornik
parents:
138
diff
changeset
|
286 |
0584cb78aa14
write comment and keywords to xmp, sidecars are used if exist
nadvornik
parents:
138
diff
changeset
|
287 while ((item = exif_get_item(exif, keyword_key))) |
0584cb78aa14
write comment and keywords to xmp, sidecars are used if exist
nadvornik
parents:
138
diff
changeset
|
288 { |
0584cb78aa14
write comment and keywords to xmp, sidecars are used if exist
nadvornik
parents:
138
diff
changeset
|
289 exif_item_delete(exif, item); |
0584cb78aa14
write comment and keywords to xmp, sidecars are used if exist
nadvornik
parents:
138
diff
changeset
|
290 } |
0584cb78aa14
write comment and keywords to xmp, sidecars are used if exist
nadvornik
parents:
138
diff
changeset
|
291 |
0584cb78aa14
write comment and keywords to xmp, sidecars are used if exist
nadvornik
parents:
138
diff
changeset
|
292 if (work) |
0584cb78aa14
write comment and keywords to xmp, sidecars are used if exist
nadvornik
parents:
138
diff
changeset
|
293 { |
0584cb78aa14
write comment and keywords to xmp, sidecars are used if exist
nadvornik
parents:
138
diff
changeset
|
294 item = exif_add_item(exif, keyword_key); |
0584cb78aa14
write comment and keywords to xmp, sidecars are used if exist
nadvornik
parents:
138
diff
changeset
|
295 |
0584cb78aa14
write comment and keywords to xmp, sidecars are used if exist
nadvornik
parents:
138
diff
changeset
|
296 while (work) |
0584cb78aa14
write comment and keywords to xmp, sidecars are used if exist
nadvornik
parents:
138
diff
changeset
|
297 { |
0584cb78aa14
write comment and keywords to xmp, sidecars are used if exist
nadvornik
parents:
138
diff
changeset
|
298 gchar *kw = (gchar *) work->data; |
0584cb78aa14
write comment and keywords to xmp, sidecars are used if exist
nadvornik
parents:
138
diff
changeset
|
299 work = work->next; |
0584cb78aa14
write comment and keywords to xmp, sidecars are used if exist
nadvornik
parents:
138
diff
changeset
|
300 |
0584cb78aa14
write comment and keywords to xmp, sidecars are used if exist
nadvornik
parents:
138
diff
changeset
|
301 exif_item_set_string(item, kw); |
0584cb78aa14
write comment and keywords to xmp, sidecars are used if exist
nadvornik
parents:
138
diff
changeset
|
302 } |
0584cb78aa14
write comment and keywords to xmp, sidecars are used if exist
nadvornik
parents:
138
diff
changeset
|
303 } |
0584cb78aa14
write comment and keywords to xmp, sidecars are used if exist
nadvornik
parents:
138
diff
changeset
|
304 |
0584cb78aa14
write comment and keywords to xmp, sidecars are used if exist
nadvornik
parents:
138
diff
changeset
|
305 success = exif_write(exif); |
0584cb78aa14
write comment and keywords to xmp, sidecars are used if exist
nadvornik
parents:
138
diff
changeset
|
306 |
0584cb78aa14
write comment and keywords to xmp, sidecars are used if exist
nadvornik
parents:
138
diff
changeset
|
307 exif_free(exif); |
0584cb78aa14
write comment and keywords to xmp, sidecars are used if exist
nadvornik
parents:
138
diff
changeset
|
308 |
0584cb78aa14
write comment and keywords to xmp, sidecars are used if exist
nadvornik
parents:
138
diff
changeset
|
309 return success; |
0584cb78aa14
write comment and keywords to xmp, sidecars are used if exist
nadvornik
parents:
138
diff
changeset
|
310 } |
0584cb78aa14
write comment and keywords to xmp, sidecars are used if exist
nadvornik
parents:
138
diff
changeset
|
311 |
0584cb78aa14
write comment and keywords to xmp, sidecars are used if exist
nadvornik
parents:
138
diff
changeset
|
312 gint comment_write(FileData *fd, GList *keywords, const gchar *comment) |
0584cb78aa14
write comment and keywords to xmp, sidecars are used if exist
nadvornik
parents:
138
diff
changeset
|
313 { |
204 | 314 if (!fd) return FALSE; |
315 | |
316 if (enable_metadata_dirs && /* FIXME - use dedicated option */ | |
317 comment_xmp_write(fd, keywords, comment)) | |
318 { | |
319 comment_delete_legacy(fd); | |
320 return TRUE; | |
321 } | |
188
0584cb78aa14
write comment and keywords to xmp, sidecars are used if exist
nadvornik
parents:
138
diff
changeset
|
322 |
0584cb78aa14
write comment and keywords to xmp, sidecars are used if exist
nadvornik
parents:
138
diff
changeset
|
323 return comment_legacy_write(fd, keywords, comment); |
0584cb78aa14
write comment and keywords to xmp, sidecars are used if exist
nadvornik
parents:
138
diff
changeset
|
324 } |
0584cb78aa14
write comment and keywords to xmp, sidecars are used if exist
nadvornik
parents:
138
diff
changeset
|
325 |
0584cb78aa14
write comment and keywords to xmp, sidecars are used if exist
nadvornik
parents:
138
diff
changeset
|
326 gint comment_read(FileData *fd, GList **keywords, gchar **comment) |
0584cb78aa14
write comment and keywords to xmp, sidecars are used if exist
nadvornik
parents:
138
diff
changeset
|
327 { |
253 | 328 GList *keywords1 = NULL; |
329 GList *keywords2 = NULL; | |
330 gchar *comment1 = NULL; | |
331 gchar *comment2 = NULL; | |
204 | 332 gint res1, res2; |
333 | |
334 if (!fd) return FALSE; | |
188
0584cb78aa14
write comment and keywords to xmp, sidecars are used if exist
nadvornik
parents:
138
diff
changeset
|
335 |
204 | 336 res1 = comment_xmp_read(fd, &keywords1, &comment1); |
337 res2 = comment_legacy_read(fd, &keywords2, &comment2); | |
338 | |
339 if (!res1 && !res2) | |
340 { | |
341 return FALSE; | |
342 } | |
343 | |
344 if (keywords) | |
345 { | |
346 if (res1 && res2) | |
347 *keywords = g_list_concat(keywords1, keywords2); | |
348 else | |
349 *keywords = res1 ? keywords1 : keywords2; | |
350 } | |
351 else | |
352 { | |
353 if (res1) string_list_free(keywords1); | |
354 if (res2) string_list_free(keywords2); | |
355 } | |
356 | |
357 | |
358 if (comment) | |
359 { | |
360 if (res1 && res2 && comment1 && comment2 && comment1[0] && comment2[0]) | |
361 *comment = g_strdup_printf("%s\n%s", comment1, comment2); | |
362 else | |
363 *comment = res1 ? comment1 : comment2; | |
364 } | |
365 if (res1 && (!comment || *comment != comment1)) g_free(comment1); | |
366 if (res2 && (!comment || *comment != comment2)) g_free(comment2); | |
367 | |
368 return TRUE; | |
188
0584cb78aa14
write comment and keywords to xmp, sidecars are used if exist
nadvornik
parents:
138
diff
changeset
|
369 } |
0584cb78aa14
write comment and keywords to xmp, sidecars are used if exist
nadvornik
parents:
138
diff
changeset
|
370 |
0584cb78aa14
write comment and keywords to xmp, sidecars are used if exist
nadvornik
parents:
138
diff
changeset
|
371 |
9 | 372 static gchar *comment_pull(GtkWidget *textview) |
373 { | |
374 GtkTextBuffer *buffer; | |
375 GtkTextIter start, end; | |
376 | |
377 buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(textview)); | |
378 gtk_text_buffer_get_bounds(buffer, &start, &end); | |
379 | |
380 return gtk_text_buffer_get_text(buffer, &start, &end, FALSE); | |
381 } | |
382 | |
383 GList *keyword_list_pull(GtkWidget *text_widget) | |
384 { | |
385 GList *list = NULL; | |
386 gchar *text; | |
387 gchar *ptr; | |
388 | |
389 if (GTK_IS_TEXT_VIEW(text_widget)) | |
390 { | |
391 text = comment_pull(text_widget); | |
392 } | |
393 else if (GTK_IS_ENTRY(text_widget)) | |
394 { | |
395 text = g_strdup(gtk_entry_get_text(GTK_ENTRY(text_widget))); | |
396 } | |
397 else | |
398 { | |
399 return NULL; | |
400 } | |
401 | |
402 ptr = text; | |
403 while (*ptr != '\0') | |
404 { | |
405 gchar *begin; | |
406 gint l = 0; | |
407 | |
408 while (*ptr == ' ' || *ptr == ',' || *ptr == '\n' || *ptr == '\r' || *ptr == '\b') ptr++; | |
409 begin = ptr; | |
410 if (*ptr != '\0') | |
411 { | |
412 while (*ptr != ' ' && *ptr != ',' && | |
413 *ptr != '\n' && *ptr != '\r' && *ptr != '\b' && | |
414 *ptr != '\0') | |
415 { | |
416 ptr++; | |
417 l++; | |
418 } | |
419 } | |
420 | |
421 if (l > 0) list = g_list_append(list, g_strndup(begin, l)); | |
422 } | |
423 | |
424 g_free(text); | |
425 | |
426 return list; | |
427 } | |
428 | |
429 void keyword_list_push(GtkWidget *textview, GList *list) | |
430 { | |
431 GtkTextBuffer *buffer; | |
432 GtkTextIter start, end; | |
433 | |
434 buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(textview)); | |
435 gtk_text_buffer_get_bounds(buffer, &start, &end); | |
436 gtk_text_buffer_delete (buffer, &start, &end); | |
437 | |
438 while (list) | |
439 { | |
440 const gchar *word = list->data; | |
441 GtkTextIter iter; | |
442 | |
443 gtk_text_buffer_get_end_iter(buffer, &iter); | |
444 if (word) gtk_text_buffer_insert(buffer, &iter, word, -1); | |
445 gtk_text_buffer_get_end_iter(buffer, &iter); | |
446 gtk_text_buffer_insert(buffer, &iter, "\n", -1); | |
447 | |
448 list = list->next; | |
449 } | |
450 } | |
451 | |
138 | 452 static void metadata_set_keywords(FileData *fd, GList *list, gint add) |
9 | 453 { |
454 gchar *comment = NULL; | |
455 GList *keywords = NULL; | |
456 GList *save_list = NULL; | |
457 | |
188
0584cb78aa14
write comment and keywords to xmp, sidecars are used if exist
nadvornik
parents:
138
diff
changeset
|
458 comment_read(fd, &keywords, &comment); |
9 | 459 |
460 if (add) | |
461 { | |
462 GList *work; | |
463 | |
464 work = list; | |
465 while (work) | |
466 { | |
467 gchar *key; | |
468 GList *p; | |
469 | |
470 key = work->data; | |
471 work = work->next; | |
472 | |
473 p = keywords; | |
474 while (p && key) | |
475 { | |
476 gchar *needle = p->data; | |
477 p = p->next; | |
478 | |
479 if (strcmp(needle, key) == 0) key = NULL; | |
480 } | |
481 | |
482 if (key) keywords = g_list_append(keywords, g_strdup(key)); | |
483 } | |
484 save_list = keywords; | |
485 } | |
486 else | |
487 { | |
488 save_list = list; | |
489 } | |
490 | |
188
0584cb78aa14
write comment and keywords to xmp, sidecars are used if exist
nadvornik
parents:
138
diff
changeset
|
491 comment_write(fd, save_list, comment); |
9 | 492 |
138 | 493 string_list_free(keywords); |
9 | 494 g_free(comment); |
495 } | |
496 | |
497 /* | |
498 *------------------------------------------------------------------- | |
499 * keyword list dialog | |
500 *------------------------------------------------------------------- | |
501 */ | |
502 | |
503 #define KEYWORD_DIALOG_WIDTH 200 | |
504 #define KEYWORD_DIALOG_HEIGHT 250 | |
505 | |
506 typedef struct _KeywordDlg KeywordDlg; | |
507 struct _KeywordDlg | |
508 { | |
509 GenericDialog *gd; | |
510 GtkWidget *treeview; | |
511 }; | |
512 | |
513 static KeywordDlg *keyword_dialog = NULL; | |
514 | |
515 | |
516 static void keyword_dialog_cancel_cb(GenericDialog *gd, gpointer data) | |
517 { | |
518 g_free(keyword_dialog); | |
519 keyword_dialog = NULL; | |
520 } | |
521 | |
522 static void keyword_dialog_ok_cb(GenericDialog *gd, gpointer data) | |
523 { | |
524 KeywordDlg *kd = data; | |
525 GtkTreeModel *store; | |
526 GtkTreeIter iter; | |
527 gint valid; | |
528 | |
529 history_list_free_key("keywords"); | |
530 | |
531 store = gtk_tree_view_get_model(GTK_TREE_VIEW(kd->treeview)); | |
532 valid = gtk_tree_model_get_iter_first(store, &iter); | |
533 while (valid) | |
534 { | |
535 gchar *key; | |
536 | |
537 gtk_tree_model_get(store, &iter, 0, &key, -1); | |
538 valid = gtk_tree_model_iter_next(store, &iter); | |
539 | |
540 history_list_add_to_key("keywords", key, 0); | |
541 } | |
542 | |
543 keyword_dialog_cancel_cb(gd, data); | |
544 | |
545 bar_info_keyword_update_all(); | |
546 } | |
547 | |
548 static void keyword_dialog_add_cb(GtkWidget *button, gpointer data) | |
549 { | |
550 KeywordDlg *kd = data; | |
551 GtkTreeSelection *selection; | |
552 GtkTreeModel *store; | |
553 GtkTreeIter sibling; | |
554 GtkTreeIter iter; | |
555 GtkTreePath *tpath; | |
556 | |
557 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(kd->treeview)); | |
558 if (gtk_tree_selection_get_selected(selection, &store, &sibling)) | |
559 { | |
560 gtk_list_store_insert_before(GTK_LIST_STORE(store), &iter, &sibling); | |
561 } | |
562 else | |
563 { | |
564 store = gtk_tree_view_get_model(GTK_TREE_VIEW(kd->treeview)); | |
565 gtk_list_store_append(GTK_LIST_STORE(store), &iter); | |
566 } | |
567 | |
568 gtk_list_store_set(GTK_LIST_STORE(store), &iter, 1, TRUE, -1); | |
569 | |
570 tpath = gtk_tree_model_get_path(store, &iter); | |
571 gtk_tree_view_set_cursor(GTK_TREE_VIEW(kd->treeview), tpath, | |
572 gtk_tree_view_get_column(GTK_TREE_VIEW(kd->treeview), 0), TRUE); | |
573 gtk_tree_path_free(tpath); | |
574 } | |
575 | |
576 static void keyword_dialog_remove_cb(GtkWidget *button, gpointer data) | |
577 { | |
578 KeywordDlg *kd = data; | |
579 GtkTreeSelection *selection; | |
580 GtkTreeModel *store; | |
581 GtkTreeIter iter; | |
582 GtkTreeIter next; | |
583 GtkTreePath *tpath; | |
584 | |
585 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(kd->treeview)); | |
586 if (!gtk_tree_selection_get_selected(selection, &store, &iter)) return; | |
587 | |
588 tpath = NULL; | |
589 next = iter; | |
590 if (gtk_tree_model_iter_next(store, &next)) | |
591 { | |
592 tpath = gtk_tree_model_get_path(store, &next); | |
593 } | |
594 else | |
595 { | |
596 tpath = gtk_tree_model_get_path(store, &iter); | |
597 if (!gtk_tree_path_prev(tpath)) | |
598 { | |
599 gtk_tree_path_free(tpath); | |
600 tpath = NULL; | |
601 } | |
602 } | |
603 if (tpath) | |
604 { | |
605 gtk_tree_view_set_cursor(GTK_TREE_VIEW(kd->treeview), tpath, | |
606 gtk_tree_view_get_column(GTK_TREE_VIEW(kd->treeview), 0), FALSE); | |
607 gtk_tree_path_free(tpath); | |
608 } | |
609 | |
610 gtk_list_store_remove(GTK_LIST_STORE(store), &iter); | |
611 } | |
612 | |
613 static void keyword_dialog_edit_cb(GtkCellRendererText *renderer, const gchar *path, | |
614 const gchar *new_text, gpointer data) | |
615 { | |
616 KeywordDlg *kd = data; | |
617 GtkTreeModel *store; | |
618 GtkTreeIter iter; | |
619 GtkTreePath *tpath; | |
620 | |
621 if (!new_text || strlen(new_text) == 0) return; | |
622 | |
623 store = gtk_tree_view_get_model(GTK_TREE_VIEW(kd->treeview)); | |
624 | |
625 tpath = gtk_tree_path_new_from_string(path); | |
626 gtk_tree_model_get_iter(store, &iter, tpath); | |
627 gtk_tree_path_free(tpath); | |
628 | |
629 gtk_list_store_set(GTK_LIST_STORE(store), &iter, 0, new_text, -1); | |
630 } | |
631 | |
632 static void keyword_dialog_populate(KeywordDlg *kd) | |
633 { | |
634 GtkListStore *store; | |
635 GList *list; | |
636 | |
637 store = GTK_LIST_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(kd->treeview))); | |
638 gtk_list_store_clear(store); | |
639 | |
640 list = history_list_get_by_key("keywords"); | |
641 list = g_list_last(list); | |
642 while (list) | |
643 { | |
644 GtkTreeIter iter; | |
645 | |
646 gtk_list_store_append(store, &iter); | |
647 gtk_list_store_set(store, &iter, 0, list->data, | |
648 1, TRUE, -1); | |
649 | |
650 list = list->prev; | |
651 } | |
652 } | |
653 | |
654 static void keyword_dialog_show(void) | |
655 { | |
656 GtkWidget *scrolled; | |
657 GtkListStore *store; | |
658 GtkTreeViewColumn *column; | |
659 GtkCellRenderer *renderer; | |
660 GtkWidget *hbox; | |
661 GtkWidget *button; | |
662 | |
663 if (keyword_dialog) | |
664 { | |
665 gtk_window_present(GTK_WINDOW(keyword_dialog->gd->dialog)); | |
666 return; | |
667 } | |
668 | |
669 keyword_dialog = g_new0(KeywordDlg, 1); | |
670 | |
671 keyword_dialog->gd = generic_dialog_new(_("Keyword Presets"), | |
254
9faf34f047b1
Make the wmclass value unique among the code by defining
zas_
parents:
253
diff
changeset
|
672 GQ_WMCLASS, "keyword_presets", NULL, TRUE, |
9 | 673 keyword_dialog_cancel_cb, keyword_dialog); |
674 generic_dialog_add_message(keyword_dialog->gd, NULL, _("Favorite keywords list"), NULL); | |
675 | |
676 generic_dialog_add_button(keyword_dialog->gd, GTK_STOCK_OK, NULL, | |
677 keyword_dialog_ok_cb, TRUE); | |
678 | |
679 scrolled = gtk_scrolled_window_new(NULL, NULL); | |
680 gtk_widget_set_size_request(scrolled, KEYWORD_DIALOG_WIDTH, KEYWORD_DIALOG_HEIGHT); | |
681 gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scrolled), GTK_SHADOW_IN); | |
682 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled), | |
683 GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); | |
684 gtk_box_pack_start(GTK_BOX(keyword_dialog->gd->vbox), scrolled, TRUE, TRUE, 5); | |
685 gtk_widget_show(scrolled); | |
686 | |
687 store = gtk_list_store_new(2, G_TYPE_STRING, G_TYPE_BOOLEAN); | |
688 keyword_dialog->treeview = gtk_tree_view_new_with_model(GTK_TREE_MODEL(store)); | |
689 g_object_unref(store); | |
690 | |
691 gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(keyword_dialog->treeview), FALSE); | |
692 gtk_tree_view_set_search_column(GTK_TREE_VIEW(keyword_dialog->treeview), 0); | |
693 gtk_tree_view_set_reorderable(GTK_TREE_VIEW(keyword_dialog->treeview), TRUE); | |
694 | |
695 column = gtk_tree_view_column_new(); | |
696 gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_AUTOSIZE); | |
697 renderer = gtk_cell_renderer_text_new(); | |
698 g_signal_connect(G_OBJECT(renderer), "edited", | |
699 G_CALLBACK(keyword_dialog_edit_cb), keyword_dialog); | |
700 gtk_tree_view_column_pack_start(column, renderer, TRUE); | |
701 gtk_tree_view_column_add_attribute(column, renderer, "text", 0); | |
702 gtk_tree_view_column_add_attribute(column, renderer, "editable", 1); | |
703 gtk_tree_view_append_column(GTK_TREE_VIEW(keyword_dialog->treeview), column); | |
704 | |
705 gtk_container_add(GTK_CONTAINER(scrolled), keyword_dialog->treeview); | |
706 gtk_widget_show(keyword_dialog->treeview); | |
707 | |
708 hbox = gtk_hbox_new(FALSE, 5); | |
709 gtk_box_pack_start(GTK_BOX(keyword_dialog->gd->vbox), hbox, FALSE, FALSE, 0); | |
710 gtk_widget_show(hbox); | |
711 | |
712 button = gtk_button_new_from_stock(GTK_STOCK_ADD); | |
713 g_signal_connect(G_OBJECT(button), "clicked", | |
714 G_CALLBACK(keyword_dialog_add_cb), keyword_dialog); | |
715 gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 0); | |
716 gtk_widget_show(button); | |
717 | |
718 button = gtk_button_new_from_stock(GTK_STOCK_REMOVE); | |
719 g_signal_connect(G_OBJECT(button), "clicked", | |
720 G_CALLBACK(keyword_dialog_remove_cb), keyword_dialog); | |
721 gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 0); | |
722 gtk_widget_show(button); | |
723 | |
724 keyword_dialog_populate(keyword_dialog); | |
725 | |
726 gtk_widget_show(keyword_dialog->gd->dialog); | |
727 } | |
728 | |
729 | |
730 static void bar_keyword_edit_cb(GtkWidget *button, gpointer data) | |
731 { | |
732 keyword_dialog_show(); | |
733 } | |
734 | |
735 | |
736 /* | |
737 *------------------------------------------------------------------- | |
738 * info bar | |
739 *------------------------------------------------------------------- | |
740 */ | |
741 | |
742 typedef enum { | |
743 BAR_SORT_COPY, | |
744 BAR_SORT_MOVE, | |
745 BAR_SORT_LINK | |
746 } SortActionType; | |
747 | |
748 enum { | |
749 KEYWORD_COLUMN_TOGGLE = 0, | |
750 KEYWORD_COLUMN_TEXT | |
751 }; | |
752 | |
753 typedef struct _BarInfoData BarInfoData; | |
754 struct _BarInfoData | |
755 { | |
756 GtkWidget *vbox; | |
757 GtkWidget *group_box; | |
758 GtkWidget *label_file_name; | |
759 GtkWidget *label_file_time; | |
760 | |
761 GtkWidget *keyword_view; | |
762 GtkWidget *keyword_treeview; | |
763 | |
764 GtkWidget *comment_view; | |
765 | |
766 GtkWidget *button_save; | |
767 GtkWidget *button_set_add; | |
768 GtkWidget *button_set_replace; | |
769 | |
138 | 770 FileData *fd; |
9 | 771 |
772 gint changed; | |
773 gint save_timeout_id; | |
774 | |
775 GList *(*list_func)(gpointer); | |
776 gpointer list_data; | |
777 }; | |
778 | |
779 | |
780 static GList *bar_list = NULL; | |
781 | |
782 | |
783 static void bar_info_write(BarInfoData *bd) | |
784 { | |
785 GList *list; | |
786 gchar *comment; | |
787 | |
138 | 788 if (!bd->fd) return; |
9 | 789 |
790 list = keyword_list_pull(bd->keyword_view); | |
791 comment = comment_pull(bd->comment_view); | |
792 | |
188
0584cb78aa14
write comment and keywords to xmp, sidecars are used if exist
nadvornik
parents:
138
diff
changeset
|
793 comment_write(bd->fd, list, comment); |
9 | 794 |
138 | 795 string_list_free(list); |
9 | 796 g_free(comment); |
797 | |
798 bd->changed = FALSE; | |
799 gtk_widget_set_sensitive(bd->button_save, FALSE); | |
800 } | |
801 | |
802 static gint bar_info_autosave(gpointer data) | |
803 { | |
804 BarInfoData *bd = data; | |
805 | |
806 bar_info_write(bd); | |
807 | |
808 bd->save_timeout_id = -1; | |
809 | |
810 return FALSE; | |
811 } | |
812 | |
813 static void bar_info_save_update(BarInfoData *bd, gint enable) | |
814 { | |
815 if (bd->save_timeout_id != -1) | |
816 { | |
817 g_source_remove(bd->save_timeout_id); | |
818 bd->save_timeout_id = -1; | |
819 } | |
820 if (enable) | |
821 { | |
822 bd->save_timeout_id = g_timeout_add(BAR_KEYWORD_AUTOSAVE_TIME, bar_info_autosave, bd); | |
823 } | |
824 } | |
825 | |
826 static gint bar_keyword_list_find(GList *list, const gchar *keyword) | |
827 { | |
828 while (list) | |
829 { | |
830 gchar *haystack = list->data; | |
831 | |
832 if (haystack && keyword && strcmp(haystack, keyword) == 0) return TRUE; | |
833 | |
834 list = list->next; | |
835 } | |
836 | |
837 return FALSE; | |
838 } | |
839 | |
840 static void bar_keyword_list_sync(BarInfoData *bd, GList *keywords) | |
841 { | |
842 GList *list; | |
843 GtkListStore *store; | |
844 GtkTreeIter iter; | |
845 | |
846 list = history_list_get_by_key("keywords"); | |
847 if (!list) | |
848 { | |
849 /* blank? set up a few example defaults */ | |
850 | |
851 gint i = 0; | |
852 | |
853 while (keyword_favorite_defaults[i] != NULL) | |
854 { | |
855 history_list_add_to_key("keywords", _(keyword_favorite_defaults[i]), 0); | |
856 i++; | |
857 } | |
858 | |
859 list = history_list_get_by_key("keywords"); | |
860 } | |
861 | |
862 store = GTK_LIST_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(bd->keyword_treeview))); | |
863 | |
864 gtk_list_store_clear(store); | |
865 | |
866 list = g_list_last(list); | |
867 while (list) | |
868 { | |
869 gchar *key = list->data; | |
870 | |
871 gtk_list_store_append(store, &iter); | |
872 gtk_list_store_set(store, &iter, KEYWORD_COLUMN_TOGGLE, bar_keyword_list_find(keywords, key), | |
873 KEYWORD_COLUMN_TEXT, key, -1); | |
874 | |
875 list = list->prev; | |
876 } | |
877 } | |
878 | |
879 static void bar_info_keyword_update_all(void) | |
880 { | |
881 GList *work; | |
882 | |
883 work = bar_list; | |
884 while (work) | |
885 { | |
886 BarInfoData *bd; | |
887 GList *keywords; | |
888 | |
889 bd = work->data; | |
890 work = work->next; | |
891 | |
892 keywords = keyword_list_pull(bd->keyword_view); | |
893 bar_keyword_list_sync(bd, keywords); | |
138 | 894 string_list_free(keywords); |
9 | 895 } |
896 } | |
897 | |
898 static void bar_info_update(BarInfoData *bd) | |
899 { | |
900 GList *keywords = NULL; | |
901 gchar *comment = NULL; | |
902 | |
903 if (bd->label_file_name) | |
904 { | |
138 | 905 gtk_label_set_text(GTK_LABEL(bd->label_file_name), (bd->fd) ? bd->fd->name : ""); |
9 | 906 } |
907 if (bd->label_file_time) | |
908 { | |
138 | 909 gtk_label_set_text(GTK_LABEL(bd->label_file_time), (bd->fd) ? text_from_time(bd->fd->date) : ""); |
9 | 910 } |
911 | |
188
0584cb78aa14
write comment and keywords to xmp, sidecars are used if exist
nadvornik
parents:
138
diff
changeset
|
912 if (comment_read(bd->fd, &keywords, &comment)) |
9 | 913 { |
914 keyword_list_push(bd->keyword_view, keywords); | |
915 gtk_text_buffer_set_text(gtk_text_view_get_buffer(GTK_TEXT_VIEW(bd->comment_view)), | |
916 (comment) ? comment : "", -1); | |
917 | |
918 bar_keyword_list_sync(bd, keywords); | |
919 | |
138 | 920 string_list_free(keywords); |
9 | 921 g_free(comment); |
922 } | |
923 else | |
924 { | |
925 gtk_text_buffer_set_text(gtk_text_view_get_buffer(GTK_TEXT_VIEW(bd->keyword_view)), "", -1); | |
926 gtk_text_buffer_set_text(gtk_text_view_get_buffer(GTK_TEXT_VIEW(bd->comment_view)), "", -1); | |
927 | |
928 bar_keyword_list_sync(bd, NULL); | |
929 } | |
930 | |
931 bar_info_save_update(bd, FALSE); | |
932 bd->changed = FALSE; | |
933 gtk_widget_set_sensitive(bd->button_save, FALSE); | |
934 | |
138 | 935 gtk_widget_set_sensitive(bd->group_box, (bd->fd != NULL)); |
9 | 936 } |
937 | |
138 | 938 void bar_info_set(GtkWidget *bar, FileData *fd) |
9 | 939 { |
940 BarInfoData *bd; | |
941 | |
942 bd = g_object_get_data(G_OBJECT(bar), "bar_info_data"); | |
943 if (!bd) return; | |
944 | |
945 if (bd->changed) bar_info_write(bd); | |
946 | |
138 | 947 file_data_unref(bd->fd); |
948 bd->fd = file_data_ref(fd); | |
9 | 949 |
950 bar_info_update(bd); | |
951 } | |
952 | |
138 | 953 void bar_info_maint_renamed(GtkWidget *bar, FileData *fd) |
9 | 954 { |
955 BarInfoData *bd; | |
956 | |
957 bd = g_object_get_data(G_OBJECT(bar), "bar_info_data"); | |
958 if (!bd) return; | |
959 | |
138 | 960 file_data_unref(bd->fd); |
961 bd->fd = file_data_ref(fd); | |
9 | 962 |
963 if (bd->label_file_name) | |
964 { | |
138 | 965 gtk_label_set_text(GTK_LABEL(bd->label_file_name), (bd->fd) ? bd->fd->name : ""); |
9 | 966 } |
967 } | |
968 | |
969 gint bar_info_event(GtkWidget *bar, GdkEvent *event) | |
970 { | |
971 BarInfoData *bd; | |
972 | |
973 bd = g_object_get_data(G_OBJECT(bar), "bar_info_data"); | |
974 if (!bd) return FALSE; | |
975 | |
976 if (GTK_WIDGET_HAS_FOCUS(bd->keyword_view)) return gtk_widget_event(bd->keyword_view, event); | |
977 if (GTK_WIDGET_HAS_FOCUS(bd->comment_view)) return gtk_widget_event(bd->comment_view, event); | |
978 | |
979 return FALSE; | |
980 } | |
981 | |
982 static void bar_info_keyword_set(BarInfoData *bd, const gchar *keyword, gint active) | |
983 { | |
984 GList *list; | |
985 gint found; | |
986 | |
987 if (!keyword) return; | |
988 | |
989 list = keyword_list_pull(bd->keyword_view); | |
990 found = bar_keyword_list_find(list, keyword); | |
991 | |
992 if (active != found) | |
993 { | |
994 if (found) | |
995 { | |
996 GList *work = list; | |
997 | |
998 while (work) | |
999 { | |
1000 gchar *key = work->data; | |
1001 work = work->next; | |
1002 | |
1003 if (key && keyword && strcmp(key, keyword) == 0) | |
1004 { | |
1005 list = g_list_remove(list, key); | |
1006 g_free(key); | |
1007 } | |
1008 } | |
1009 } | |
1010 else | |
1011 { | |
1012 list = g_list_append(list, g_strdup(keyword)); | |
1013 } | |
1014 | |
1015 keyword_list_push(bd->keyword_view, list); | |
1016 } | |
1017 | |
138 | 1018 string_list_free(list); |
9 | 1019 } |
1020 | |
1021 static void bar_info_keyword_toggle(GtkCellRendererToggle *toggle, const gchar *path, gpointer data) | |
1022 { | |
1023 BarInfoData *bd = data; | |
1024 GtkTreeModel *store; | |
1025 GtkTreeIter iter; | |
1026 GtkTreePath *tpath; | |
1027 gchar *key = NULL; | |
1028 gboolean active; | |
1029 | |
1030 store = gtk_tree_view_get_model(GTK_TREE_VIEW(bd->keyword_treeview)); | |
1031 | |
1032 tpath = gtk_tree_path_new_from_string(path); | |
1033 gtk_tree_model_get_iter(store, &iter, tpath); | |
1034 gtk_tree_path_free(tpath); | |
1035 | |
1036 gtk_tree_model_get(store, &iter, KEYWORD_COLUMN_TOGGLE, &active, | |
1037 KEYWORD_COLUMN_TEXT, &key, -1); | |
1038 active = (!active); | |
1039 gtk_list_store_set(GTK_LIST_STORE(store), &iter, KEYWORD_COLUMN_TOGGLE, active, -1); | |
1040 | |
1041 bar_info_keyword_set(bd, key, active); | |
1042 g_free(key); | |
1043 } | |
1044 | |
1045 static void bar_info_save(GtkWidget *button, gpointer data) | |
1046 { | |
1047 BarInfoData *bd = data; | |
1048 | |
1049 bar_info_save_update(bd, FALSE); | |
1050 bar_info_write(bd); | |
1051 } | |
1052 | |
1053 static void bar_info_set_selection(BarInfoData *bd, gint add) | |
1054 { | |
1055 GList *keywords; | |
1056 GList *list = NULL; | |
1057 GList *work; | |
1058 | |
1059 if (!bd->list_func) return; | |
1060 | |
1061 keywords = keyword_list_pull(bd->keyword_view); | |
1062 if (!keywords && add) return; | |
1063 | |
1064 list = bd->list_func(bd->list_data); | |
1065 work = list; | |
1066 while (work) | |
1067 { | |
138 | 1068 FileData *fd = work->data; |
9 | 1069 work = work->next; |
1070 | |
138 | 1071 metadata_set_keywords(fd, keywords, add); |
9 | 1072 } |
1073 | |
138 | 1074 filelist_free(list); |
1075 string_list_free(keywords); | |
9 | 1076 } |
1077 | |
1078 static void bar_info_set_add(GtkWidget *button, gpointer data) | |
1079 { | |
1080 BarInfoData *bd = data; | |
1081 | |
1082 bar_info_set_selection(bd, TRUE); | |
1083 } | |
1084 | |
1085 static void bar_info_set_replace(GtkWidget *button, gpointer data) | |
1086 { | |
1087 BarInfoData *bd = data; | |
1088 | |
1089 bar_info_set_selection(bd, FALSE); | |
1090 } | |
1091 | |
1092 static void bar_info_changed(GtkTextBuffer *buffer, gpointer data) | |
1093 { | |
1094 BarInfoData *bd = data; | |
1095 | |
1096 bd->changed = TRUE; | |
1097 gtk_widget_set_sensitive(bd->button_save, TRUE); | |
1098 | |
1099 bar_info_save_update(bd, TRUE); | |
1100 } | |
1101 | |
1102 void bar_info_close(GtkWidget *bar) | |
1103 { | |
1104 BarInfoData *bd; | |
1105 | |
1106 bd = g_object_get_data(G_OBJECT(bar), "bar_info_data"); | |
1107 if (!bd) return; | |
1108 | |
1109 gtk_widget_destroy(bd->vbox); | |
1110 } | |
1111 | |
1112 static void bar_info_destroy(GtkWidget *widget, gpointer data) | |
1113 { | |
1114 BarInfoData *bd = data; | |
1115 | |
1116 if (bd->changed) bar_info_write(bd); | |
1117 bar_info_save_update(bd, FALSE); | |
1118 | |
1119 bar_list = g_list_remove(bar_list, bd); | |
1120 | |
138 | 1121 file_data_unref(bd->fd); |
9 | 1122 |
1123 g_free(bd); | |
1124 } | |
1125 | |
138 | 1126 GtkWidget *bar_info_new(FileData *fd, gint metadata_only, GtkWidget *bounding_widget) |
9 | 1127 { |
1128 BarInfoData *bd; | |
1129 GtkWidget *box; | |
1130 GtkWidget *hbox; | |
1131 GtkWidget *table; | |
1132 GtkWidget *scrolled; | |
1133 GtkTextBuffer *buffer; | |
1134 GtkWidget *label; | |
1135 GtkWidget *tbar; | |
1136 GtkListStore *store; | |
1137 GtkTreeViewColumn *column; | |
1138 GtkCellRenderer *renderer; | |
1139 | |
1140 bd = g_new0(BarInfoData, 1); | |
1141 | |
1142 bd->list_func = NULL; | |
1143 bd->list_data = NULL; | |
1144 | |
1145 bd->vbox = gtk_vbox_new(FALSE, PREF_PAD_GAP); | |
1146 g_object_set_data(G_OBJECT(bd->vbox), "bar_info_data", bd); | |
1147 g_signal_connect(G_OBJECT(bd->vbox), "destroy", | |
1148 G_CALLBACK(bar_info_destroy), bd); | |
1149 | |
1150 if (!metadata_only) | |
1151 { | |
1152 hbox = pref_box_new(bd->vbox, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_GAP); | |
1153 | |
1154 label = sizer_new(bd->vbox, bounding_widget, SIZER_POS_LEFT); | |
1155 gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0); | |
1156 gtk_widget_show(label); | |
1157 | |
1158 label = gtk_label_new(_("Keywords")); | |
1159 pref_label_bold(label, TRUE, FALSE); | |
1160 gtk_box_pack_start(GTK_BOX(hbox), label, TRUE, TRUE, 0); | |
1161 gtk_widget_show(label); | |
1162 } | |
1163 | |
1164 bd->group_box = pref_box_new(bd->vbox, TRUE, GTK_ORIENTATION_VERTICAL, PREF_PAD_GAP); | |
1165 | |
1166 if (!metadata_only) | |
1167 { | |
1168 GtkWidget *table; | |
1169 | |
1170 table = pref_table_new(bd->group_box, 2, 2, FALSE, FALSE); | |
1171 | |
1172 bd->label_file_name = table_add_line(table, 0, 0, _("Filename:"), NULL); | |
1173 bd->label_file_time = table_add_line(table, 0, 1, _("File date:"), NULL); | |
1174 } | |
1175 else | |
1176 { | |
1177 bd->label_file_name = NULL; | |
1178 bd->label_file_time = NULL; | |
1179 } | |
1180 | |
1181 table = gtk_table_new(3, 1, TRUE); | |
1182 gtk_table_set_row_spacings(GTK_TABLE(table), PREF_PAD_GAP); | |
1183 gtk_box_pack_start(GTK_BOX(bd->group_box), table, TRUE, TRUE, 0); | |
1184 gtk_widget_show(table); | |
1185 | |
1186 /* keyword entry */ | |
1187 | |
1188 box = gtk_vbox_new(FALSE, 0); | |
1189 gtk_table_attach(GTK_TABLE(table), box, 0, 1, 0, 2, | |
1190 GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0); | |
1191 gtk_widget_show(box); | |
1192 | |
1193 label = pref_label_new(box, _("Keywords:")); | |
1194 gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5); | |
1195 pref_label_bold(label, TRUE, FALSE); | |
1196 | |
1197 hbox = pref_box_new(box, TRUE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_GAP); | |
1198 | |
1199 scrolled = gtk_scrolled_window_new(NULL, NULL); | |
1200 gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scrolled), GTK_SHADOW_IN); | |
1201 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled), | |
1202 GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); | |
1203 gtk_box_pack_start(GTK_BOX(hbox), scrolled, TRUE, TRUE, 0); | |
1204 gtk_widget_show(scrolled); | |
1205 | |
1206 bd->keyword_view = gtk_text_view_new(); | |
1207 gtk_container_add(GTK_CONTAINER(scrolled), bd->keyword_view); | |
1208 gtk_widget_show(bd->keyword_view); | |
1209 | |
1210 buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(bd->keyword_view)); | |
1211 g_signal_connect(G_OBJECT(buffer), "changed", | |
1212 G_CALLBACK(bar_info_changed), bd); | |
1213 | |
1214 scrolled = gtk_scrolled_window_new(NULL, NULL); | |
1215 gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scrolled), GTK_SHADOW_IN); | |
1216 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled), | |
1217 GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); | |
1218 gtk_box_pack_start(GTK_BOX(hbox), scrolled, TRUE, TRUE, 0); | |
1219 gtk_widget_show(scrolled); | |
1220 | |
1221 store = gtk_list_store_new(2, G_TYPE_BOOLEAN, G_TYPE_STRING); | |
1222 bd->keyword_treeview = gtk_tree_view_new_with_model(GTK_TREE_MODEL(store)); | |
1223 g_object_unref(store); | |
1224 | |
1225 gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(bd->keyword_treeview), FALSE); | |
1226 | |
1227 if (metadata_only) | |
1228 { | |
1229 gtk_tree_view_set_search_column(GTK_TREE_VIEW(bd->keyword_treeview), KEYWORD_COLUMN_TEXT); | |
1230 } | |
1231 else | |
1232 { | |
1233 gtk_tree_view_set_enable_search(GTK_TREE_VIEW(bd->keyword_treeview), FALSE); | |
1234 } | |
1235 | |
1236 column = gtk_tree_view_column_new(); | |
1237 gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_AUTOSIZE); | |
1238 | |
1239 renderer = gtk_cell_renderer_toggle_new(); | |
1240 gtk_tree_view_column_pack_start(column, renderer, FALSE); | |
1241 gtk_tree_view_column_add_attribute(column, renderer, "active", KEYWORD_COLUMN_TOGGLE); | |
1242 g_signal_connect(G_OBJECT(renderer), "toggled", | |
1243 G_CALLBACK(bar_info_keyword_toggle), bd); | |
1244 | |
1245 renderer = gtk_cell_renderer_text_new(); | |
1246 gtk_tree_view_column_pack_start(column, renderer, TRUE); | |
1247 gtk_tree_view_column_add_attribute(column, renderer, "text", KEYWORD_COLUMN_TEXT); | |
1248 | |
1249 gtk_tree_view_append_column(GTK_TREE_VIEW(bd->keyword_treeview), column); | |
1250 | |
1251 gtk_container_add(GTK_CONTAINER(scrolled), bd->keyword_treeview); | |
1252 gtk_widget_show(bd->keyword_treeview); | |
1253 | |
1254 /* comment entry */ | |
1255 | |
1256 box = gtk_vbox_new(FALSE, 0); | |
1257 gtk_table_attach(GTK_TABLE(table), box, 0, 1, 2, 3, | |
1258 GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0); | |
1259 gtk_widget_show(box); | |
1260 | |
1261 label = pref_label_new(box, _("Comment:")); | |
1262 gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5); | |
1263 pref_label_bold(label, TRUE, FALSE); | |
1264 | |
1265 scrolled = gtk_scrolled_window_new(NULL, NULL); | |
1266 gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scrolled), GTK_SHADOW_IN); | |
1267 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled), | |
1268 GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); | |
1269 gtk_box_pack_start(GTK_BOX(box), scrolled, TRUE, TRUE, 0); | |
1270 gtk_widget_show(scrolled); | |
1271 | |
1272 bd->comment_view = gtk_text_view_new(); | |
1273 gtk_container_add(GTK_CONTAINER(scrolled), bd->comment_view); | |
1274 gtk_widget_show(bd->comment_view); | |
1275 | |
1276 buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(bd->comment_view)); | |
1277 g_signal_connect(G_OBJECT(buffer), "changed", | |
1278 G_CALLBACK(bar_info_changed), bd); | |
1279 | |
1280 /* toolbar */ | |
1281 | |
1282 tbar = pref_toolbar_new(bd->group_box, GTK_TOOLBAR_ICONS); | |
1283 | |
41
6281cc38e5ca
Wed Apr 27 15:17:57 2005 John Ellis <johne@verizon.net>
gqview
parents:
9
diff
changeset
|
1284 pref_toolbar_button(tbar, GTK_STOCK_INDEX, NULL, FALSE, |
9 | 1285 _("Edit favorite keywords list."), |
1286 G_CALLBACK(bar_keyword_edit_cb), bd); | |
1287 pref_toolbar_spacer(tbar); | |
41
6281cc38e5ca
Wed Apr 27 15:17:57 2005 John Ellis <johne@verizon.net>
gqview
parents:
9
diff
changeset
|
1288 bd->button_set_add = pref_toolbar_button(tbar, GTK_STOCK_ADD, NULL, FALSE, |
9 | 1289 _("Add keywords to selected files"), |
1290 G_CALLBACK(bar_info_set_add), bd); | |
41
6281cc38e5ca
Wed Apr 27 15:17:57 2005 John Ellis <johne@verizon.net>
gqview
parents:
9
diff
changeset
|
1291 bd->button_set_replace = pref_toolbar_button(tbar, GTK_STOCK_CONVERT, NULL, FALSE, |
9 | 1292 _("Add keywords to selected files, replacing the existing ones."), |
1293 G_CALLBACK(bar_info_set_replace), bd); | |
1294 pref_toolbar_spacer(tbar); | |
41
6281cc38e5ca
Wed Apr 27 15:17:57 2005 John Ellis <johne@verizon.net>
gqview
parents:
9
diff
changeset
|
1295 bd->button_save = pref_toolbar_button(tbar, GTK_STOCK_SAVE, NULL, FALSE, |
9 | 1296 _("Save comment now"), |
1297 G_CALLBACK(bar_info_save), bd); | |
1298 | |
1299 bd->save_timeout_id = -1; | |
1300 | |
138 | 1301 bd->fd = file_data_ref(fd); |
9 | 1302 bar_info_update(bd); |
1303 | |
1304 bar_info_selection(bd->vbox, 0); | |
1305 | |
1306 bar_list = g_list_append(bar_list, bd); | |
1307 | |
1308 return bd->vbox; | |
1309 } | |
1310 | |
1311 void bar_info_set_selection_func(GtkWidget *bar, GList *(*list_func)(gpointer data), gpointer data) | |
1312 { | |
1313 BarInfoData *bd; | |
1314 | |
1315 bd = g_object_get_data(G_OBJECT(bar), "bar_info_data"); | |
1316 if (!bd) return; | |
1317 | |
1318 bd->list_func = list_func; | |
1319 bd->list_data = data; | |
1320 } | |
1321 | |
1322 void bar_info_selection(GtkWidget *bar, gint count) | |
1323 { | |
1324 BarInfoData *bd; | |
1325 gint enable; | |
1326 | |
1327 bd = g_object_get_data(G_OBJECT(bar), "bar_info_data"); | |
1328 if (!bd) return; | |
1329 | |
1330 enable = (count > 0 && bd->list_func != NULL); | |
1331 | |
1332 gtk_widget_set_sensitive(bd->button_set_add, enable); | |
1333 gtk_widget_set_sensitive(bd->button_set_replace, enable); | |
1334 } | |
1335 | |
1336 void bar_info_size_request(GtkWidget *bar, gint width) | |
1337 { | |
1338 BarInfoData *bd; | |
1339 | |
1340 bd = g_object_get_data(G_OBJECT(bar), "bar_info_data"); | |
1341 if (!bd) return; | |
1342 | |
1343 if (bd->label_file_name) | |
1344 { | |
1345 gtk_widget_set_size_request(bd->vbox, width, -1); | |
1346 } | |
1347 } | |
1348 |