Mercurial > geeqie.yaz
annotate src/collect.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 | fa7d69e7d02d |
children | 9995c5fb202a |
rev | line source |
---|---|
9 | 1 /* |
196 | 2 * Geeqie |
94
50dc5a14d37b
Thu Nov 2 17:51:31 2006 John Ellis <johne@verizon.net>
gqview
parents:
91
diff
changeset
|
3 * (C) 2006 John Ellis |
9 | 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" | |
14 #include "collect.h" | |
15 | |
16 #include "collect-dlg.h" | |
17 #include "collect-io.h" | |
18 #include "collect-table.h" | |
19 #include "editors.h" | |
20 #include "filelist.h" | |
21 #include "img-view.h" | |
22 #include "info.h" | |
23 #include "layout.h" | |
24 #include "layout_image.h" | |
91
d063f97503b7
Wed Nov 1 11:39:48 2006 John Ellis <johne@verizon.net>
gqview
parents:
85
diff
changeset
|
25 #include "pixbuf_util.h" |
94
50dc5a14d37b
Thu Nov 2 17:51:31 2006 John Ellis <johne@verizon.net>
gqview
parents:
91
diff
changeset
|
26 #include "print.h" |
9 | 27 #include "utilops.h" |
28 #include "ui_fileops.h" | |
29 #include "ui_tree_edit.h" | |
30 | |
31 #include <gdk/gdkkeysyms.h> /* for keyboard values */ | |
32 | |
33 | |
34 #define COLLECT_DEF_WIDTH 440 | |
35 #define COLLECT_DEF_HEIGHT 450 | |
36 | |
37 static GList *collection_list = NULL; | |
38 static GList *collection_window_list = NULL; | |
39 | |
40 static void collection_window_get_geometry(CollectWindow *cw); | |
41 static void collection_window_refresh(CollectWindow *cw); | |
42 static void collection_window_update_title(CollectWindow *cw); | |
43 static void collection_window_add(CollectWindow *cw, CollectInfo *ci); | |
44 static void collection_window_insert(CollectWindow *cw, CollectInfo *ci); | |
45 static void collection_window_remove(CollectWindow *cw, CollectInfo *ci); | |
46 static void collection_window_update(CollectWindow *cw, CollectInfo *ci); | |
47 | |
48 static void collection_window_close(CollectWindow *cw); | |
49 | |
50 /* | |
51 *------------------------------------------------------------------- | |
52 * data, list handling | |
53 *------------------------------------------------------------------- | |
54 */ | |
55 | |
138 | 56 CollectInfo *collection_info_new(FileData *fd, struct stat *st, GdkPixbuf *pixbuf) |
9 | 57 { |
58 CollectInfo *ci; | |
59 | |
138 | 60 if (!fd) return NULL; |
9 | 61 |
62 ci = g_new0(CollectInfo, 1); | |
138 | 63 ci->fd = file_data_ref(fd); |
9 | 64 |
65 ci->pixbuf = pixbuf; | |
66 if (ci->pixbuf) g_object_ref(ci->pixbuf); | |
67 | |
68 return ci; | |
69 } | |
70 | |
71 void collection_info_free_thumb(CollectInfo *ci) | |
72 { | |
73 if (ci->pixbuf) g_object_unref(ci->pixbuf); | |
74 ci->pixbuf = NULL; | |
75 } | |
76 | |
77 void collection_info_free(CollectInfo *ci) | |
78 { | |
79 if (!ci) return; | |
80 | |
138 | 81 file_data_unref(ci->fd); |
9 | 82 collection_info_free_thumb(ci); |
83 g_free(ci); | |
84 } | |
85 | |
86 void collection_info_set_thumb(CollectInfo *ci, GdkPixbuf *pixbuf) | |
87 { | |
88 if (pixbuf) g_object_ref(pixbuf); | |
89 collection_info_free_thumb(ci); | |
90 ci->pixbuf = pixbuf; | |
91 } | |
92 | |
93 gint collection_info_load_thumb(CollectInfo *ci) | |
94 { | |
95 if (!ci) return FALSE; | |
96 | |
97 collection_info_free_thumb(ci); | |
98 | |
99 printf("collection_info_load_thumb not implemented!\n(because an instant thumb loader not implemented)"); | |
100 return FALSE; | |
101 #if 0 | |
138 | 102 if (create_thumbnail(ci->fd->path, &ci->pixmap, &ci->mask) < 0) return FALSE; |
9 | 103 |
104 if (ci->pixmap) gdk_pixmap_ref(ci->pixmap); | |
105 if (ci->mask) gdk_bitmap_ref(ci->mask); | |
106 | |
107 return TRUE; | |
108 #endif | |
109 } | |
110 | |
111 void collection_list_free(GList *list) | |
112 { | |
113 GList *work; | |
114 work = list; | |
115 while(work) | |
116 { | |
117 collection_info_free((CollectInfo *)work->data); | |
118 work = work->next; | |
119 } | |
120 g_list_free(list); | |
121 } | |
122 | |
123 /* an ugly static var, well what ya gonna do ? */ | |
124 static SortType collection_list_sort_method = SORT_NAME; | |
125 | |
126 static gint collection_list_sort_cb(gconstpointer a, gconstpointer b) | |
127 { | |
128 const CollectInfo *cia = a; | |
129 const CollectInfo *cib = b; | |
130 | |
131 switch(collection_list_sort_method) | |
132 { | |
133 case SORT_NONE: | |
134 return 0; | |
135 break; | |
136 case SORT_SIZE: | |
138 | 137 if (cia->fd->size < cib->fd->size) return -1; |
138 if (cia->fd->size > cib->fd->size) return 1; | |
9 | 139 return 0; |
140 break; | |
141 case SORT_TIME: | |
138 | 142 if (cia->fd->date < cib->fd->date) return -1; |
143 if (cia->fd->date > cib->fd->date) return 1; | |
9 | 144 return 0; |
145 break; | |
146 case SORT_PATH: | |
138 | 147 return CASE_SORT(cia->fd->path, cib->fd->path); |
9 | 148 break; |
149 #ifdef HAVE_STRVERSCMP | |
150 case SORT_NUMBER: | |
138 | 151 return strverscmp(cia->fd->name, cib->fd->name); |
9 | 152 break; |
153 #endif | |
154 case SORT_NAME: | |
155 default: | |
138 | 156 return CASE_SORT(cia->fd->name, cib->fd->name); |
9 | 157 break; |
158 } | |
159 | |
160 return 0; | |
161 } | |
162 | |
163 GList *collection_list_sort(GList *list, SortType method) | |
164 { | |
165 if (method == SORT_NONE) return list; | |
166 | |
167 collection_list_sort_method = method; | |
168 | |
169 return g_list_sort(list, collection_list_sort_cb); | |
170 } | |
171 | |
172 GList *collection_list_add(GList *list, CollectInfo *ci, SortType method) | |
173 { | |
174 if (method != SORT_NONE) | |
175 { | |
176 collection_list_sort_method = method; | |
177 list = g_list_insert_sorted(list, ci, collection_list_sort_cb); | |
178 } | |
179 else | |
180 { | |
181 list = g_list_append(list, ci); | |
182 } | |
183 | |
184 return list; | |
185 } | |
186 | |
187 GList *collection_list_insert(GList *list, CollectInfo *ci, CollectInfo *insert_ci, SortType method) | |
188 { | |
189 if (method != SORT_NONE) | |
190 { | |
191 collection_list_sort_method = method; | |
192 list = g_list_insert_sorted(list, ci, collection_list_sort_cb); | |
193 } | |
194 else | |
195 { | |
196 GList *point; | |
197 | |
198 point = g_list_find(list, insert_ci); | |
199 list = uig_list_insert_link(list, point, ci); | |
200 } | |
201 | |
202 return list; | |
203 } | |
204 | |
205 GList *collection_list_remove(GList *list, CollectInfo *ci) | |
206 { | |
207 list = g_list_remove(list, ci); | |
208 collection_info_free(ci); | |
209 return list; | |
210 } | |
211 | |
212 CollectInfo *collection_list_find(GList *list, const gchar *path) | |
213 { | |
214 GList *work = list; | |
215 | |
216 while(work) | |
217 { | |
218 CollectInfo *ci = work->data; | |
138 | 219 if (strcmp(ci->fd->path, path) == 0) return ci; |
9 | 220 work = work->next; |
221 } | |
222 | |
223 return NULL; | |
224 } | |
225 | |
226 #if 0 | |
227 static GList *collection_list_find_link(GList *list, gchar *path) | |
228 { | |
229 GList *work = list; | |
230 | |
231 while(work) | |
232 { | |
233 CollectInfo *ci = work->data; | |
138 | 234 if (strcmp(ci->fd->path, path) == 0) return work; |
9 | 235 work = work->next; |
236 } | |
237 | |
238 return NULL; | |
239 } | |
240 | |
241 static gint collection_list_find_index(GList *list, gchar *path) | |
242 { | |
243 gint c = 0; | |
244 GList *work = list; | |
245 | |
246 while(work) | |
247 { | |
248 CollectInfo *ci = work->data; | |
138 | 249 if (strcmp(ci->fd->path, path) == 0) return c; |
9 | 250 work = work->next; |
251 c++; | |
252 } | |
253 | |
254 return -1; | |
255 } | |
256 #endif | |
257 | |
138 | 258 GList *collection_list_to_filelist(GList *list) |
9 | 259 { |
138 | 260 GList *filelist = NULL; |
9 | 261 GList *work = list; |
262 | |
263 while (work) | |
264 { | |
265 CollectInfo *info = work->data; | |
138 | 266 filelist = g_list_prepend(filelist, file_data_ref(info->fd)); |
9 | 267 work = work->next; |
268 } | |
269 | |
138 | 270 filelist = g_list_reverse(filelist); |
271 return filelist; | |
9 | 272 } |
273 | |
274 CollectWindow *collection_window_find(CollectionData *cd) | |
275 { | |
276 GList *work; | |
277 | |
278 work = collection_window_list; | |
279 while (work) | |
280 { | |
281 CollectWindow *cw = work->data; | |
282 if (cw->cd == cd) return cw; | |
283 work = work->next; | |
284 } | |
285 | |
286 return NULL; | |
287 } | |
288 | |
289 CollectWindow *collection_window_find_by_path(const gchar *path) | |
290 { | |
291 GList *work; | |
292 | |
293 if (!path) return NULL; | |
294 | |
295 work = collection_window_list; | |
296 while (work) | |
297 { | |
298 CollectWindow *cw = work->data; | |
299 if (cw->cd->path && strcmp(cw->cd->path, path) == 0) return cw; | |
300 work = work->next; | |
301 } | |
302 | |
303 return NULL; | |
304 } | |
305 | |
306 /* | |
307 *------------------------------------------------------------------- | |
308 * please use these to actually add/remove stuff | |
309 *------------------------------------------------------------------- | |
310 */ | |
311 | |
312 CollectionData *collection_new(const gchar *path) | |
313 { | |
314 CollectionData *cd; | |
315 static gint untitled_counter = 0; | |
316 | |
317 cd = g_new0(CollectionData, 1); | |
318 | |
319 collection_list = g_list_append(collection_list, cd); | |
320 | |
321 cd->ref = 1; /* starts with a ref of 1 */ | |
322 | |
323 cd->list = NULL; | |
324 cd->sort_method = SORT_NONE; | |
325 cd->thumb_loader = NULL; | |
326 cd->info_updated_func = NULL; | |
327 | |
328 cd->window_read = FALSE; | |
329 cd->window_x = 0; | |
330 cd->window_y = 0; | |
331 cd->window_w = COLLECT_DEF_WIDTH; | |
332 cd->window_h = COLLECT_DEF_HEIGHT; | |
333 | |
334 cd->changed = FALSE; | |
335 | |
336 if (path) | |
337 { | |
338 cd->path = g_strdup(path); | |
339 cd->name = g_strdup(filename_from_path(cd->path)); | |
340 /* load it */ | |
341 } | |
342 else | |
343 { | |
344 cd->path = NULL; | |
345 | |
346 if (untitled_counter == 0) | |
347 { | |
348 cd->name = g_strdup(_("Untitled")); | |
349 } | |
350 else | |
351 { | |
352 cd->name = g_strdup_printf(_("Untitled (%d)"), untitled_counter + 1); | |
353 } | |
354 | |
355 untitled_counter++; | |
356 } | |
357 | |
358 return cd; | |
359 } | |
360 | |
361 void collection_free(CollectionData *cd) | |
362 { | |
363 if (!cd) return; | |
364 | |
365 if (debug) printf("collection \"%s\" freed\n", cd->name); | |
366 | |
367 collection_load_stop(cd); | |
368 collection_list_free(cd->list); | |
369 | |
370 collection_list = g_list_remove(collection_list, cd); | |
371 | |
372 g_free(cd->path); | |
373 g_free(cd->name); | |
374 | |
375 g_free(cd); | |
376 } | |
377 | |
378 void collection_ref(CollectionData *cd) | |
379 { | |
380 cd->ref++; | |
381 | |
382 if (debug) printf("collection \"%s\" ref count = %d\n", cd->name, cd->ref); | |
383 } | |
384 | |
385 void collection_unref(CollectionData *cd) | |
386 { | |
387 cd->ref--; | |
388 | |
389 if (debug) printf("collection \"%s\" ref count = %d\n", cd->name, cd->ref); | |
390 | |
391 if (cd->ref < 1) | |
392 { | |
393 collection_free(cd); | |
394 } | |
395 } | |
396 | |
397 void collection_path_changed(CollectionData *cd) | |
398 { | |
399 collection_window_update_title(collection_window_find(cd)); | |
400 } | |
401 | |
402 gint collection_to_number(CollectionData *cd) | |
403 { | |
404 return g_list_index(collection_list, cd); | |
405 } | |
406 | |
407 CollectionData *collection_from_number(gint n) | |
408 { | |
409 return g_list_nth_data(collection_list, n); | |
410 } | |
411 | |
412 CollectionData *collection_from_dnd_data(const gchar *data, GList **list, GList **info_list) | |
413 { | |
414 CollectionData *cd; | |
415 gint n; | |
416 | |
417 if (strncmp(data, "COLLECTION:", 11) != 0) return NULL; | |
418 | |
419 n = (gint)strtol(data + 11, NULL, 10); | |
420 cd = collection_from_number(n); | |
421 | |
422 if (!cd || (!list && !info_list)) | |
423 { | |
424 return cd; | |
425 } | |
426 else | |
427 { | |
428 GList *work = NULL; | |
429 GList *infol = NULL; | |
430 gint b, e; | |
431 | |
432 b = 0; | |
433 while(data[b] != '\0' && data[b] != '\n' ) b++; | |
434 b++; | |
435 e = b; | |
436 | |
437 while (data[b] != '\0') | |
438 { | |
439 CollectInfo *info; | |
440 | |
441 while (data[e] != '\n' && data[e] != '\0') e++; | |
442 n = (gint)strtol(data + b, NULL, 10); | |
443 | |
444 info = g_list_nth_data(cd->list, n); | |
138 | 445 if (info && list) work = g_list_append(work, file_data_ref(info->fd)); |
9 | 446 if (info && info_list) infol = g_list_append(infol, info); |
447 | |
448 while (data[e] == '\n') e++; | |
449 b = e; | |
450 } | |
451 if (list) *list = work; | |
452 if (info_list) *info_list = infol; | |
453 } | |
454 | |
455 return cd; | |
456 } | |
457 | |
458 gchar *collection_info_list_to_dnd_data(CollectionData *cd, GList *list, gint *length) | |
459 { | |
460 gchar *uri_text = NULL; | |
461 gint total; | |
462 GList *work; | |
463 gint n; | |
464 GList *temp; | |
465 gchar *ptr; | |
466 | |
467 n = collection_to_number(cd); | |
468 | |
469 if (!list || n < 0) | |
470 { | |
471 *length = 0; | |
472 return NULL; | |
473 } | |
474 | |
475 temp = NULL; | |
476 temp = g_list_prepend(temp, g_strdup_printf("COLLECTION:%d\n", n)); | |
477 work = list; | |
478 while(work) | |
479 { | |
480 n = g_list_index(cd->list, work->data); | |
481 if (n >= 0) | |
482 { | |
483 temp = g_list_prepend(temp, g_strdup_printf("%d\n", n)); | |
484 } | |
485 work = work->next; | |
486 } | |
487 | |
488 total = 0; | |
489 work = temp; | |
490 while(work) | |
491 { | |
492 total += strlen((gchar *)work->data); | |
493 work = work->next; | |
494 } | |
495 total += 1; | |
496 | |
497 uri_text = g_malloc(total); | |
498 ptr = uri_text; | |
499 | |
500 work = g_list_last(temp); | |
501 while(work) | |
502 { | |
503 gchar *text = work->data; | |
504 | |
505 work = work->prev; | |
506 | |
507 strcpy(ptr, text); | |
508 ptr += strlen(text); | |
509 } | |
510 | |
511 ptr[0] = '\0'; | |
512 | |
138 | 513 string_list_free(temp); |
9 | 514 |
515 *length = total; | |
516 | |
517 return uri_text; | |
518 } | |
519 | |
520 gint collection_info_valid(CollectionData *cd, CollectInfo *info) | |
521 { | |
522 if (collection_to_number(cd) < 0) return FALSE; | |
523 | |
524 return (g_list_index(cd->list, info) != 0); | |
525 } | |
526 | |
527 CollectInfo *collection_next_by_info(CollectionData *cd, CollectInfo *info) | |
528 { | |
529 GList *work; | |
530 | |
531 work = g_list_find(cd->list, info); | |
532 | |
533 if (!work) return NULL; | |
534 work = work->next; | |
535 if (work) return work->data; | |
536 return NULL; | |
537 } | |
538 | |
539 CollectInfo *collection_prev_by_info(CollectionData *cd, CollectInfo *info) | |
540 { | |
541 GList *work; | |
542 | |
543 work = g_list_find(cd->list, info); | |
544 | |
545 if (!work) return NULL; | |
546 work = work->prev; | |
547 if (work) return work->data; | |
548 return NULL; | |
549 } | |
550 | |
551 CollectInfo *collection_get_first(CollectionData *cd) | |
552 { | |
553 if (cd->list) return cd->list->data; | |
554 | |
555 return NULL; | |
556 } | |
557 | |
558 CollectInfo *collection_get_last(CollectionData *cd) | |
559 { | |
560 GList *list; | |
561 | |
562 list = g_list_last(cd->list); | |
563 | |
564 if (list) return list->data; | |
565 | |
566 return NULL; | |
567 } | |
568 | |
569 void collection_set_sort_method(CollectionData *cd, SortType method) | |
570 { | |
571 if (!cd) return; | |
572 | |
573 if (cd->sort_method == method) return; | |
574 | |
575 cd->sort_method = method; | |
576 cd->list = collection_list_sort(cd->list, cd->sort_method); | |
577 if (cd->list) cd->changed = TRUE; | |
578 | |
579 collection_window_refresh(collection_window_find(cd)); | |
580 } | |
581 | |
582 void collection_set_update_info_func(CollectionData *cd, | |
583 void (*func)(CollectionData *, CollectInfo *, gpointer), gpointer data) | |
584 { | |
585 cd->info_updated_func = func; | |
586 cd->info_updated_data = data; | |
587 } | |
588 | |
138 | 589 gint collection_add_check(CollectionData *cd, FileData *fd, gint sorted, gint must_exist) |
9 | 590 { |
591 struct stat st; | |
592 gint valid; | |
593 | |
594 if (must_exist) | |
595 { | |
138 | 596 valid = (stat_utf8(fd->path, &st) && !S_ISDIR(st.st_mode)); |
9 | 597 } |
598 else | |
599 { | |
600 valid = TRUE; | |
601 st.st_size = 0; | |
602 st.st_mtime = 0; | |
603 } | |
604 | |
605 if (valid) | |
606 { | |
607 CollectInfo *ci; | |
138 | 608 ci = collection_info_new(fd, &st, NULL); |
9 | 609 cd->list = collection_list_add(cd->list, ci, sorted ? cd->sort_method : SORT_NONE); |
610 cd->changed = TRUE; | |
611 | |
612 if (!sorted || cd->sort_method == SORT_NONE) | |
613 { | |
614 collection_window_add(collection_window_find(cd), ci); | |
615 } | |
616 else | |
617 { | |
618 collection_window_insert(collection_window_find(cd), ci); | |
619 } | |
620 } | |
621 | |
622 return valid; | |
623 } | |
624 | |
138 | 625 gint collection_add(CollectionData *cd, FileData *fd, gint sorted) |
9 | 626 { |
138 | 627 return collection_add_check(cd, fd, sorted, TRUE); |
9 | 628 } |
629 | |
138 | 630 gint collection_insert(CollectionData *cd, FileData *fd, CollectInfo *insert_ci, gint sorted) |
9 | 631 { |
632 struct stat st; | |
633 | |
138 | 634 if (!insert_ci) return collection_add(cd, fd, sorted); |
9 | 635 |
138 | 636 if (stat_utf8(fd->path, &st) >= 0 && !S_ISDIR(st.st_mode)) |
9 | 637 { |
638 CollectInfo *ci; | |
138 | 639 ci = collection_info_new(fd, &st, NULL); |
9 | 640 cd->list = collection_list_insert(cd->list, ci, insert_ci, sorted ? cd->sort_method : SORT_NONE); |
641 cd->changed = TRUE; | |
642 | |
643 collection_window_insert(collection_window_find(cd), ci); | |
644 | |
645 return TRUE; | |
646 } | |
647 | |
648 return FALSE; | |
649 } | |
650 | |
138 | 651 gint collection_remove(CollectionData *cd, FileData *fd) |
9 | 652 { |
653 CollectInfo *ci; | |
654 | |
138 | 655 ci = collection_list_find(cd->list, fd->path); |
9 | 656 |
657 if (!ci) return FALSE; | |
658 | |
659 cd->list = g_list_remove(cd->list, ci); | |
660 cd->changed = TRUE; | |
661 | |
662 collection_window_remove(collection_window_find(cd), ci); | |
663 collection_info_free(ci); | |
664 | |
665 return TRUE; | |
666 } | |
667 | |
668 static void collection_remove_by_info(CollectionData *cd, CollectInfo *info) | |
669 { | |
670 if (!info || !g_list_find(cd->list, info)) return; | |
671 | |
672 cd->list = g_list_remove(cd->list, info); | |
673 cd->changed = (cd->list != NULL); | |
674 | |
675 collection_window_remove(collection_window_find(cd), info); | |
676 collection_info_free(info); | |
677 } | |
678 | |
679 void collection_remove_by_info_list(CollectionData *cd, GList *list) | |
680 { | |
681 GList *work; | |
682 | |
683 if (!list) return; | |
684 | |
685 if (!list->next) | |
686 { | |
687 /* more efficient (in collect-table) to remove a single item this way */ | |
688 collection_remove_by_info(cd, (CollectInfo *)list->data); | |
689 return; | |
690 } | |
691 | |
692 work = list; | |
693 while(work) | |
694 { | |
695 cd->list = collection_list_remove(cd->list, work->data); | |
696 work = work->next; | |
697 } | |
698 cd->changed = (cd->list != NULL); | |
699 | |
700 collection_window_refresh(collection_window_find(cd)); | |
701 } | |
702 | |
138 | 703 gint collection_rename(CollectionData *cd, FileData *fd) |
9 | 704 { |
705 CollectInfo *ci; | |
138 | 706 const gchar *source = fd->change->source; |
259 | 707 // const gchar *dest = fd->change->dest; |
9 | 708 ci = collection_list_find(cd->list, source); |
709 | |
710 if (!ci) return FALSE; | |
711 | |
138 | 712 // g_free(ci->path); |
713 // ci->path = g_strdup(dest); FIXME | |
9 | 714 cd->changed = TRUE; |
715 | |
716 collection_window_update(collection_window_find(cd), ci); | |
717 | |
718 return TRUE; | |
719 } | |
720 | |
721 void collection_update_geometry(CollectionData *cd) | |
722 { | |
723 collection_window_get_geometry(collection_window_find(cd)); | |
724 } | |
725 | |
726 /* | |
727 *------------------------------------------------------------------- | |
728 * simple maintenance for renaming, deleting | |
729 *------------------------------------------------------------------- | |
730 */ | |
731 | |
138 | 732 void collection_maint_removed(FileData *fd) |
9 | 733 { |
734 GList *work; | |
735 | |
736 work = collection_list; | |
737 while(work) | |
738 { | |
739 CollectionData *cd = work->data; | |
740 work = work->next; | |
741 | |
138 | 742 while(collection_remove(cd, fd)); |
9 | 743 } |
744 #if 0 | |
745 /* Do we really need to do this? removed files are | |
746 * automatically ignored when loading a collection. | |
747 */ | |
138 | 748 collect_manager_moved(fd, NULL); |
9 | 749 #endif |
750 } | |
751 | |
138 | 752 void collection_maint_renamed(FileData *fd) |
9 | 753 { |
754 GList *work; | |
755 | |
756 work = collection_list; | |
757 while(work) | |
758 { | |
759 CollectionData *cd = work->data; | |
760 work = work->next; | |
761 | |
138 | 762 while(collection_rename(cd, fd)); |
9 | 763 } |
764 | |
138 | 765 collect_manager_moved(fd); |
9 | 766 } |
767 | |
768 /* | |
769 *------------------------------------------------------------------- | |
770 * window key presses | |
771 *------------------------------------------------------------------- | |
772 */ | |
773 | |
774 static gint collection_window_keypress(GtkWidget *widget, GdkEventKey *event, gpointer data) | |
775 { | |
776 CollectWindow *cw = data; | |
777 gint stop_signal = FALSE; | |
778 gint edit_val = -1; | |
779 GList *list; | |
780 | |
781 if (event->state & GDK_CONTROL_MASK) | |
782 { | |
85
9d5c75b5ec28
Fri Oct 20 09:20:10 2006 John Ellis <johne@verizon.net>
gqview
parents:
9
diff
changeset
|
783 stop_signal = TRUE; |
9 | 784 switch (event->keyval) |
785 { | |
786 case '1': | |
787 edit_val = 0; | |
788 break; | |
789 case '2': | |
790 edit_val = 1; | |
791 break; | |
792 case '3': | |
793 edit_val = 2; | |
794 break; | |
795 case '4': | |
796 edit_val = 3; | |
797 break; | |
798 case '5': | |
799 edit_val = 4; | |
800 break; | |
801 case '6': | |
802 edit_val = 5; | |
803 break; | |
804 case '7': | |
805 edit_val = 6; | |
806 break; | |
807 case '8': | |
808 edit_val = 7; | |
809 break; | |
810 case '9': | |
811 edit_val = 8; | |
812 break; | |
813 case '0': | |
814 edit_val = 9; | |
815 break; | |
816 case 'A': case 'a': | |
817 if (event->state & GDK_SHIFT_MASK) | |
818 { | |
819 collection_table_unselect_all(cw->table); | |
820 } | |
821 else | |
822 { | |
823 collection_table_select_all(cw->table); | |
824 } | |
825 break; | |
826 case 'L': case 'l': | |
827 list = layout_list(NULL); | |
828 if (list) | |
829 { | |
138 | 830 collection_table_add_filelist(cw->table, list); |
831 filelist_free(list); | |
9 | 832 } |
833 break; | |
834 case 'C': case 'c': | |
835 file_util_copy(NULL, collection_table_selection_get_list(cw->table), NULL, cw->window); | |
836 break; | |
837 case 'M': case 'm': | |
838 file_util_move(NULL, collection_table_selection_get_list(cw->table), NULL, cw->window); | |
839 break; | |
840 case 'R': case 'r': | |
841 file_util_rename(NULL, collection_table_selection_get_list(cw->table), cw->window); | |
842 break; | |
843 case 'D': case 'd': | |
844 file_util_delete(NULL, collection_table_selection_get_list(cw->table), cw->window); | |
845 break; | |
846 case 'P': case 'p': | |
847 info_window_new(NULL, collection_table_selection_get_list(cw->table)); | |
848 break; | |
849 case 'S': case 's': | |
850 collection_dialog_save_as(NULL, cw->cd); | |
851 break; | |
852 case 'W': case 'w': | |
853 collection_window_close(cw); | |
854 break; | |
855 default: | |
85
9d5c75b5ec28
Fri Oct 20 09:20:10 2006 John Ellis <johne@verizon.net>
gqview
parents:
9
diff
changeset
|
856 stop_signal = FALSE; |
9 | 857 break; |
858 } | |
859 } | |
860 else | |
861 { | |
85
9d5c75b5ec28
Fri Oct 20 09:20:10 2006 John Ellis <johne@verizon.net>
gqview
parents:
9
diff
changeset
|
862 stop_signal = TRUE; |
9 | 863 switch (event->keyval) |
864 { | |
865 case GDK_Return: case GDK_KP_Enter: | |
866 layout_image_set_collection(NULL, cw->cd, | |
867 collection_table_get_focus_info(cw->table)); | |
868 break; | |
869 case 'V': case 'v': | |
870 view_window_new_from_collection(cw->cd, | |
871 collection_table_get_focus_info(cw->table)); | |
872 break; | |
873 case 'S': case 's': | |
874 if (!cw->cd->path) | |
875 { | |
876 collection_dialog_save_as(NULL, cw->cd); | |
877 } | |
878 else if (!collection_save(cw->cd, cw->cd->path)) | |
879 { | |
880 printf("failed saving to collection path: %s\n", cw->cd->path); | |
881 } | |
882 break; | |
883 case 'A': case 'a': | |
85
9d5c75b5ec28
Fri Oct 20 09:20:10 2006 John Ellis <johne@verizon.net>
gqview
parents:
9
diff
changeset
|
884 collection_dialog_append(NULL, cw->cd); |
9 | 885 break; |
886 case 'N': case 'n': | |
887 collection_set_sort_method(cw->cd, SORT_NAME); | |
888 break; | |
889 #ifdef HAVE_STRVERSCMP | |
890 case 'I': case 'i': | |
891 collection_set_sort_method(cw->cd, SORT_NUMBER); | |
892 break; | |
893 #endif | |
894 case 'D': case 'd': | |
895 collection_set_sort_method(cw->cd, SORT_TIME); | |
896 break; | |
897 case 'B': case 'b': | |
898 collection_set_sort_method(cw->cd, SORT_SIZE); | |
899 break; | |
900 case 'P': case 'p': | |
94
50dc5a14d37b
Thu Nov 2 17:51:31 2006 John Ellis <johne@verizon.net>
gqview
parents:
91
diff
changeset
|
901 if (event->state & GDK_SHIFT_MASK) |
50dc5a14d37b
Thu Nov 2 17:51:31 2006 John Ellis <johne@verizon.net>
gqview
parents:
91
diff
changeset
|
902 { |
50dc5a14d37b
Thu Nov 2 17:51:31 2006 John Ellis <johne@verizon.net>
gqview
parents:
91
diff
changeset
|
903 CollectInfo *info; |
50dc5a14d37b
Thu Nov 2 17:51:31 2006 John Ellis <johne@verizon.net>
gqview
parents:
91
diff
changeset
|
904 |
50dc5a14d37b
Thu Nov 2 17:51:31 2006 John Ellis <johne@verizon.net>
gqview
parents:
91
diff
changeset
|
905 info = collection_table_get_focus_info(cw->table); |
50dc5a14d37b
Thu Nov 2 17:51:31 2006 John Ellis <johne@verizon.net>
gqview
parents:
91
diff
changeset
|
906 |
138 | 907 print_window_new(info->fd, collection_table_selection_get_list(cw->table), |
908 collection_list_to_filelist(cw->cd->list), cw->window); | |
94
50dc5a14d37b
Thu Nov 2 17:51:31 2006 John Ellis <johne@verizon.net>
gqview
parents:
91
diff
changeset
|
909 } |
50dc5a14d37b
Thu Nov 2 17:51:31 2006 John Ellis <johne@verizon.net>
gqview
parents:
91
diff
changeset
|
910 else |
50dc5a14d37b
Thu Nov 2 17:51:31 2006 John Ellis <johne@verizon.net>
gqview
parents:
91
diff
changeset
|
911 { |
50dc5a14d37b
Thu Nov 2 17:51:31 2006 John Ellis <johne@verizon.net>
gqview
parents:
91
diff
changeset
|
912 collection_set_sort_method(cw->cd, SORT_PATH); |
50dc5a14d37b
Thu Nov 2 17:51:31 2006 John Ellis <johne@verizon.net>
gqview
parents:
91
diff
changeset
|
913 } |
9 | 914 break; |
915 case GDK_Delete: case GDK_KP_Delete: | |
916 list = g_list_copy(cw->table->selection); | |
917 if (list) | |
918 { | |
919 collection_remove_by_info_list(cw->cd, list); | |
920 g_list_free(list); | |
921 } | |
922 else | |
923 { | |
924 collection_remove_by_info(cw->cd, collection_table_get_focus_info(cw->table)); | |
925 } | |
926 break; | |
927 default: | |
85
9d5c75b5ec28
Fri Oct 20 09:20:10 2006 John Ellis <johne@verizon.net>
gqview
parents:
9
diff
changeset
|
928 stop_signal = FALSE; |
9 | 929 break; |
930 } | |
931 } | |
932 | |
933 if (edit_val != -1) | |
934 { | |
935 list = collection_table_selection_get_list(cw->table); | |
138 | 936 start_editor_from_filelist(edit_val, list); |
937 filelist_free(list); | |
9 | 938 } |
939 | |
940 return stop_signal; | |
941 } | |
942 | |
943 /* | |
944 *------------------------------------------------------------------- | |
945 * window | |
946 *------------------------------------------------------------------- | |
947 */ | |
948 static void collection_window_get_geometry(CollectWindow *cw) | |
949 { | |
950 CollectionData *cd; | |
951 | |
952 if (!cw) return; | |
953 | |
954 cd = cw->cd; | |
955 gdk_window_get_position (cw->window->window, &cd->window_x, &cd->window_y); | |
956 gdk_drawable_get_size(cw->window->window, &cd->window_w, &cd->window_h); | |
957 cd->window_read = TRUE; | |
958 } | |
959 | |
960 static void collection_window_refresh(CollectWindow *cw) | |
961 { | |
962 if (!cw) return; | |
963 | |
964 collection_table_refresh(cw->table); | |
965 } | |
966 | |
967 static void collection_window_update_title(CollectWindow *cw) | |
968 { | |
969 gchar *buf; | |
970 | |
971 if (!cw) return; | |
972 | |
196 | 973 buf = g_strdup_printf(_("%s - Geeqie Collection"), cw->cd->name); |
9 | 974 gtk_window_set_title(GTK_WINDOW(cw->window), buf); |
975 g_free(buf); | |
976 } | |
977 | |
978 static void collection_window_update_info(CollectionData *cd, CollectInfo *ci, gpointer data) | |
979 { | |
980 CollectWindow *cw = data; | |
981 | |
982 collection_table_file_update(cw->table, ci); | |
983 } | |
984 | |
985 static void collection_window_add(CollectWindow *cw, CollectInfo *ci) | |
986 { | |
987 if (!cw) return; | |
988 | |
989 if (!ci->pixbuf) collection_load_thumb_idle(cw->cd); | |
990 collection_table_file_add(cw->table, ci); | |
991 } | |
992 | |
993 static void collection_window_insert(CollectWindow *cw, CollectInfo *ci) | |
994 { | |
995 if (!cw) return; | |
996 | |
997 if (!ci->pixbuf) collection_load_thumb_idle(cw->cd); | |
998 collection_table_file_insert(cw->table, ci); | |
999 if (!cw) return; | |
1000 } | |
1001 | |
1002 #if 0 | |
1003 static void collection_window_move(CollectWindow *cw, CollectInfo *ci) | |
1004 { | |
1005 if (!cw) return; | |
1006 } | |
1007 #endif | |
1008 | |
1009 static void collection_window_remove(CollectWindow *cw, CollectInfo *ci) | |
1010 { | |
1011 if (!cw) return; | |
1012 | |
1013 collection_table_file_remove(cw->table, ci); | |
1014 } | |
1015 | |
1016 static void collection_window_update(CollectWindow *cw, CollectInfo *ci) | |
1017 { | |
1018 if (!cw) return; | |
1019 | |
1020 collection_table_file_update(cw->table, ci); | |
1021 collection_table_file_update(cw->table, NULL); | |
1022 } | |
1023 | |
1024 static void collection_window_close_final(CollectWindow *cw) | |
1025 { | |
1026 if (cw->close_dialog) return; | |
1027 | |
1028 collection_window_list = g_list_remove(collection_window_list, cw); | |
1029 collection_window_get_geometry(cw); | |
1030 | |
1031 gtk_widget_destroy(cw->window); | |
1032 | |
1033 collection_set_update_info_func(cw->cd, NULL, NULL); | |
1034 collection_unref(cw->cd); | |
1035 | |
1036 g_free(cw); | |
1037 } | |
1038 | |
1039 static void collection_close_save_cb(GenericDialog *gd, gpointer data) | |
1040 { | |
1041 CollectWindow *cw = data; | |
1042 | |
1043 cw->close_dialog = NULL; | |
1044 generic_dialog_close(gd); | |
1045 | |
1046 if (!cw->cd->path) | |
1047 { | |
1048 collection_dialog_save_close(NULL, cw->cd); | |
1049 return; | |
1050 } | |
1051 else if (!collection_save(cw->cd, cw->cd->path)) | |
1052 { | |
1053 gchar *buf; | |
1054 buf = g_strdup_printf(_("Failed to save the collection:\n%s"), cw->cd->path); | |
1055 warning_dialog(_("Save Failed"), buf, GTK_STOCK_DIALOG_ERROR, cw->window); | |
1056 g_free(buf); | |
1057 return; | |
1058 } | |
1059 | |
1060 collection_window_close_final(cw); | |
1061 } | |
1062 | |
1063 static void collection_close_close_cb(GenericDialog *gd, gpointer data) | |
1064 { | |
1065 CollectWindow *cw = data; | |
1066 | |
1067 cw->close_dialog = NULL; | |
1068 generic_dialog_close(gd); | |
1069 | |
1070 collection_window_close_final(cw); | |
1071 } | |
1072 | |
1073 static void collection_close_cancel_cb(GenericDialog *gd, gpointer data) | |
1074 { | |
1075 CollectWindow *cw = data; | |
1076 | |
1077 cw->close_dialog = NULL; | |
1078 generic_dialog_close(gd); | |
1079 } | |
1080 | |
1081 static void collection_close_dlg_show(CollectWindow *cw) | |
1082 { | |
1083 GenericDialog *gd; | |
1084 | |
1085 if (cw->close_dialog) | |
1086 { | |
1087 gtk_window_present(GTK_WINDOW(cw->close_dialog)); | |
1088 return; | |
1089 } | |
1090 | |
1091 gd = generic_dialog_new(_("Close collection"), | |
254
9faf34f047b1
Make the wmclass value unique among the code by defining
zas_
parents:
196
diff
changeset
|
1092 GQ_WMCLASS, "close_collection", cw->window, FALSE, |
9 | 1093 collection_close_cancel_cb, cw); |
1094 generic_dialog_add_message(gd, GTK_STOCK_DIALOG_QUESTION, | |
1095 _("Close collection"), | |
1096 _("Collection has been modified.\nSave first?")); | |
1097 | |
1098 generic_dialog_add_button(gd, GTK_STOCK_SAVE, NULL, collection_close_save_cb, TRUE); | |
1099 generic_dialog_add_button(gd, GTK_STOCK_DELETE, _("_Discard"), collection_close_close_cb, FALSE); | |
1100 | |
1101 cw->close_dialog = gd->dialog; | |
1102 | |
1103 gtk_widget_show(gd->dialog); | |
1104 } | |
1105 | |
1106 static void collection_window_close(CollectWindow *cw) | |
1107 { | |
1108 if (!cw->cd->changed && !cw->close_dialog) | |
1109 { | |
1110 collection_window_close_final(cw); | |
1111 return; | |
1112 } | |
1113 | |
1114 collection_close_dlg_show(cw); | |
1115 } | |
1116 | |
1117 void collection_window_close_by_collection(CollectionData *cd) | |
1118 { | |
1119 CollectWindow *cw; | |
1120 | |
1121 cw = collection_window_find(cd); | |
1122 if (cw) collection_window_close_final(cw); | |
1123 } | |
1124 | |
1125 gint collection_window_modified_exists(void) | |
1126 { | |
1127 GList *work; | |
1128 | |
1129 work = collection_window_list; | |
1130 while (work) | |
1131 { | |
1132 CollectWindow *cw = work->data; | |
1133 if (cw->cd->changed) return TRUE; | |
1134 work = work->next; | |
1135 } | |
1136 | |
1137 return FALSE; | |
1138 } | |
1139 | |
1140 static gint collection_window_delete(GtkWidget *widget, GdkEvent *event, gpointer data) | |
1141 { | |
1142 CollectWindow *cw = data; | |
1143 collection_window_close(cw); | |
1144 | |
1145 return TRUE; | |
1146 } | |
1147 | |
1148 CollectWindow *collection_window_new(const gchar *path) | |
1149 { | |
1150 CollectWindow *cw; | |
1151 GtkWidget *vbox; | |
1152 GtkWidget *frame; | |
1153 GtkWidget *status_label; | |
1154 GtkWidget *extra_label; | |
1155 GdkGeometry geometry; | |
1156 | |
1157 cw = g_new0(CollectWindow, 1); | |
1158 | |
1159 cw->close_dialog = NULL; | |
1160 | |
1161 collection_window_list = g_list_append(collection_window_list, cw); | |
1162 | |
1163 cw->cd = collection_new(path); | |
1164 | |
1165 cw->window = gtk_window_new(GTK_WINDOW_TOPLEVEL); | |
91
d063f97503b7
Wed Nov 1 11:39:48 2006 John Ellis <johne@verizon.net>
gqview
parents:
85
diff
changeset
|
1166 window_set_icon(cw->window, PIXBUF_INLINE_ICON_BOOK, NULL); |
9 | 1167 |
1168 geometry.min_width = 32; | |
1169 geometry.min_height = 32; | |
1170 geometry.base_width = COLLECT_DEF_WIDTH; | |
1171 geometry.base_height = COLLECT_DEF_HEIGHT; | |
1172 gtk_window_set_geometry_hints(GTK_WINDOW(cw->window), NULL, &geometry, | |
1173 GDK_HINT_MIN_SIZE | GDK_HINT_BASE_SIZE); | |
1174 | |
1175 | |
1176 if (save_window_positions && path && collection_load_only_geometry(cw->cd, path)) | |
1177 { | |
1178 /* FIXME: x, y is not implemented */ | |
1179 gtk_window_set_default_size(GTK_WINDOW(cw->window), cw->cd->window_w, cw->cd->window_h); | |
1180 } | |
1181 else | |
1182 { | |
1183 gtk_window_set_default_size(GTK_WINDOW(cw->window), COLLECT_DEF_WIDTH, COLLECT_DEF_HEIGHT); | |
1184 } | |
1185 | |
1186 gtk_window_set_resizable(GTK_WINDOW(cw->window), TRUE); | |
1187 collection_window_update_title(cw); | |
254
9faf34f047b1
Make the wmclass value unique among the code by defining
zas_
parents:
196
diff
changeset
|
1188 gtk_window_set_wmclass(GTK_WINDOW(cw->window), "collection", GQ_WMCLASS); |
9 | 1189 gtk_container_set_border_width (GTK_CONTAINER (cw->window), 0); |
1190 | |
1191 g_signal_connect(G_OBJECT(cw->window), "delete_event", | |
1192 G_CALLBACK(collection_window_delete), cw); | |
1193 | |
1194 g_signal_connect(G_OBJECT(cw->window),"key_press_event", | |
1195 G_CALLBACK(collection_window_keypress), cw); | |
1196 | |
1197 vbox = gtk_vbox_new(FALSE, 0); | |
1198 gtk_container_add(GTK_CONTAINER(cw->window), vbox); | |
1199 gtk_widget_show(vbox); | |
1200 | |
1201 cw->table = collection_table_new(cw->cd); | |
1202 gtk_box_pack_start(GTK_BOX(vbox), cw->table->scrolled, TRUE, TRUE, 0); | |
1203 gtk_widget_show(cw->table->scrolled); | |
1204 | |
1205 cw->status_box = gtk_hbox_new(TRUE, 0); | |
1206 gtk_box_pack_start(GTK_BOX(vbox), cw->status_box, FALSE, FALSE, 0); | |
1207 gtk_widget_show(cw->status_box); | |
1208 | |
1209 frame = gtk_frame_new(NULL); | |
1210 gtk_frame_set_shadow_type(GTK_FRAME(frame), GTK_SHADOW_IN); | |
1211 gtk_box_pack_start(GTK_BOX(cw->status_box), frame, TRUE, TRUE, 0); | |
1212 gtk_widget_show(frame); | |
1213 | |
1214 status_label = gtk_label_new(""); | |
1215 gtk_container_add(GTK_CONTAINER(frame), status_label); | |
1216 gtk_widget_show(status_label); | |
1217 | |
1218 extra_label = gtk_progress_bar_new(); | |
1219 gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(extra_label), 0.0); | |
1220 gtk_box_pack_start(GTK_BOX(cw->status_box), extra_label, TRUE, TRUE, 0); | |
1221 gtk_widget_show(extra_label); | |
1222 | |
1223 collection_table_set_labels(cw->table, status_label, extra_label); | |
1224 | |
1225 gtk_widget_show(cw->window); | |
1226 gtk_widget_grab_focus(cw->table->listview); | |
1227 | |
1228 collection_set_update_info_func(cw->cd, collection_window_update_info, cw); | |
1229 | |
1230 if (path && *path == '/') collection_load_begin(cw->cd, NULL, FALSE); | |
1231 | |
1232 return cw; | |
1233 } | |
1234 |