Mercurial > geeqie
comparison src/filelist.c @ 9:d907d608745f
Sync to GQview 1.5.9 release.
########
DO NOT BASE ENHANCEMENTS OR TRANSLATION UPDATES ON CODE IN THIS CVS!
This CVS is never up to date with current development and is provided
solely for reference purposes, please use the latest official release
package when making any changes or translation updates.
########
author | gqview |
---|---|
date | Sat, 26 Feb 2005 00:13:35 +0000 |
parents | c0e337a01cb7 |
children | 3263965d5f9e |
comparison
equal
deleted
inserted
replaced
8:e0d0593d519e | 9:d907d608745f |
---|---|
1 /* | 1 /* |
2 * GQview image viewer | 2 * GQview |
3 * (C)2000 John Ellis | 3 * (C) 2004 John Ellis |
4 * | 4 * |
5 * Author: John Ellis | 5 * Author: John Ellis |
6 * | 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! | |
7 */ | 10 */ |
8 | 11 |
12 | |
9 #include "gqview.h" | 13 #include "gqview.h" |
10 | 14 #include "filelist.h" |
11 static gint filelist_click_row = -1; | 15 |
12 | 16 #include "cache.h" |
13 static void update_progressbar(gfloat val); | 17 #include "rcfile.h" |
14 | 18 #include "ui_fileops.h" |
15 static gint file_is_hidden(gchar *name); | 19 |
16 static gint file_is_in_filter(gchar *name); | |
17 static void add_to_filter(gchar *text, gint add); | |
18 | |
19 static gint sort_list_cb(void *a, void *b); | |
20 static void filelist_read(gchar *path); | |
21 | |
22 static gint file_find_closest_unaccounted(gint row, gint count, GList *ignore_list); | |
23 | |
24 static void history_menu_select_cb(GtkWidget *widget, gpointer data); | |
25 static gchar *truncate_hist_text(gchar *t, gint l); | |
26 static void filelist_set_history(gchar *path); | |
27 | 20 |
28 /* | 21 /* |
29 *----------------------------------------------------------------------------- | 22 *----------------------------------------------------------------------------- |
30 * file status information (private) | 23 * file filtering |
31 *----------------------------------------------------------------------------- | 24 *----------------------------------------------------------------------------- |
32 */ | 25 */ |
33 | 26 |
34 static void update_progressbar(gfloat val) | 27 static GList *filter_list = NULL; |
35 { | 28 static GList *extension_list = NULL; |
36 gtk_progress_bar_update (GTK_PROGRESS_BAR(info_progress_bar), val); | 29 |
37 } | 30 gint ishidden(const gchar *name) |
38 | |
39 void update_status_label(gchar *text) | |
40 { | |
41 gchar *buf; | |
42 gint count; | |
43 gchar *ss = ""; | |
44 | |
45 if (text) | |
46 { | |
47 gtk_label_set(GTK_LABEL(info_status), text); | |
48 return; | |
49 } | |
50 | |
51 if (slideshow_is_running()) ss = _(" Slideshow"); | |
52 | |
53 count = file_selection_count(); | |
54 if (count > 0) | |
55 buf = g_strdup_printf(_("%d files (%d)%s"), file_count(), count, ss); | |
56 else | |
57 buf = g_strdup_printf(_("%d files%s"), file_count(), ss); | |
58 | |
59 gtk_label_set(GTK_LABEL(info_status), buf); | |
60 g_free(buf); | |
61 } | |
62 | |
63 /* | |
64 *----------------------------------------------------------------------------- | |
65 * file filtering | |
66 *----------------------------------------------------------------------------- | |
67 */ | |
68 | |
69 static gint file_is_hidden(gchar *name) | |
70 { | 31 { |
71 if (name[0] != '.') return FALSE; | 32 if (name[0] != '.') return FALSE; |
72 if (name[1] == '\0' || (name[1] == '.' && name[2] == '\0')) return FALSE; | 33 if (name[1] == '\0' || (name[1] == '.' && name[2] == '\0')) return FALSE; |
73 return TRUE; | 34 return TRUE; |
74 } | 35 } |
75 | 36 |
76 static gint file_is_in_filter(gchar *name) | 37 static FilterEntry *filter_entry_new(const gchar *key, const gchar *description, |
77 { | 38 const gchar *extensions, gint enabled) |
78 GList *work; | 39 { |
79 if (!filename_filter || file_filter_disable) return TRUE; | 40 FilterEntry *fe; |
80 | 41 |
81 work = filename_filter; | 42 fe = g_new0(FilterEntry, 1); |
43 fe->key = g_strdup(key); | |
44 fe->description = g_strdup(description); | |
45 fe->extensions = g_strdup(extensions); | |
46 fe->enabled = enabled; | |
47 | |
48 return fe; | |
49 } | |
50 | |
51 static void filter_entry_free(FilterEntry *fe) | |
52 { | |
53 if (!fe) return; | |
54 | |
55 g_free(fe->key); | |
56 g_free(fe->description); | |
57 g_free(fe->extensions); | |
58 g_free(fe); | |
59 } | |
60 | |
61 GList *filter_get_list(void) | |
62 { | |
63 return filter_list; | |
64 } | |
65 | |
66 void filter_remove_entry(FilterEntry *fe) | |
67 { | |
68 if (!g_list_find(filter_list, fe)) return; | |
69 | |
70 filter_list = g_list_remove(filter_list, fe); | |
71 filter_entry_free(fe); | |
72 } | |
73 | |
74 static gint filter_key_exists(const gchar *key) | |
75 { | |
76 GList *work; | |
77 | |
78 if (!key) return FALSE; | |
79 | |
80 work = filter_list; | |
81 while (work) | |
82 { | |
83 FilterEntry *fe = work->data; | |
84 work = work->next; | |
85 | |
86 if (strcmp(fe->key, key) == 0) return TRUE; | |
87 } | |
88 | |
89 return FALSE; | |
90 } | |
91 | |
92 void filter_add(const gchar *key, const gchar *description, const gchar *extensions, gint enabled) | |
93 { | |
94 filter_list = g_list_append(filter_list, filter_entry_new(key, description, extensions, enabled)); | |
95 } | |
96 | |
97 void filter_add_unique(const gchar *description, const gchar *extensions, gint enabled) | |
98 { | |
99 gchar *key; | |
100 gint n; | |
101 | |
102 key = g_strdup("user0"); | |
103 n = 1; | |
104 while (filter_key_exists(key)) | |
105 { | |
106 g_free(key); | |
107 if (n > 999) return; | |
108 key = g_strdup_printf("user%d", n); | |
109 n++; | |
110 } | |
111 | |
112 filter_add(key, description, extensions, enabled); | |
113 g_free(key); | |
114 } | |
115 | |
116 static void filter_add_if_missing(const gchar *key, const gchar *description, const gchar *extensions, gint enabled) | |
117 { | |
118 GList *work; | |
119 | |
120 if (!key) return; | |
121 | |
122 work = filter_list; | |
123 while (work) | |
124 { | |
125 FilterEntry *fe = work->data; | |
126 work = work->next; | |
127 if (fe->key && strcmp(fe->key, key) == 0) return; | |
128 } | |
129 | |
130 filter_add(key, description, extensions, enabled); | |
131 } | |
132 | |
133 void filter_reset(void) | |
134 { | |
135 GList *work; | |
136 | |
137 work = filter_list; | |
138 while (work) | |
139 { | |
140 FilterEntry *fe = work->data; | |
141 work = work->next; | |
142 filter_entry_free(fe); | |
143 } | |
144 | |
145 g_list_free(filter_list); | |
146 filter_list = NULL; | |
147 } | |
148 | |
149 void filter_add_defaults(void) | |
150 { | |
151 GSList *list, *work; | |
152 | |
153 list = gdk_pixbuf_get_formats(); | |
154 work = list; | |
155 while (work) | |
156 { | |
157 GdkPixbufFormat *format; | |
158 gchar *name; | |
159 gchar *desc; | |
160 gchar **extensions; | |
161 GString *filter = NULL; | |
162 gint i; | |
163 | |
164 format = work->data; | |
165 work = work->next; | |
166 | |
167 name = gdk_pixbuf_format_get_name(format); | |
168 desc = gdk_pixbuf_format_get_description(format); | |
169 extensions = gdk_pixbuf_format_get_extensions(format); | |
170 | |
171 i = 0; | |
172 while (extensions[i]) | |
173 { | |
174 if (!filter) | |
175 { | |
176 filter = g_string_new("."); | |
177 filter = g_string_append(filter, extensions[i]); | |
178 } | |
179 else | |
180 { | |
181 filter = g_string_append(filter, ";."); | |
182 filter = g_string_append(filter, extensions[i]); | |
183 } | |
184 i++; | |
185 } | |
186 | |
187 if (debug) printf("loader reported [%s] [%s] [%s]\n", name, desc, filter->str); | |
188 | |
189 filter_add_if_missing(name, desc, filter->str, TRUE); | |
190 | |
191 g_free(name); | |
192 g_free(desc); | |
193 g_strfreev(extensions); | |
194 g_string_free(filter, TRUE); | |
195 } | |
196 g_slist_free(list); | |
197 | |
198 /* add defaults even if gdk-pixbuf does not have them, but disabled */ | |
199 filter_add_if_missing("jpeg", "JPEG group", ".jpg;.jpeg;.jpe", FALSE); | |
200 filter_add_if_missing("png", "Portable Network Graphic", ".png", FALSE); | |
201 filter_add_if_missing("tiff", "Tiff", ".tif;.tiff", FALSE); | |
202 filter_add_if_missing("pnm", "Packed Pixel formats", ".pbm;.pgm;.pnm;.ppm", FALSE); | |
203 filter_add_if_missing("gif", "Graphics Interchange Format", ".gif", FALSE); | |
204 filter_add_if_missing("xbm", "X bitmap", ".xbm", FALSE); | |
205 filter_add_if_missing("xpm", "X pixmap", ".xpm", FALSE); | |
206 filter_add_if_missing("bmp", "Bitmap", ".bmp", FALSE); | |
207 filter_add_if_missing("ico", "Icon file", ".ico;.cur", FALSE); | |
208 filter_add_if_missing("ras", "Raster", ".ras", FALSE); | |
209 filter_add_if_missing("svg", "Scalable Vector Graphics", ".svg", FALSE); | |
210 } | |
211 | |
212 static GList *filter_to_list(const gchar *extensions) | |
213 { | |
214 GList *list = NULL; | |
215 const gchar *p; | |
216 | |
217 if (!extensions) return NULL; | |
218 | |
219 p = extensions; | |
220 while (*p != '\0') | |
221 { | |
222 const gchar *b; | |
223 gint l = 0; | |
224 | |
225 b = p; | |
226 while (*p != '\0' && *p != ';') | |
227 { | |
228 p++; | |
229 l++; | |
230 } | |
231 list = g_list_append(list, g_strndup(b, l)); | |
232 if (*p == ';') p++; | |
233 } | |
234 | |
235 return list; | |
236 } | |
237 | |
238 void filter_rebuild(void) | |
239 { | |
240 GList *work; | |
241 | |
242 path_list_free(extension_list); | |
243 extension_list = NULL; | |
244 | |
245 work = filter_list; | |
246 while (work) | |
247 { | |
248 FilterEntry *fe; | |
249 | |
250 fe = work->data; | |
251 work = work->next; | |
252 | |
253 if (fe->enabled) | |
254 { | |
255 GList *ext; | |
256 | |
257 ext = filter_to_list(fe->extensions); | |
258 if (ext) extension_list = g_list_concat(extension_list, ext); | |
259 } | |
260 } | |
261 } | |
262 | |
263 gint filter_name_exists(const gchar *name) | |
264 { | |
265 GList *work; | |
266 if (!extension_list || file_filter_disable) return TRUE; | |
267 | |
268 work = extension_list; | |
82 while (work) | 269 while (work) |
83 { | 270 { |
84 gchar *filter = work->data; | 271 gchar *filter = work->data; |
85 gint lf = strlen(filter); | 272 gint lf = strlen(filter); |
86 gint ln = strlen(name); | 273 gint ln = strlen(name); |
92 } | 279 } |
93 | 280 |
94 return FALSE; | 281 return FALSE; |
95 } | 282 } |
96 | 283 |
97 static void add_to_filter(gchar *text, gint add) | 284 void filter_write_list(FILE *f) |
98 { | 285 { |
99 if (add) filename_filter = g_list_append(filename_filter, g_strdup(text)); | 286 GList *work; |
100 } | 287 |
101 | 288 work = filter_list; |
102 void rebuild_file_filter() | 289 while (work) |
103 { | 290 { |
104 if (filename_filter) | 291 FilterEntry *fe = work->data; |
105 { | 292 work = work->next; |
106 g_list_foreach(filename_filter,(GFunc)g_free,NULL); | 293 |
107 g_list_free(filename_filter); | 294 fprintf(f, "filter_ext: \"%s%s\" \"%s\" \"%s\"\n", (fe->enabled) ? "" : "#", |
108 filename_filter = NULL; | 295 fe->key, fe->extensions, |
109 } | 296 (fe->description) ? fe->description : ""); |
110 | 297 } |
111 add_to_filter(".jpg", filter_include_jpg); | 298 } |
112 add_to_filter(".jpeg", filter_include_jpg); | 299 |
113 add_to_filter(".xpm", filter_include_xpm); | 300 void filter_parse(const gchar *text) |
114 add_to_filter(".tif", filter_include_tif); | 301 { |
115 add_to_filter(".tiff", filter_include_tif); | 302 const gchar *p; |
116 add_to_filter(".gif", filter_include_gif); | 303 gchar *key; |
117 add_to_filter(".png", filter_include_png); | 304 gchar *ext; |
118 add_to_filter(".ppm", filter_include_ppm); | 305 gchar *desc; |
119 add_to_filter(".pgm", filter_include_pgm); | 306 gint enabled = TRUE; |
120 add_to_filter(".pcx", filter_include_pcx); | 307 |
121 add_to_filter(".bmp", filter_include_bmp); | 308 if (!text || text[0] != '"') return; |
122 | 309 |
123 if (custom_filter) | 310 key = quoted_value(text); |
124 { | 311 if (!key) return; |
125 gchar *buf = g_strdup(custom_filter); | 312 |
126 gchar *pos_ptr_b; | 313 p = text; |
127 gchar *pos_ptr_e = buf; | 314 p++; |
128 while(pos_ptr_e[0] != '\0') | 315 while (*p != '"' && *p != '\0') p++; |
129 { | 316 if (*p != '"') |
130 pos_ptr_b = pos_ptr_e; | 317 { |
131 while (pos_ptr_e[0] != ';' && pos_ptr_e[0] != '\0') pos_ptr_e++; | 318 g_free(key); |
132 if (pos_ptr_e[0] == ';') | 319 return; |
133 { | 320 } |
134 pos_ptr_e[0] = '\0'; | 321 p++; |
135 pos_ptr_e++; | 322 while (*p != '"' && *p != '\0') p++; |
136 } | 323 if (*p != '"') |
137 add_to_filter(pos_ptr_b, TRUE); | 324 { |
138 } | 325 g_free(key); |
139 g_free(buf); | 326 return; |
140 } | 327 } |
328 | |
329 ext = quoted_value(p); | |
330 | |
331 p++; | |
332 while (*p != '"' && *p != '\0') p++; | |
333 if (*p == '"') p++; | |
334 while (*p != '"' && *p != '\0') p++; | |
335 | |
336 if (*p == '"') | |
337 { | |
338 desc = quoted_value(p); | |
339 } | |
340 else | |
341 { | |
342 desc = NULL; | |
343 } | |
344 | |
345 if (key && key[0] == '#') | |
346 { | |
347 gchar *tmp; | |
348 tmp = g_strdup(key + 1); | |
349 g_free(key); | |
350 key = tmp; | |
351 | |
352 enabled = FALSE; | |
353 } | |
354 | |
355 if (key && strlen(key) > 0 && ext) filter_add(key, desc, ext, enabled); | |
356 | |
357 g_free(key); | |
358 g_free(ext); | |
359 g_free(desc); | |
360 } | |
361 | |
362 GList *path_list_filter(GList *list, gint is_dir_list) | |
363 { | |
364 GList *work; | |
365 | |
366 if (!is_dir_list && file_filter_disable && show_dot_files) return list; | |
367 | |
368 work = list; | |
369 while (work) | |
370 { | |
371 gchar *name = work->data; | |
372 const gchar *base; | |
373 | |
374 base = filename_from_path(name); | |
375 | |
376 if ((!show_dot_files && ishidden(base)) || | |
377 (!is_dir_list && !filter_name_exists(base)) || | |
378 (is_dir_list && base[0] == '.' && (strcmp(base, GQVIEW_CACHE_LOCAL_THUMB) == 0 || | |
379 strcmp(base, GQVIEW_CACHE_LOCAL_METADATA) == 0)) ) | |
380 { | |
381 GList *link = work; | |
382 work = work->next; | |
383 list = g_list_remove_link(list, link); | |
384 g_free(name); | |
385 g_list_free(link); | |
386 } | |
387 else | |
388 { | |
389 work = work->next; | |
390 } | |
391 } | |
392 | |
393 return list; | |
141 } | 394 } |
142 | 395 |
143 /* | 396 /* |
144 *----------------------------------------------------------------------------- | 397 *----------------------------------------------------------------------------- |
145 * load file list (private) | 398 * path list recursive |
146 *----------------------------------------------------------------------------- | 399 *----------------------------------------------------------------------------- |
147 */ | 400 */ |
148 | 401 |
149 static gint sort_list_cb(void *a, void *b) | 402 static gint path_list_sort_cb(gconstpointer a, gconstpointer b) |
150 { | 403 { |
151 return strcmp((gchar *)a, (gchar *)b); | 404 return CASE_SORT((gchar *)a, (gchar *)b); |
152 } | 405 } |
153 | 406 |
154 static void filelist_read(gchar *path) | 407 GList *path_list_sort(GList *list) |
408 { | |
409 return g_list_sort(list, path_list_sort_cb); | |
410 } | |
411 | |
412 static void path_list_recursive_append(GList **list, GList *dirs) | |
413 { | |
414 GList *work; | |
415 | |
416 work = dirs; | |
417 while (work) | |
418 { | |
419 const gchar *path = work->data; | |
420 GList *f = NULL; | |
421 GList *d = NULL; | |
422 | |
423 if (path_list(path, &f, &d)) | |
424 { | |
425 f = path_list_filter(f, FALSE); | |
426 f = path_list_sort(f); | |
427 *list = g_list_concat(*list, f); | |
428 | |
429 d = path_list_filter(d, TRUE); | |
430 d = path_list_sort(d); | |
431 path_list_recursive_append(list, d); | |
432 g_list_free(d); | |
433 } | |
434 | |
435 work = work->next; | |
436 } | |
437 } | |
438 | |
439 GList *path_list_recursive(const gchar *path) | |
440 { | |
441 GList *list = NULL; | |
442 GList *d = NULL; | |
443 | |
444 if (!path_list(path, &list, &d)) return NULL; | |
445 list = path_list_filter(list, FALSE); | |
446 list = path_list_sort(list); | |
447 | |
448 d = path_list_filter(d, TRUE); | |
449 d = path_list_sort(d); | |
450 path_list_recursive_append(&list, d); | |
451 path_list_free(d); | |
452 | |
453 return list; | |
454 } | |
455 | |
456 /* | |
457 *----------------------------------------------------------------------------- | |
458 * text conversion utils | |
459 *----------------------------------------------------------------------------- | |
460 */ | |
461 | |
462 gchar *text_from_size(gint64 size) | |
463 { | |
464 gchar *a, *b; | |
465 gchar *s, *d; | |
466 gint l, n, i; | |
467 | |
468 /* what I would like to use is printf("%'d", size) | |
469 * BUT: not supported on every libc :( | |
470 */ | |
471 if (size > G_MAXUINT) | |
472 { | |
473 /* the %lld conversion is not valid in all libcs, so use a simple work-around */ | |
474 a = g_strdup_printf("%d%09d", (guint)(size / 1000000000), (guint)(size % 1000000000)); | |
475 } | |
476 else | |
477 { | |
478 a = g_strdup_printf("%d", (guint)size); | |
479 } | |
480 l = strlen(a); | |
481 n = (l - 1)/ 3; | |
482 if (n < 1) return a; | |
483 | |
484 b = g_new(gchar, l + n + 1); | |
485 | |
486 s = a; | |
487 d = b; | |
488 i = l - n * 3; | |
489 while (*s != '\0') | |
490 { | |
491 if (i < 1) | |
492 { | |
493 i = 3; | |
494 *d = ','; | |
495 d++; | |
496 } | |
497 | |
498 *d = *s; | |
499 s++; | |
500 d++; | |
501 i--; | |
502 } | |
503 *d = '\0'; | |
504 | |
505 g_free(a); | |
506 return b; | |
507 } | |
508 | |
509 gchar *text_from_size_abrev(gint64 size) | |
510 { | |
511 if (size < (gint64)1024) | |
512 { | |
513 return g_strdup_printf(_("%d bytes"), (gint)size); | |
514 } | |
515 if (size < (gint64)1048576) | |
516 { | |
517 return g_strdup_printf(_("%.1f K"), (gfloat)size / 1024.0); | |
518 } | |
519 if (size < (gint64)1073741824) | |
520 { | |
521 return g_strdup_printf(_("%.1f MB"), (gfloat)size / 1048576.0); | |
522 } | |
523 | |
524 /* to avoid overflowing the float, do division in two steps */ | |
525 size /= 1048576.0; | |
526 return g_strdup_printf(_("%.1f GB"), (gfloat)size / 1024.0); | |
527 } | |
528 | |
529 /* note: returned string is valid until next call to text_from_time() */ | |
530 const gchar *text_from_time(time_t t) | |
531 { | |
532 static gchar *ret = NULL; | |
533 gchar buf[128]; | |
534 gint buflen; | |
535 struct tm *btime; | |
536 GError *error = NULL; | |
537 | |
538 btime = localtime(&t); | |
539 | |
540 /* the %x warning about 2 digit years is not an error */ | |
541 buflen = strftime(buf, sizeof(buf), "%x %H:%M", btime); | |
542 if (buflen < 1) return ""; | |
543 | |
544 g_free(ret); | |
545 ret = g_locale_to_utf8(buf, buflen, NULL, NULL, &error); | |
546 if (error) | |
547 { | |
548 printf("Error converting locale strftime to UTF-8: %s\n", error->message); | |
549 g_error_free(error); | |
550 return ""; | |
551 } | |
552 | |
553 return ret; | |
554 } | |
555 | |
556 /* | |
557 *----------------------------------------------------------------------------- | |
558 * file info struct | |
559 *----------------------------------------------------------------------------- | |
560 */ | |
561 | |
562 FileData *file_data_new(const gchar *path, struct stat *st) | |
563 { | |
564 FileData *fd; | |
565 | |
566 fd = g_new0(FileData, 1); | |
567 fd->path = path_to_utf8(path); | |
568 fd->name = filename_from_path(fd->path); | |
569 fd->size = st->st_size; | |
570 fd->date = st->st_mtime; | |
571 fd->pixbuf = NULL; | |
572 | |
573 return fd; | |
574 } | |
575 | |
576 FileData *file_data_new_simple(const gchar *path) | |
577 { | |
578 FileData *fd; | |
579 struct stat st; | |
580 | |
581 fd = g_new0(FileData, 1); | |
582 fd->path = g_strdup(path); | |
583 fd->name = filename_from_path(fd->path); | |
584 | |
585 if (stat_utf8(fd->path, &st)) | |
586 { | |
587 fd->size = st.st_size; | |
588 fd->date = st.st_mtime; | |
589 } | |
590 | |
591 fd->pixbuf = NULL; | |
592 | |
593 return fd; | |
594 } | |
595 | |
596 void file_data_free(FileData *fd) | |
597 { | |
598 g_free(fd->path); | |
599 if (fd->pixbuf) g_object_unref(fd->pixbuf); | |
600 g_free(fd); | |
601 } | |
602 | |
603 /* | |
604 *----------------------------------------------------------------------------- | |
605 * load file list | |
606 *----------------------------------------------------------------------------- | |
607 */ | |
608 | |
609 static SortType filelist_sort_method = SORT_NONE; | |
610 static gint filelist_sort_ascend = TRUE; | |
611 | |
612 static gint sort_file_cb(void *a, void *b) | |
613 { | |
614 FileData *fa = a; | |
615 FileData *fb = b; | |
616 | |
617 if (!filelist_sort_ascend) | |
618 { | |
619 fa = b; | |
620 fb = a; | |
621 } | |
622 | |
623 switch (filelist_sort_method) | |
624 { | |
625 case SORT_SIZE: | |
626 if (fa->size < fb->size) return -1; | |
627 if (fa->size > fb->size) return 1; | |
628 return 0; | |
629 break; | |
630 case SORT_TIME: | |
631 if (fa->date < fb->date) return -1; | |
632 if (fa->date > fb->date) return 1; | |
633 return 0; | |
634 break; | |
635 #ifdef HAVE_STRVERSCMP | |
636 case SORT_NUMBER: | |
637 return strverscmp(fa->name, fb->name); | |
638 break; | |
639 #endif | |
640 case SORT_NAME: | |
641 default: | |
642 return CASE_SORT(fa->name, fb->name); | |
643 break; | |
644 } | |
645 } | |
646 | |
647 GList *filelist_sort(GList *list, SortType method, gint ascend) | |
648 { | |
649 filelist_sort_method = method; | |
650 filelist_sort_ascend = ascend; | |
651 return g_list_sort(list, (GCompareFunc) sort_file_cb); | |
652 } | |
653 | |
654 GList *filelist_insert_sort(GList *list, FileData *fd, SortType method, gint ascend) | |
655 { | |
656 filelist_sort_method = method; | |
657 filelist_sort_ascend = ascend; | |
658 return g_list_insert_sorted(list, fd, (GCompareFunc) sort_file_cb); | |
659 } | |
660 | |
661 gint filelist_read(const gchar *path, GList **files, GList **dirs) | |
155 { | 662 { |
156 DIR *dp; | 663 DIR *dp; |
157 struct dirent *dir; | 664 struct dirent *dir; |
158 struct stat ent_sbuf; | 665 struct stat ent_sbuf; |
159 | 666 gchar *pathl; |
160 if((dp = opendir(path))==NULL) | 667 GList *dlist; |
161 { | 668 GList *flist; |
162 /* dir not found */ | 669 |
163 return; | 670 dlist = NULL; |
164 } | 671 flist = NULL; |
165 | 672 |
166 g_list_foreach(dir_list,(GFunc)g_free,NULL); | 673 pathl = path_from_utf8(path); |
167 g_list_free(dir_list); | 674 if (!pathl || (dp = opendir(pathl)) == NULL) |
168 dir_list = NULL; | 675 { |
169 | 676 g_free(pathl); |
170 g_list_foreach(file_list,(GFunc)g_free,NULL); | 677 if (files) *files = NULL; |
171 g_list_free(file_list); | 678 if (dirs) *dirs = NULL; |
172 file_list = NULL; | 679 return FALSE; |
680 } | |
681 | |
682 /* root dir fix */ | |
683 if (pathl[0] == '/' && pathl[1] == '\0') | |
684 { | |
685 g_free(pathl); | |
686 pathl = g_strdup(""); | |
687 } | |
173 | 688 |
174 while ((dir = readdir(dp)) != NULL) | 689 while ((dir = readdir(dp)) != NULL) |
175 { | 690 { |
176 /* skips removed files */ | 691 gchar *name = dir->d_name; |
177 if (dir->d_ino > 0) | 692 if (show_dot_files || !ishidden(name)) |
178 { | 693 { |
179 gchar *name = dir->d_name; | 694 gchar *filepath = g_strconcat(pathl, "/", name, NULL); |
180 if (show_dot_files || !file_is_hidden(name)) | 695 if (stat(filepath, &ent_sbuf) >= 0) |
181 { | 696 { |
182 gchar *filepath = g_strconcat(path, "/", name, NULL); | 697 if (S_ISDIR(ent_sbuf.st_mode)) |
183 if (stat(filepath,&ent_sbuf) >= 0 && S_ISDIR(ent_sbuf.st_mode)) | |
184 { | 698 { |
185 dir_list = g_list_prepend(dir_list, g_strdup(name)); | 699 /* we ignore the .thumbnails dir for cleanliness */ |
700 if ((dirs) && | |
701 !(name[0] == '.' && (name[1] == '\0' || (name[1] == '.' && name[2] == '\0'))) && | |
702 strcmp(name, GQVIEW_CACHE_LOCAL_THUMB) != 0 && | |
703 strcmp(name, GQVIEW_CACHE_LOCAL_METADATA) != 0) | |
704 { | |
705 dlist = g_list_prepend(dlist, file_data_new(filepath, &ent_sbuf)); | |
706 } | |
186 } | 707 } |
187 else | 708 else |
188 { | 709 { |
189 if (file_is_in_filter(name)) | 710 if ((files) && filter_name_exists(name)) |
190 file_list = g_list_prepend(file_list, g_strdup(name)); | |
191 } | |
192 g_free(filepath); | |
193 } | |
194 } | |
195 } | |
196 | |
197 closedir(dp); | |
198 | |
199 dir_list = g_list_sort(dir_list, (GCompareFunc) sort_list_cb); | |
200 file_list = g_list_sort(file_list, (GCompareFunc) sort_list_cb); | |
201 } | |
202 | |
203 /* | |
204 *----------------------------------------------------------------------------- | |
205 * file list utilities to retrieve information (public) | |
206 *----------------------------------------------------------------------------- | |
207 */ | |
208 | |
209 gint file_count() | |
210 { | |
211 return g_list_length(file_list); | |
212 } | |
213 | |
214 gint file_selection_count() | |
215 { | |
216 gint count = 0; | |
217 GList *work = GTK_CLIST(file_clist)->selection; | |
218 while(work) | |
219 { | |
220 count++; | |
221 if (debug) printf("s = %d\n", GPOINTER_TO_INT(work->data)); | |
222 work = work->next; | |
223 } | |
224 | |
225 if (debug) printf("files selected = %d\n", count); | |
226 | |
227 return count; | |
228 } | |
229 | |
230 gint find_file_in_list(gchar *path) | |
231 { | |
232 GList *work = file_list; | |
233 gchar *buf; | |
234 gchar *name; | |
235 gint count = -1; | |
236 | |
237 if (!path) return -1; | |
238 | |
239 buf = remove_level_from_path(path); | |
240 if (strcmp(buf, current_path) != 0) | |
241 { | |
242 g_free(buf); | |
243 return -1; | |
244 } | |
245 g_free(buf); | |
246 | |
247 name = filename_from_path(path); | |
248 while(work) | |
249 { | |
250 count++; | |
251 if (strcmp(name, work->data) == 0) return count; | |
252 work = work->next; | |
253 } | |
254 | |
255 return -1; | |
256 } | |
257 | |
258 gchar *file_get_path(gint row) | |
259 { | |
260 gchar *path = NULL; | |
261 gchar *name = gtk_clist_get_row_data(GTK_CLIST(file_clist), row); | |
262 | |
263 if (name) path = g_strconcat(current_path, "/", name, NULL); | |
264 | |
265 return path; | |
266 } | |
267 | |
268 gint file_is_selected(gint row) | |
269 { | |
270 GList *work = GTK_CLIST(file_clist)->selection; | |
271 | |
272 while(work) | |
273 { | |
274 if (GPOINTER_TO_INT(work->data) == row) return TRUE; | |
275 work = work->next; | |
276 } | |
277 | |
278 return FALSE; | |
279 } | |
280 | |
281 /* | |
282 *----------------------------------------------------------------------------- | |
283 * utilities to retrieve list of selected files (public) | |
284 *----------------------------------------------------------------------------- | |
285 */ | |
286 | |
287 GList *file_get_selected_list() | |
288 { | |
289 GList *list = NULL; | |
290 GList *work = GTK_CLIST(file_clist)->selection; | |
291 | |
292 while(work) | |
293 { | |
294 gchar *name = gtk_clist_get_row_data(GTK_CLIST(file_clist), | |
295 GPOINTER_TO_INT(work->data)); | |
296 list = g_list_prepend(list, g_strconcat(current_path, "/", name, NULL)); | |
297 work = work->next; | |
298 } | |
299 | |
300 list = g_list_reverse(list); | |
301 | |
302 return list; | |
303 } | |
304 | |
305 void free_selected_list(GList *list) | |
306 { | |
307 g_list_foreach(list, (GFunc)g_free, NULL); | |
308 g_list_free(list); | |
309 } | |
310 | |
311 gint file_clicked_is_selected() | |
312 { | |
313 return file_is_selected(filelist_click_row); | |
314 } | |
315 | |
316 gchar *file_clicked_get_path() | |
317 { | |
318 return file_get_path(filelist_click_row); | |
319 } | |
320 | |
321 /* | |
322 *----------------------------------------------------------------------------- | |
323 * image change routines | |
324 *----------------------------------------------------------------------------- | |
325 */ | |
326 | |
327 void file_image_change_to(gint row) | |
328 { | |
329 gtk_clist_unselect_all(GTK_CLIST(file_clist)); | |
330 gtk_clist_select_row(GTK_CLIST(file_clist), row, -1); | |
331 if (gtk_clist_row_is_visible(GTK_CLIST(file_clist), row) != GTK_VISIBILITY_FULL) | |
332 { | |
333 gtk_clist_moveto(GTK_CLIST(file_clist), row, -1, 0.5, 0.0); | |
334 } | |
335 } | |
336 | |
337 void file_next_image() | |
338 { | |
339 gint current; | |
340 gint total; | |
341 | |
342 if (slideshow_is_running()) | |
343 { | |
344 slideshow_next(); | |
345 return; | |
346 } | |
347 | |
348 current = find_file_in_list(image_get_path()); | |
349 total = file_count(); | |
350 | |
351 if (current >= 0) | |
352 { | |
353 if (current < total - 1) | |
354 { | |
355 file_image_change_to(current + 1); | |
356 } | |
357 } | |
358 else | |
359 { | |
360 file_image_change_to(0); | |
361 } | |
362 } | |
363 | |
364 void file_prev_image() | |
365 { | |
366 gint current; | |
367 | |
368 if (slideshow_is_running()) | |
369 { | |
370 slideshow_prev(); | |
371 return; | |
372 } | |
373 | |
374 current = find_file_in_list(image_get_path()); | |
375 | |
376 if (current >= 0) | |
377 { | |
378 if (current > 0) | |
379 { | |
380 file_image_change_to(current - 1); | |
381 } | |
382 } | |
383 else | |
384 { | |
385 file_image_change_to(file_count() - 1); | |
386 } | |
387 } | |
388 | |
389 void file_first_image() | |
390 { | |
391 gint current = find_file_in_list(image_get_path()); | |
392 if (current != 0 && file_count() > 0) | |
393 { | |
394 file_image_change_to(0); | |
395 } | |
396 } | |
397 | |
398 void file_last_image() | |
399 { | |
400 gint current = find_file_in_list(image_get_path()); | |
401 gint count = file_count(); | |
402 if (current != count - 1 && count > 0) | |
403 { | |
404 file_image_change_to(count - 1); | |
405 } | |
406 } | |
407 | |
408 /* | |
409 *----------------------------------------------------------------------------- | |
410 * file delete/rename update routines | |
411 *----------------------------------------------------------------------------- | |
412 */ | |
413 | |
414 static gint file_find_closest_unaccounted(gint row, gint count, GList *ignore_list) | |
415 { | |
416 GList *list = NULL; | |
417 GList *work; | |
418 gint rev = row - 1; | |
419 row ++; | |
420 | |
421 work = ignore_list; | |
422 while(work) | |
423 { | |
424 gint f = find_file_in_list(work->data); | |
425 if (f >= 0) list = g_list_append(list, GINT_TO_POINTER(f)); | |
426 work = work->next; | |
427 } | |
428 | |
429 while(list) | |
430 { | |
431 gint c = TRUE; | |
432 work = list; | |
433 while(work && c) | |
434 { | |
435 gpointer p = work->data; | |
436 work = work->next; | |
437 if (row == GPOINTER_TO_INT(p)) | |
438 { | |
439 row++; | |
440 c = FALSE; | |
441 } | |
442 if (rev == GPOINTER_TO_INT(p)) | |
443 { | |
444 rev--; | |
445 c = FALSE; | |
446 } | |
447 if (!c) list = g_list_remove(list, p); | |
448 } | |
449 if (c && list) | |
450 { | |
451 g_list_free(list); | |
452 list = NULL; | |
453 } | |
454 } | |
455 if (row > count - 1) | |
456 { | |
457 if (rev < 0) | |
458 return -1; | |
459 else | |
460 return rev; | |
461 } | |
462 else | |
463 { | |
464 return row; | |
465 } | |
466 } | |
467 | |
468 void file_is_gone(gchar *path, GList *ignore_list) | |
469 { | |
470 GList *list; | |
471 gchar *name; | |
472 gint row; | |
473 gint new_row = -1; | |
474 row = find_file_in_list(path); | |
475 if (row < 0) return; | |
476 | |
477 if (file_is_selected(row) /* && file_selection_count() == 1 */) | |
478 { | |
479 gint n = file_count(); | |
480 if (ignore_list) | |
481 { | |
482 new_row = file_find_closest_unaccounted(row, n, ignore_list); | |
483 if (debug) printf("row = %d, closest is %d\n", row, new_row); | |
484 } | |
485 else | |
486 { | |
487 if (row + 1 < n) | |
488 { | |
489 new_row = row + 1; | |
490 } | |
491 else if (row > 0) | |
492 { | |
493 new_row = row - 1; | |
494 } | |
495 } | |
496 gtk_clist_unselect_all(GTK_CLIST(file_clist)); | |
497 if (new_row >= 0) | |
498 { | |
499 gtk_clist_select_row(GTK_CLIST(file_clist), new_row, -1); | |
500 file_image_change_to(new_row); | |
501 } | |
502 else | |
503 { | |
504 image_change_to(NULL); | |
505 } | |
506 } | |
507 | |
508 gtk_clist_remove(GTK_CLIST(file_clist), row); | |
509 list = g_list_nth(file_list, row); | |
510 name = list->data; | |
511 file_list = g_list_remove(file_list, name); | |
512 g_free(name); | |
513 update_status_label(NULL); | |
514 } | |
515 | |
516 void file_is_renamed(gchar *source, gchar *dest) | |
517 { | |
518 gint row; | |
519 gchar *source_base; | |
520 gchar *dest_base; | |
521 | |
522 if (image_get_path() && !strcmp(source, image_get_path())) | |
523 { | |
524 image_set_path(dest); | |
525 } | |
526 | |
527 row = find_file_in_list(source); | |
528 if (row < 0) return; | |
529 | |
530 source_base = remove_level_from_path(source); | |
531 dest_base = remove_level_from_path(dest); | |
532 | |
533 if (strcmp(source_base, dest_base) == 0) | |
534 { | |
535 gchar *name; | |
536 gint n; | |
537 GList *work = g_list_nth(file_list, row); | |
538 name = work->data; | |
539 file_list = g_list_remove(file_list, name); | |
540 g_free(name); | |
541 name = g_strdup(filename_from_path(dest)); | |
542 file_list = g_list_insert_sorted(file_list, name, (GCompareFunc) sort_list_cb); | |
543 n = g_list_index(file_list, name); | |
544 | |
545 if (gtk_clist_get_cell_type(GTK_CLIST(file_clist), row, 0) != GTK_CELL_PIXTEXT) | |
546 { | |
547 gtk_clist_set_text (GTK_CLIST(file_clist), row, 0, name); | |
548 } | |
549 else | |
550 { | |
551 guint8 spacing = 0; | |
552 GdkPixmap *pixmap = NULL; | |
553 GdkBitmap *mask = NULL; | |
554 gtk_clist_get_pixtext(GTK_CLIST(file_clist), row, 0, | |
555 NULL, &spacing, &pixmap, &mask); | |
556 gtk_clist_set_pixtext(GTK_CLIST(file_clist), row, 0, | |
557 name, spacing, pixmap, mask); | |
558 } | |
559 | |
560 gtk_clist_set_row_data(GTK_CLIST(file_clist), row, name); | |
561 gtk_clist_row_move(GTK_CLIST(file_clist), row, n); | |
562 } | |
563 else | |
564 { | |
565 GList *work = g_list_nth(file_list, row); | |
566 gchar *name = work->data; | |
567 file_list = g_list_remove(file_list, name); | |
568 gtk_clist_remove(GTK_CLIST(file_clist), row); | |
569 g_free(name); | |
570 update_status_label(NULL); | |
571 } | |
572 | |
573 g_free(source_base); | |
574 g_free(dest_base); | |
575 | |
576 } | |
577 | |
578 /* | |
579 *----------------------------------------------------------------------------- | |
580 * directory list callbacks | |
581 *----------------------------------------------------------------------------- | |
582 */ | |
583 | |
584 void dir_select_cb(GtkWidget *widget, gint row, gint col, | |
585 GdkEvent *event, gpointer data) | |
586 { | |
587 gchar *name; | |
588 gchar *new_path; | |
589 name = gtk_clist_get_row_data (GTK_CLIST(dir_clist), row); | |
590 if (strcmp(name, ".") == 0) | |
591 { | |
592 new_path = g_strdup(current_path); | |
593 } | |
594 else if (strcmp(name, "..") == 0) | |
595 { | |
596 new_path = remove_level_from_path(current_path); | |
597 } | |
598 else | |
599 { | |
600 if (strcmp(current_path, "/") == 0) | |
601 new_path = g_strconcat(current_path, name, NULL); | |
602 else | |
603 new_path = g_strconcat(current_path, "/", name, NULL); | |
604 } | |
605 filelist_change_to(new_path); | |
606 g_free(new_path); | |
607 } | |
608 | |
609 void dir_press_cb(GtkWidget *widget, GdkEventButton *bevent, gpointer data) | |
610 { | |
611 gint row = -1; | |
612 gint col = -1; | |
613 | |
614 gtk_clist_get_selection_info (GTK_CLIST (widget), bevent->x, bevent->y, &row, &col); | |
615 | |
616 if (bevent->button == 2) | |
617 { | |
618 gtk_object_set_user_data(GTK_OBJECT(dir_clist), GINT_TO_POINTER(row)); | |
619 } | |
620 } | |
621 | |
622 /* | |
623 *----------------------------------------------------------------------------- | |
624 * file list callbacks | |
625 *----------------------------------------------------------------------------- | |
626 */ | |
627 | |
628 void file_press_cb(GtkWidget *widget, GdkEventButton *bevent, gpointer data) | |
629 { | |
630 gint row = -1; | |
631 gint col = -1; | |
632 | |
633 gtk_clist_get_selection_info (GTK_CLIST (widget), bevent->x, bevent->y, &row, &col); | |
634 if (row == -1 || col == -1) | |
635 { | |
636 filelist_click_row = -1; | |
637 return; | |
638 } | |
639 | |
640 filelist_click_row = row; | |
641 | |
642 if (bevent->button == 3) | |
643 { | |
644 file_clist_highlight_set(); | |
645 gtk_menu_popup (GTK_MENU(menu_file_popup), NULL, NULL, NULL, NULL, | |
646 bevent->button, bevent->time); | |
647 } | |
648 } | |
649 | |
650 void file_select_cb(GtkWidget *widget, gint row, gint col, | |
651 GdkEvent *event, gpointer data) | |
652 { | |
653 gchar *name; | |
654 gchar *path; | |
655 | |
656 if (file_selection_count() != 1) | |
657 { | |
658 update_status_label(NULL); | |
659 return; | |
660 } | |
661 | |
662 name = gtk_clist_get_row_data(GTK_CLIST(file_clist), row); | |
663 path = g_strconcat(current_path, "/", name, NULL); | |
664 image_change_to(path); | |
665 update_status_label(NULL); | |
666 g_free(path); | |
667 } | |
668 | |
669 void file_unselect_cb(GtkWidget *widget, gint row, gint col, | |
670 GdkEvent *event, gpointer data) | |
671 { | |
672 #if 0 | |
673 gchar *name; | |
674 gchar *path; | |
675 | |
676 name = gtk_clist_get_row_data(GTK_CLIST(file_clist), row); | |
677 path = g_strconcat(current_path, "/", name, NULL); | |
678 | |
679 if (strcmp(path, image_get_path()) == 0) | |
680 { | |
681 if (file_selection_count() > 0 && !file_is_selected(find_file_in_list(image_get_path())) ) | |
682 { | |
683 gint new_row = GPOINTER_TO_INT(GTK_CLIST(file_clist)->selection->data); | |
684 gchar *new_name = gtk_clist_get_row_data(GTK_CLIST(file_clist), new_row); | |
685 gchar *new_path = g_strconcat(current_path, "/", new_name, NULL); | |
686 image_change_to(new_path); | |
687 g_free(new_path); | |
688 } | |
689 } | |
690 g_free(path); | |
691 #endif | |
692 update_status_label(NULL); | |
693 } | |
694 | |
695 /* | |
696 *----------------------------------------------------------------------------- | |
697 * file list highlight utils | |
698 *----------------------------------------------------------------------------- | |
699 */ | |
700 | |
701 void file_clist_highlight_set() | |
702 { | |
703 if (file_clicked_is_selected()) return; | |
704 | |
705 gtk_clist_set_background(GTK_CLIST(file_clist), filelist_click_row, | |
706 >K_WIDGET (file_clist)->style->bg[GTK_STATE_PRELIGHT]); | |
707 gtk_clist_set_foreground(GTK_CLIST(file_clist), filelist_click_row, | |
708 >K_WIDGET (file_clist)->style->fg[GTK_STATE_PRELIGHT]); | |
709 } | |
710 | |
711 void file_clist_highlight_unset() | |
712 { | |
713 if (file_clicked_is_selected()) return; | |
714 | |
715 gtk_clist_set_background(GTK_CLIST(file_clist), filelist_click_row, NULL); | |
716 gtk_clist_set_foreground(GTK_CLIST(file_clist), filelist_click_row, NULL); | |
717 } | |
718 | |
719 /* | |
720 *----------------------------------------------------------------------------- | |
721 * path entry and history menu | |
722 *----------------------------------------------------------------------------- | |
723 */ | |
724 | |
725 void path_entry_tab_cb(gchar *newdir, gpointer data) | |
726 { | |
727 gchar *new_path; | |
728 gchar *buf; | |
729 gint found = FALSE; | |
730 | |
731 new_path = g_strdup(newdir); | |
732 parse_out_relatives(new_path); | |
733 buf = remove_level_from_path(new_path); | |
734 | |
735 if (buf && current_path && strcmp(buf, current_path) == 0) | |
736 { | |
737 GList *work; | |
738 gchar *part; | |
739 | |
740 part = filename_from_path(new_path); | |
741 work = file_list; | |
742 | |
743 while(part && work) | |
744 { | |
745 gchar *name = work->data; | |
746 work = work->next; | |
747 | |
748 if (strncmp(part, name, strlen(part)) == 0) | |
749 { | |
750 gint row = g_list_index(file_list, name); | |
751 if (!gtk_clist_row_is_visible(GTK_CLIST(file_clist), row) != GTK_VISIBILITY_FULL) | |
752 { | |
753 gtk_clist_moveto(GTK_CLIST(file_clist), row, -1, 0.5, 0.0); | |
754 } | |
755 found = TRUE; | |
756 break; | |
757 } | |
758 } | |
759 } | |
760 | |
761 if (!found && new_path && current_path && | |
762 strcmp(new_path, current_path) != 0 && isdir(new_path)) | |
763 { | |
764 filelist_change_to(new_path); | |
765 /* we are doing tab completion, add '/' back */ | |
766 gtk_entry_append_text(GTK_ENTRY(path_entry), "/"); | |
767 } | |
768 | |
769 g_free(buf); | |
770 g_free(new_path); | |
771 } | |
772 | |
773 void path_entry_cb(gchar *newdir, gpointer data) | |
774 { | |
775 gchar *new_path = g_strdup(newdir); | |
776 parse_out_relatives(new_path); | |
777 if (isdir(new_path)) | |
778 filelist_change_to(new_path); | |
779 else if (isfile(new_path)) | |
780 { | |
781 gchar *path = remove_level_from_path(new_path); | |
782 filelist_change_to(path); | |
783 g_free(path); | |
784 image_change_to(new_path); | |
785 } | |
786 g_free(new_path); | |
787 } | |
788 | |
789 static void history_menu_select_cb(GtkWidget *widget, gpointer data) | |
790 { | |
791 gchar *new_path = data; | |
792 filelist_change_to(new_path); | |
793 } | |
794 | |
795 static gchar *truncate_hist_text(gchar *t, gint l) | |
796 { | |
797 gchar *tp; | |
798 gchar *tbuf; | |
799 if (l >= strlen(t)) return g_strdup(t); | |
800 tp = t + strlen(t) - l; | |
801 while (tp[0] != '/' && tp < t + strlen(t)) tp++; | |
802 /* this checks to see if directory name is longer than l, if so | |
803 * reset the length of name to l, it's better to have a partial | |
804 * name than no name at all. | |
805 */ | |
806 if (tp >= t + strlen(t)) tp = t + strlen(t) - l; | |
807 tbuf = g_strconcat("/...", tp, NULL); | |
808 return tbuf; | |
809 } | |
810 | |
811 static void filelist_set_history(gchar *path) | |
812 { | |
813 static GList *history_list = NULL; | |
814 gchar *buf; | |
815 gchar *buf_ptr; | |
816 GtkWidget *menu; | |
817 GtkWidget *item; | |
818 | |
819 if (!path) return; | |
820 | |
821 gtk_entry_set_text(GTK_ENTRY(path_entry), current_path); | |
822 | |
823 if (history_list) | |
824 { | |
825 g_list_foreach(history_list, (GFunc)g_free, NULL); | |
826 g_list_free(history_list); | |
827 history_list = NULL; | |
828 } | |
829 | |
830 menu = gtk_menu_new(); | |
831 | |
832 buf = g_strdup(path); | |
833 buf_ptr = buf + strlen(buf) - 1 ; | |
834 while (buf_ptr > buf) | |
835 { | |
836 gchar *full_path; | |
837 gchar *truncated; | |
838 truncated = truncate_hist_text(buf, 32); | |
839 | |
840 full_path = g_strdup(buf); | |
841 history_list = g_list_append(history_list, full_path); | |
842 | |
843 item = gtk_menu_item_new_with_label (truncated); | |
844 gtk_signal_connect (GTK_OBJECT (item), "activate", | |
845 (GtkSignalFunc) history_menu_select_cb, full_path); | |
846 | |
847 gtk_menu_append (GTK_MENU (menu), item); | |
848 gtk_widget_show (item); | |
849 | |
850 g_free(truncated); | |
851 | |
852 while (buf_ptr[0] != '/' && buf_ptr > buf) buf_ptr--; | |
853 buf_ptr[0] = '\0'; | |
854 } | |
855 g_free(buf); | |
856 | |
857 item = gtk_menu_item_new_with_label ("/"); | |
858 | |
859 gtk_signal_connect (GTK_OBJECT (item), "activate", | |
860 (GtkSignalFunc) history_menu_select_cb, "/"); | |
861 | |
862 gtk_menu_append (GTK_MENU (menu), item); | |
863 gtk_widget_show (item); | |
864 | |
865 gtk_option_menu_set_menu(GTK_OPTION_MENU(history_menu), menu); | |
866 } | |
867 | |
868 /* | |
869 *----------------------------------------------------------------------------- | |
870 * list update routines (public) | |
871 *----------------------------------------------------------------------------- | |
872 */ | |
873 | |
874 static gint thumbs_running = 0; | |
875 | |
876 void interrupt_thumbs() | |
877 { | |
878 if (thumbs_running > 0) thumbs_running ++; | |
879 } | |
880 | |
881 void filelist_populate_clist() | |
882 { | |
883 GList *work; | |
884 gint width; | |
885 gint tmp_width; | |
886 gint row; | |
887 gchar *image_name = NULL; | |
888 gchar *buf; | |
889 | |
890 gint row_p = 0; | |
891 gchar *text; | |
892 guint8 spacing; | |
893 GdkPixmap *nopixmap; | |
894 GdkBitmap *nomask; | |
895 | |
896 interrupt_thumbs(); | |
897 | |
898 filelist_set_history(current_path); | |
899 | |
900 gtk_clist_freeze (GTK_CLIST (dir_clist)); | |
901 gtk_clist_clear (GTK_CLIST (dir_clist)); | |
902 | |
903 width = 0; | |
904 work = dir_list; | |
905 while(work) | |
906 { | |
907 gchar *buf[2]; | |
908 buf[0] = work->data; | |
909 buf[1] = NULL; | |
910 row = gtk_clist_append(GTK_CLIST(dir_clist), buf); | |
911 gtk_clist_set_row_data (GTK_CLIST(dir_clist), row, work->data); | |
912 tmp_width = gdk_string_width(dir_clist->style->font, buf[0]); | |
913 if (tmp_width > width) width = tmp_width; | |
914 work = work->next; | |
915 } | |
916 | |
917 gtk_clist_set_column_width(GTK_CLIST(dir_clist), 0, width); | |
918 gtk_clist_thaw(GTK_CLIST (dir_clist)); | |
919 | |
920 buf = remove_level_from_path(image_get_path()); | |
921 if (buf && strcmp(buf, current_path) == 0) | |
922 { | |
923 image_name = image_get_name(); | |
924 } | |
925 g_free(buf); | |
926 | |
927 gtk_clist_freeze (GTK_CLIST (file_clist)); | |
928 | |
929 if (!thumbnails_enabled) | |
930 { | |
931 gtk_clist_set_row_height (GTK_CLIST(file_clist), | |
932 GTK_WIDGET(file_clist)->style->font->ascent + | |
933 GTK_WIDGET(file_clist)->style->font->descent + 1); | |
934 } | |
935 else | |
936 { | |
937 gtk_clist_set_row_height (GTK_CLIST(file_clist), thumb_max_height + 2); | |
938 maintain_thumbnail_dir(current_path, FALSE); | |
939 } | |
940 | |
941 width = 0; | |
942 work = file_list; | |
943 | |
944 while(work) | |
945 { | |
946 gint has_pixmap; | |
947 gint match; | |
948 gchar *name = work->data; | |
949 gint done = FALSE; | |
950 | |
951 while (!done) | |
952 { | |
953 if (GTK_CLIST(file_clist)->rows > row_p) | |
954 { | |
955 if (gtk_clist_get_cell_type(GTK_CLIST(file_clist),row_p, 0) == GTK_CELL_PIXTEXT) | |
956 { | |
957 gtk_clist_get_pixtext(GTK_CLIST(file_clist), row_p, 0, &text, &spacing, &nopixmap, &nomask); | |
958 has_pixmap = TRUE; | |
959 } | |
960 else | |
961 { | |
962 gtk_clist_get_text(GTK_CLIST(file_clist), row_p, 0, &text); | |
963 has_pixmap = FALSE; | |
964 } | |
965 match = strcmp(name, text); | |
966 } | |
967 else | |
968 { | |
969 match = -1; | |
970 } | |
971 | |
972 if (match < 0) | |
973 { | |
974 gchar *buf[2]; | |
975 buf[0] = name; | |
976 buf[1] = NULL; | |
977 row = gtk_clist_insert(GTK_CLIST(file_clist), row_p, buf); | |
978 gtk_clist_set_row_data (GTK_CLIST(file_clist), row, name); | |
979 if (thumbnails_enabled) | |
980 gtk_clist_set_shift(GTK_CLIST(file_clist), row, 0, 0, 5 + thumb_max_width); | |
981 done = TRUE; | |
982 if (image_name && strcmp(name, image_name) == 0) | |
983 gtk_clist_select_row(GTK_CLIST(file_clist), row, 0); | |
984 } | |
985 else if (match > 0) | |
986 { | |
987 gtk_clist_remove(GTK_CLIST(file_clist), row_p); | |
988 } | |
989 else | |
990 { | |
991 if (thumbnails_enabled && !has_pixmap) | |
992 gtk_clist_set_shift(GTK_CLIST(file_clist), row_p, 0, 0, 5 + thumb_max_width); | |
993 if (!thumbnails_enabled/* && has_pixmap*/) | |
994 { | |
995 gtk_clist_set_text(GTK_CLIST(file_clist), row_p, 0, name); | |
996 gtk_clist_set_shift(GTK_CLIST(file_clist), row_p, 0, 0, 0); | |
997 } | |
998 gtk_clist_set_row_data (GTK_CLIST(file_clist), row_p, name); | |
999 done = TRUE; | |
1000 } | |
1001 } | |
1002 row_p++; | |
1003 | |
1004 if (thumbnails_enabled) | |
1005 tmp_width = gdk_string_width(file_clist->style->font, name) + thumb_max_width + 5; | |
1006 else | |
1007 tmp_width = gdk_string_width(file_clist->style->font, name); | |
1008 if (tmp_width > width) width = tmp_width; | |
1009 work = work->next; | |
1010 } | |
1011 | |
1012 while (GTK_CLIST(file_clist)->rows > row_p) | |
1013 gtk_clist_remove(GTK_CLIST(file_clist), row_p); | |
1014 | |
1015 gtk_clist_set_column_width(GTK_CLIST(file_clist), 0, width); | |
1016 gtk_clist_thaw(GTK_CLIST (file_clist)); | |
1017 | |
1018 if (thumbnails_enabled) | |
1019 { | |
1020 GList *done_list = NULL; | |
1021 gint past_run; | |
1022 gint finished = FALSE; | |
1023 gint j; | |
1024 gint count = 0; | |
1025 update_status_label(_("Loading thumbs...")); | |
1026 | |
1027 for (j = 0; j < GTK_CLIST(file_clist)->rows; j++) | |
1028 { | |
1029 done_list = g_list_prepend(done_list, GINT_TO_POINTER(FALSE)); | |
1030 } | |
1031 | |
1032 /* load thumbs */ | |
1033 | |
1034 while (!finished && done_list) | |
1035 { | |
1036 gint p = -1; | |
1037 gint r = -1; | |
1038 gint c = -1; | |
1039 gtk_clist_get_selection_info (GTK_CLIST(file_clist), 1, 1, &r, &c); | |
1040 if (r != -1) | |
1041 { | |
1042 work = g_list_nth(done_list, r); | |
1043 while (work) | |
1044 { | |
1045 if (gtk_clist_row_is_visible(GTK_CLIST(file_clist), r)) | |
1046 { | 711 { |
1047 if (!GPOINTER_TO_INT(work->data)) | 712 flist = g_list_prepend(flist, file_data_new(filepath, &ent_sbuf)); |
1048 { | |
1049 work->data = GINT_TO_POINTER(TRUE); | |
1050 p = r; | |
1051 work = NULL; | |
1052 } | |
1053 else | |
1054 { | |
1055 r++; | |
1056 work = work->next; | |
1057 } | |
1058 } | |
1059 else | |
1060 { | |
1061 work = NULL; | |
1062 } | 713 } |
1063 } | 714 } |
1064 } | 715 } |
1065 if (p == -1) | 716 g_free(filepath); |
1066 { | 717 } |
1067 work = done_list; | 718 } |
1068 r = 0; | 719 |
1069 while(work && p == -1) | 720 closedir(dp); |
1070 { | 721 |
1071 if (!GPOINTER_TO_INT(work->data)) | 722 g_free(pathl); |
1072 { | 723 |
1073 p = r; | 724 if (dirs) *dirs = dlist; |
1074 work->data = GINT_TO_POINTER(TRUE); | 725 if (files) *files = flist; |
1075 } | 726 |
1076 else | 727 return TRUE; |
1077 { | 728 } |
1078 r++; | 729 |
1079 work = work->next; | 730 void filelist_free(GList *list) |
1080 if (!work) finished = TRUE; | 731 { |
1081 } | 732 GList *work; |
1082 } | 733 |
1083 } | 734 work = list; |
1084 | 735 while (work) |
1085 count++; | 736 { |
1086 | 737 file_data_free((FileData *)work->data); |
1087 if (!finished && gtk_clist_get_cell_type(GTK_CLIST(file_clist), p, 0) != GTK_CELL_PIXTEXT) | 738 work = work->next; |
1088 { | 739 } |
1089 GdkPixmap *pixmap = NULL; | 740 |
1090 GdkBitmap *mask = NULL; | 741 g_list_free(list); |
1091 gchar *name; | 742 } |
1092 gchar *path; | 743 |
1093 | 744 |
1094 thumbs_running ++; | |
1095 past_run = thumbs_running; | |
1096 while(gtk_events_pending()) gtk_main_iteration(); | |
1097 if (thumbs_running > past_run) | |
1098 { | |
1099 thumbs_running -= 2; | |
1100 update_progressbar(0.0); | |
1101 update_status_label(NULL); | |
1102 g_list_free(done_list); | |
1103 return; | |
1104 } | |
1105 thumbs_running --; | |
1106 | |
1107 name = gtk_clist_get_row_data(GTK_CLIST(file_clist), p); | |
1108 path = g_strconcat (current_path, "/", name, NULL); | |
1109 spacing = create_thumbnail(path, &pixmap, &mask); | |
1110 g_free(path); | |
1111 gtk_clist_set_pixtext (GTK_CLIST(file_clist), p, 0, name, spacing + 5, pixmap, mask); | |
1112 gtk_clist_set_shift(GTK_CLIST(file_clist), p, 0, 0, 0); | |
1113 | |
1114 update_progressbar((gfloat)(count) / GTK_CLIST(file_clist)->rows); | |
1115 } | |
1116 } | |
1117 update_progressbar(0.0); | |
1118 g_list_free(done_list); | |
1119 } | |
1120 | |
1121 update_status_label(NULL); | |
1122 } | |
1123 | |
1124 void filelist_refresh() | |
1125 { | |
1126 filelist_read(current_path); | |
1127 filelist_populate_clist(); | |
1128 filelist_click_row = -1; | |
1129 } | |
1130 | |
1131 void filelist_change_to(gchar *path) | |
1132 { | |
1133 if (!isdir(path)) return; | |
1134 | |
1135 g_free(current_path); | |
1136 current_path = g_strdup(path); | |
1137 | |
1138 filelist_refresh(); | |
1139 } |