1 /* -*- Mode: C; tab-width: 3; indent-tabs-mode: nil; c-basic-offset: 3 -*- */
2
3 /*
4 * GImageView
5 * Copyright (C) 2001 Takuro Ashie
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
20 *
21 * $Id: gimv_thumb_view.c,v 1.17 2004/12/20 11:07:31 makeinu Exp $
22 */
23
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <string.h>
27 #include <sys/stat.h>
28 #include <unistd.h>
29
30 #include "gimageview.h"
31
32 #include "charset.h"
33 #include "dirview.h"
34 #include "dnd.h"
35 #include "fileload.h"
36 #include "fileutil.h"
37 #include "gfileutil.h"
38 #include "gtk2-compat.h"
39 #include "gtk_prop.h"
40 #include "gtkutils.h"
41 #include "gimv_comment_view.h"
42 #include "gimv_dupl_finder.h"
43 #include "gimv_dupl_win.h"
44 #include "gimv_image.h"
45 #include "gimv_image_win.h"
46 #include "gimv_scrolled.h"
47 #include "gimv_thumb.h"
48 #include "gimv_thumb_cache.h"
49 #include "gimv_thumb_view.h"
50 #include "gimv_thumb_win.h"
51 #include "menu.h"
52 #include "prefs.h"
53
54 #ifdef ENABLE_EXIF
55 # include "exif_view.h"
56 #endif /* ENABLE_EXIF */
57
58
59 typedef enum
60 {
61 ACTION_NONE,
62 ACTION_POPUP,
63 ACTION_OPEN_AUTO,
64 ACTION_OPEN_AUTO_FORCE,
65 ACTION_OPEN_IN_PREVIEW,
66 ACTION_OPEN_IN_PREVIEW_FORCE,
67 ACTION_OPEN_IN_NEW_WIN,
68 ACTION_OPEN_IN_SHARED_WIN,
69 ACTION_OPEN_IN_SHARED_WIN_FORCE
70 } ButtonActionType;
71
72
73 struct GimvThumbViewPriv_Tag
74 {
75 gchar *dirname; /* store dir name if mode is dirmode */
76 FRArchive *archive;
77
78 /* list of relation to other object */
79 GList *related_image_view;
80 GList *related_dupl_win;
81
82 /* for mouse event */
83 gint button_2pressed_queue; /* attach an action to
84 button release event */
85 };
86
87
88 static void gimv_thumb_view_class_init (GimvThumbViewClass *klass);
89 static void gimv_thumb_view_init (GimvThumbView *tv);
90 static void gimv_thumb_view_destroy (GtkObject *object);
91
92
93 /* callback functions */
94 static void cb_open_image (GimvThumbView *tv,
95 GimvThumbViewOpenImageType action,
96 GtkWidget *menuitem);
97 static void cb_open_image_by_external(GtkWidget *menuitem,
98 GimvThumbView *tv);
99 static void cb_open_image_by_script (GtkWidget *menuitem,
100 GimvThumbView *tv);
101 static void cb_recreate_thumbnail (GimvThumbView *tv,
102 guint action,
103 GtkWidget *menuitem);
104 static void cb_remove_thumbnail (GimvThumbView *tv,
105 guint action,
106 GtkWidget *menuitem);
107 static void cb_file_property (GimvThumbView *tv,
108 guint action,
109 GtkWidget *menuitem);
110 #ifdef ENABLE_EXIF
111 static void cb_exif (GimvThumbView *tv,
112 guint action,
113 GtkWidget *menuitem);
114 #endif /* ENABLE_EXIF */
115 static void cb_edit_comment (GimvThumbView *tv,
116 guint action,
117 GtkWidget *menuitem);
118 static void cb_file_operate (GimvThumbView *tv,
119 FileOperateType type,
120 GtkWidget *widget);
121 static void cb_rename_file (GimvThumbView *tv,
122 guint action,
123 GtkWidget *menuitem);
124 static void cb_remove_file (GimvThumbView *tv,
125 guint action,
126 GtkWidget *menuitem);
127 static void cb_dupl_win_destroy (GtkWidget *window,
128 GimvThumbView *tv);
129 static void cb_thumbview_scrollbar_value_changed
130 (GtkWidget *widget,
131 GimvThumbView *tv);
132
133
134 /* compare functions */
135 static int comp_func_spel (gconstpointer data1,
136 gconstpointer data2);
137 static int comp_func_size (gconstpointer data1,
138 gconstpointer data2);
139 static int comp_func_atime (gconstpointer data1,
140 gconstpointer data2);
141 static int comp_func_mtime (gconstpointer data1,
142 gconstpointer data2);
143 static int comp_func_ctime (gconstpointer data1,
144 gconstpointer data2);
145 static int comp_func_type (gconstpointer data1,
146 gconstpointer data2);
147 static int comp_func_width (gconstpointer data1,
148 gconstpointer data2);
149 static int comp_func_height(gconstpointer data1,
150 gconstpointer data2);
151 static int comp_func_area (gconstpointer data1,
152 gconstpointer data2);
153
154 /* other private functions */
155 static void gimv_thumb_view_append_thumb_data(GimvThumbView *tv,
156 GimvThumb *thumb);
157 static void gimv_thumb_view_remove_thumb_data(GimvThumbView *tv,
158 GimvThumb *thumb);
159 static gchar *get_uri_list (GList *thumblist);
160 static void gimv_thumb_view_button_action (GimvThumbView *tv,
161 GimvThumb *thumb,
162 GdkEventButton *event,
163 gint num);
164 static GtkWidget *create_progs_submenu (GimvThumbView *tv);
165 static GtkWidget *create_scripts_submenu (GimvThumbView *tv);
166 static void gimv_thumb_view_reset_load_priority
167 (GimvThumbView *tv);
168 static void gimv_thumb_view_set_scrollbar_callback
169 (GimvThumbView *tv);
170 static void gimv_thumb_view_remove_scrollbar_callback
171 (GimvThumbView *tv);
172 static GCompareFunc
173 gimv_thumb_view_get_compare_func(GimvThumbView *tv,
174 gboolean *reverse);
175
176
177 /* reference popup menu for each thumbnail */
178 static GtkItemFactoryEntry thumb_button_popup_items [] =
179 {
180 {N_("/_Open"), NULL, cb_open_image, GIMV_THUMB_VIEW_OPEN_IMAGE_AUTO, NULL},
181 {N_("/Open in New _Window"), NULL, cb_open_image, GIMV_THUMB_VIEW_OPEN_IMAGE_NEW_WIN, NULL},
182 {N_("/Open in S_hared Window"), NULL, cb_open_image, GIMV_THUMB_VIEW_OPEN_IMAGE_SHARED_WIN, NULL},
183 {N_("/Open in E_xternal Program"), NULL, NULL, 0, "<Branch>"},
184 {N_("/_Scripts"), NULL, NULL, 0, "<Branch>"},
185 {N_("/---"), NULL, NULL, 0, "<Separator>"},
186 {N_("/_Update Thumbnail"), NULL, cb_recreate_thumbnail, 0, NULL},
187 {N_("/Remo_ve from List"), NULL, cb_remove_thumbnail, 0, NULL},
188 {N_("/---"), NULL, NULL, 0, "<Separator>"},
189 {N_("/_Property..."), NULL, cb_file_property, 0, NULL},
190 #ifdef ENABLE_EXIF
191 {N_("/Scan E_XIF Data..."), NULL, cb_exif, 0, NULL},
192 #endif
193 {N_("/_Edit Comment..."), NULL, cb_edit_comment, 0, NULL},
194 {N_("/---"), NULL, NULL, 0, "<Separator>"},
195 {N_("/Re_name..."), NULL, cb_rename_file, 0, NULL},
196 {N_("/_Copy Files To..."), NULL, cb_file_operate, FILE_COPY, NULL},
197 {N_("/_Move Files To..."), NULL, cb_file_operate, FILE_MOVE, NULL},
198 {N_("/_Link Files To..."), NULL, cb_file_operate, FILE_LINK, NULL},
199 {N_("/_Remove file..."), NULL, cb_remove_file, 0, NULL},
200 {NULL, NULL, NULL, 0, NULL},
201 };
202
203
204 static GList *GimvThumbViewList = NULL;
205
206 static GtkObjectClass *parent_class = NULL;
207
208 static guint total_tab_count = 0;
209
210 static guint button = 0;
211 static gboolean pressed = FALSE;
212 static gboolean dragging = FALSE;
213 static gint drag_start_x = 0;
214 static gint drag_start_y = 0;
215
216
217
218 /****************************************************************************
219 *
220 * Plugin Management
221 *
222 ****************************************************************************/
223 static GList *plugin_list = NULL;
224 static GHashTable *modes_table = NULL;
225 static gchar **mode_labels = NULL;
226 extern GimvThumbViewPlugin thumbalbum_modes[];
227 extern gint thumbalbum_modes_num;
228
229 gint
gimv_thumb_view_label_to_num(const gchar * label)230 gimv_thumb_view_label_to_num(const gchar *label)
231 {
232 GimvThumbViewPlugin *view, *default_view;
233 gint pos;
234
235 g_return_val_if_fail (modes_table, 0);
236
237 if (!label || !*label) return 0;
238
239 view = g_hash_table_lookup (modes_table, label);
240
241 if (!view) {
242 default_view = g_hash_table_lookup (modes_table,
243 GIMV_THUMB_VIEW_DEFAULT_SUMMARY_MODE);
244 g_return_val_if_fail (view && default_view, 0);
245 pos = g_list_index (plugin_list, view);
246 } else {
247 pos = g_list_index (plugin_list, view);
248 }
249
250 if (pos < 0)
251 return 0;
252 else
253 return pos;
254 }
255
256
257 const gchar *
gimv_thumb_view_num_to_label(gint num)258 gimv_thumb_view_num_to_label (gint num)
259 {
260 GimvThumbViewPlugin *view;
261
262 view = g_list_nth_data (plugin_list, num);
263 g_return_val_if_fail (view, NULL);
264
265 return view->label;
266 }
267
268
269 GList *
gimv_thumb_view_get_summary_mode_list(void)270 gimv_thumb_view_get_summary_mode_list (void)
271 {
272 gint i;
273
274 if (!modes_table)
275 modes_table = g_hash_table_new (g_str_hash, g_str_equal);
276
277 if (!plugin_list) {
278 for (i = 0; i < thumbalbum_modes_num; i++) {
279 g_hash_table_insert (modes_table,
280 (gpointer) thumbalbum_modes[i].label,
281 &thumbalbum_modes[i]);
282 plugin_list = g_list_append (plugin_list, &thumbalbum_modes[i]);
283 }
284 }
285
286 return plugin_list;
287 }
288
289
290 gchar **
gimv_thumb_view_get_summary_mode_labels(gint * length_ret)291 gimv_thumb_view_get_summary_mode_labels (gint *length_ret)
292 {
293 gint i, num;
294 gchar **labels;
295 GList *list;
296
297 gimv_thumb_view_get_summary_mode_list ();
298 g_return_val_if_fail (plugin_list, NULL);
299
300 if (mode_labels) {
301 *length_ret = sizeof (mode_labels) / sizeof (gchar *);
302 return mode_labels;
303 }
304
305 num = *length_ret = g_list_length (plugin_list);
306 g_return_val_if_fail (num > 0, NULL);
307
308 mode_labels = labels = g_new0 (gchar *, num + 1);
309 list = plugin_list;
310 for (i = 0; list && i < num; i++) {
311 GimvThumbViewPlugin *view = list->data;
312 if (!view) {
313 g_free (labels);
314 return NULL;
315 }
316 labels[i] = g_strdup (view->label);
317 list = g_list_next (list);
318 }
319 labels[num] = NULL;
320
321 return labels;
322 }
323
324
325 static gint
comp_func_priority(GimvThumbViewPlugin * plugin1,GimvThumbViewPlugin * plugin2)326 comp_func_priority (GimvThumbViewPlugin *plugin1,
327 GimvThumbViewPlugin *plugin2)
328 {
329 g_return_val_if_fail (plugin1, 1);
330 g_return_val_if_fail (plugin2, -1);
331
332 return plugin1->priority_hint - plugin2->priority_hint;
333 }
334
335
336 gboolean
gimv_thumb_view_plugin_regist(const gchar * plugin_name,const gchar * module_name,gpointer impl,gint size)337 gimv_thumb_view_plugin_regist (const gchar *plugin_name,
338 const gchar *module_name,
339 gpointer impl,
340 gint size)
341 {
342 GimvThumbViewPlugin *plugin = impl;
343
344 g_return_val_if_fail (module_name, FALSE);
345 g_return_val_if_fail (plugin, FALSE);
346 g_return_val_if_fail (size > 0, FALSE);
347 g_return_val_if_fail (plugin->if_version == GIMV_THUMBNAIL_VIEW_IF_VERSION,
348 FALSE);
349 g_return_val_if_fail (plugin->label, FALSE);
350
351 if (!plugin_list)
352 gimv_thumb_view_get_summary_mode_list();
353
354 g_hash_table_insert (modes_table,
355 (gpointer) plugin->label,
356 plugin);
357 plugin_list = g_list_append (plugin_list, plugin);
358 plugin_list = g_list_sort (plugin_list,
359 (GCompareFunc) comp_func_priority);
360
361 return TRUE;
362 }
363
364
365 /******************************************************************************
366 *
367 * Callback functions.
368 *
369 ******************************************************************************/
370 static void
cb_open_image(GimvThumbView * tv,GimvThumbViewOpenImageType action,GtkWidget * menuitem)371 cb_open_image (GimvThumbView *tv, GimvThumbViewOpenImageType action,
372 GtkWidget *menuitem)
373 {
374 GimvThumb *thumb;
375 GList *thumblist, *node;
376 gint listnum;
377
378 g_return_if_fail (GIMV_IS_THUMB_VIEW (tv));
379
380 thumblist = gimv_thumb_view_get_selection_list (tv);
381 if (!thumblist) return;
382
383 listnum = g_list_length (thumblist);
384
385 if (action == GIMV_THUMB_VIEW_OPEN_IMAGE_SHARED_WIN) {
386 thumb = thumblist->data;
387 gimv_thumb_view_open_image (tv, thumb, action);
388 } else {
389 FilesLoader *files;
390
391 files = files_loader_new ();
392 if (listnum > 2)
393 files_loader_create_progress_window (files);
394 node = thumblist;
395
396 while (node) {
397 gint pos;
398 gfloat progress;
399 gchar buf[32];
400
401 thumb = node->data;
402 node = g_list_next (node);
403
404 if (files->status == CANCEL || files->status == STOP) break;
405
406 gimv_thumb_view_open_image (tv, thumb, action);
407
408 pos = g_list_position (thumblist, node) + 1;
409 progress = (gfloat) pos / (gfloat) listnum;
410 g_snprintf (buf, 32, "%d/%d files", pos, listnum);
411 files_loader_progress_update (files, progress, buf);
412 }
413
414 files_loader_destroy_progress_window (files);
415 files_loader_delete (files);
416 }
417
418 g_list_free (thumblist);
419 }
420
421
422 static void
cb_open_image_by_external(GtkWidget * menuitem,GimvThumbView * tv)423 cb_open_image_by_external (GtkWidget *menuitem, GimvThumbView *tv)
424 {
425 GimvThumb *thumb;
426 GList *thumblist, *node;
427 guint action;
428 gchar *user_cmd, *cmd = NULL, *tmpstr = NULL, **pair;
429 gboolean show_dialog = FALSE;
430
431 g_return_if_fail (menuitem && GIMV_IS_THUMB_VIEW (tv));
432
433 thumblist = node = gimv_thumb_view_get_selection_list (tv);
434 if (!thumblist) return;
435
436 action = GPOINTER_TO_INT (gtk_object_get_data (GTK_OBJECT (menuitem), "num"));
437
438 /* find command */
439 if (action < sizeof (conf.progs) / sizeof (conf.progs[0])) {
440 pair = g_strsplit (conf.progs[action], ",", 3);
441 if (!pair[1]) {
442 g_strfreev (pair);
443 return;
444 } else {
445 cmd = g_strdup (pair[1]);
446 }
447 if (pair[2] && !g_strcasecmp (pair[2], "TRUE"))
448 show_dialog = TRUE;
449 g_strfreev (pair);
450 } else {
451 return;
452 }
453
454 /* create command string */
455 while (node) {
456 thumb = node->data;
457 tmpstr = g_strconcat (cmd, " ",
458 "\"", gimv_image_info_get_path (thumb->info), "\"",
459 NULL);
460 g_free (cmd);
461 cmd = tmpstr;
462 node = g_list_next (node);
463 }
464 tmpstr = g_strconcat (cmd, " &", NULL);
465 g_free (cmd);
466 cmd = tmpstr;
467 tmpstr = NULL;
468
469 tmpstr = cmd;
470 cmd = charset_to_internal (cmd,
471 conf.charset_filename,
472 conf.charset_auto_detect_fn,
473 conf.charset_filename_mode);
474 g_free (tmpstr);
475 tmpstr = NULL;
476
477 if (show_dialog) {
478 user_cmd = gtkutil_popup_textentry (_("Execute command"),
479 _("Please enter options:"),
480 cmd, NULL, 400,
481 TEXT_ENTRY_AUTOCOMP_PATH
482 | TEXT_ENTRY_WRAP_ENTRY
483 | TEXT_ENTRY_CURSOR_TOP,
484 GTK_WINDOW (tv->tw));
485 } else {
486 user_cmd = g_strdup (cmd);
487 }
488 g_free (cmd);
489 cmd = NULL;
490
491 /* exec command */
492 if (user_cmd) {
493 tmpstr = user_cmd;
494 user_cmd = charset_internal_to_locale (user_cmd);
495 g_free (tmpstr);
496 tmpstr = NULL;
497 system (user_cmd);
498 g_free (user_cmd);
499 }
500
501 g_list_free (thumblist);
502 }
503
504
505 static void
cb_open_image_by_script(GtkWidget * menuitem,GimvThumbView * tv)506 cb_open_image_by_script (GtkWidget *menuitem, GimvThumbView *tv)
507 {
508 GimvThumb *thumb;
509 GList *thumblist, *node;
510 gchar *script, *cmd = NULL, *tmpstr = NULL, *user_cmd;
511
512 g_return_if_fail (menuitem && GIMV_IS_THUMB_VIEW (tv));
513
514 thumblist = node = gimv_thumb_view_get_selection_list (tv);
515 if (!thumblist) return;
516
517 script = gtk_object_get_data (GTK_OBJECT (menuitem), "script");
518 if (!script || !script || !isexecutable (script)) goto ERROR;
519
520 cmd = g_strdup (script);
521
522 /* create command string */
523 while (node) {
524 thumb = node->data;
525 tmpstr = g_strconcat (cmd, " ",
526 "\"", gimv_image_info_get_path (thumb->info), "\"",
527 NULL);
528 g_free (cmd);
529 cmd = tmpstr;
530 node = g_list_next (node);
531 }
532 tmpstr = g_strconcat (cmd, " &", NULL);
533 g_free (cmd);
534 cmd = tmpstr;
535 tmpstr = NULL;
536
537 {
538 tmpstr = cmd;
539 cmd = charset_to_internal (cmd,
540 conf.charset_filename,
541 conf.charset_auto_detect_fn,
542 conf.charset_filename_mode);
543 g_free (tmpstr);
544 tmpstr = NULL;
545
546 if (conf.scripts_show_dialog) {
547 user_cmd = gtkutil_popup_textentry (_("Execute script"),
548 _("Please enter options:"),
549 cmd, NULL, 400,
550 TEXT_ENTRY_AUTOCOMP_PATH
551 | TEXT_ENTRY_WRAP_ENTRY
552 | TEXT_ENTRY_CURSOR_TOP,
553 GTK_WINDOW (tv->tw));
554 } else {
555 user_cmd = g_strdup (cmd);
556 }
557 g_free (cmd);
558 cmd = NULL;
559
560 tmpstr = user_cmd;
561 user_cmd = charset_internal_to_locale (user_cmd);
562 g_free (tmpstr);
563 tmpstr = NULL;
564 }
565
566 /* exec command */
567 if (user_cmd) {
568 { /********** convert charset **********/
569 tmpstr = user_cmd;
570 user_cmd = charset_internal_to_locale (user_cmd);
571 g_free (tmpstr);
572 tmpstr = NULL;
573 }
574 system (user_cmd);
575 g_free (user_cmd);
576 user_cmd = NULL;
577 }
578
579 ERROR:
580 g_list_free (thumblist);
581 }
582
583
584 /* FIXME: context of progress should be displayed */
585 static void
cb_recreate_thumbnail(GimvThumbView * tv,guint action,GtkWidget * menuitem)586 cb_recreate_thumbnail (GimvThumbView *tv, guint action, GtkWidget *menuitem)
587 {
588 GimvThumb *thumb;
589 GList *thumblist, *node;
590
591 g_return_if_fail (GIMV_IS_THUMB_VIEW (tv));
592
593 thumblist = gimv_thumb_view_get_selection_list (tv);
594 if (!thumblist) return;
595
596 for (node = thumblist; node; node = g_list_next (node)) {
597 thumb = node->data;
598 if (!thumb) continue;
599
600 gimv_thumb_view_refresh_thumbnail (tv, thumb, CREATE_THUMB);
601 }
602
603 g_list_free (thumblist);
604 }
605 /* END FIXME */
606
607
608 static void
cb_remove_thumbnail(GimvThumbView * tv,guint action,GtkWidget * menuitem)609 cb_remove_thumbnail (GimvThumbView *tv, guint action, GtkWidget *menuitem)
610 {
611 GimvThumb *thumb;
612 GList *thumblist, *node;
613
614 g_return_if_fail (GIMV_IS_THUMB_VIEW (tv));
615 g_return_if_fail (tv->vfuncs);
616
617 thumblist = gimv_thumb_view_get_selection_list (tv);
618 if (!thumblist) return;
619
620 if (tv->vfuncs->freeze)
621 tv->vfuncs->freeze (tv);
622
623 node = thumblist;
624 while (node) {
625 thumb = node->data;
626 node = g_list_next (node);
627 if (!GIMV_IS_THUMB (thumb)) continue;
628
629 tv->vfuncs->remove_thumb (tv, thumb);
630 gimv_thumb_view_remove_thumb_data (tv, thumb);
631 gtk_object_unref (GTK_OBJECT(thumb));
632 }
633
634 if (tv->vfuncs->thaw)
635 tv->vfuncs->thaw (tv);
636
637 gimv_thumb_win_set_statusbar_page_info (tv->tw,
638 GIMV_THUMB_WIN_CURRENT_PAGE);
639
640 g_list_free (thumblist);
641 }
642
643
644 static void
cb_file_property(GimvThumbView * tv,guint action,GtkWidget * menuitem)645 cb_file_property (GimvThumbView *tv, guint action, GtkWidget *menuitem)
646 {
647 GimvThumb *thumb;
648 GList *thumblist;
649 GimvImageInfo *info;
650 gint flags = 0;
651
652 g_return_if_fail (GIMV_IS_THUMB_VIEW (tv));
653
654 thumblist = gimv_thumb_view_get_selection_list (tv);
655 if (!thumblist || g_list_length (thumblist) > 1) return;
656
657 thumb = thumblist->data;
658 if (!thumb) return;
659
660 info = gimv_image_info_ref (thumb->info);
661 if (!info) return;
662
663 if (tv->mode == GIMV_THUMB_VIEW_MODE_ARCHIVE) {
664 flags |= GTK_PROP_EDITABLE | GTK_PROP_NOT_DETECT_TYPE;
665 }
666
667 if (dlg_prop_from_image_info (info, flags))
668 gimv_thumb_view_refresh_list (tv);
669
670 gimv_image_info_unref (info);
671 }
672
673
674 #ifdef ENABLE_EXIF
675 static void
cb_exif(GimvThumbView * tv,guint action,GtkWidget * menuitem)676 cb_exif (GimvThumbView *tv, guint action, GtkWidget *menuitem)
677 {
678 GimvThumb *thumb;
679 GList *thumblist;
680
681 g_return_if_fail (GIMV_IS_THUMB_VIEW (tv));
682
683 thumblist = gimv_thumb_view_get_selection_list (tv);
684 if (!thumblist || g_list_length (thumblist) > 1) return;
685
686 thumb = thumblist->data;
687 if (!thumb) return;
688
689 exif_view_create_window (gimv_image_info_get_path (thumb->info),
690 GTK_WINDOW (tv->tw));
691 }
692 #endif /* ENABLE_EXIF */
693
694
695 static void
cb_edit_comment(GimvThumbView * tv,guint action,GtkWidget * menuitem)696 cb_edit_comment (GimvThumbView *tv, guint action, GtkWidget *menuitem)
697 {
698 GList *thumblist, *node;
699
700 g_return_if_fail (GIMV_IS_THUMB_VIEW (tv));
701
702 node = thumblist = gimv_thumb_view_get_selection_list (tv);
703 if (!thumblist) return;
704
705 while (node) {
706 GimvThumb *thumb = node->data;
707 node = g_list_next (node);
708
709 if (!thumb) continue;
710
711 gimv_comment_view_create_window (thumb->info);
712 }
713 }
714
715
716 static gchar *previous_dir = NULL;
717
718
719 static void
cb_file_operate(GimvThumbView * tv,FileOperateType type,GtkWidget * widget)720 cb_file_operate (GimvThumbView *tv, FileOperateType type, GtkWidget *widget)
721 {
722 g_return_if_fail (GIMV_IS_THUMB_VIEW (tv));
723 gimv_thumb_view_file_operate (tv, type);
724 }
725
726
727 static void
cb_rename_file(GimvThumbView * tv,guint action,GtkWidget * menuitem)728 cb_rename_file (GimvThumbView *tv, guint action, GtkWidget *menuitem)
729 {
730 g_return_if_fail (GIMV_IS_THUMB_VIEW (tv));
731 gimv_thumb_view_rename_file (tv);
732 }
733
734
735 static void
cb_remove_file(GimvThumbView * tv,guint action,GtkWidget * menuitem)736 cb_remove_file (GimvThumbView *tv, guint action, GtkWidget *menuitem)
737 {
738 g_return_if_fail (GIMV_IS_THUMB_VIEW (tv));
739 gimv_thumb_view_delete_files (tv);
740 }
741
742
743 static void
cb_dupl_win_destroy(GtkWidget * window,GimvThumbView * tv)744 cb_dupl_win_destroy (GtkWidget *window, GimvThumbView *tv)
745 {
746 g_return_if_fail (GIMV_IS_THUMB_VIEW (tv));
747
748 if (!tv->priv) return;
749
750 tv->priv->related_dupl_win
751 = g_list_remove (tv->priv->related_dupl_win, window);
752 }
753
754
755 static void
cb_thumbview_scrollbar_value_changed(GtkWidget * widget,GimvThumbView * tv)756 cb_thumbview_scrollbar_value_changed (GtkWidget *widget,
757 GimvThumbView *tv)
758 {
759 g_return_if_fail (GIMV_IS_THUMB_VIEW (tv));
760
761 gimv_thumb_view_reset_load_priority (tv);
762 }
763
764
765 typedef struct GimvThumbViewButtonAction_Tag
766 {
767 GimvThumbView *tv;
768 GimvThumb *thumb;
769 GdkEventButton event;
770 gint action;
771 } GimvThumbViewButtonAction;
772
773
774 static gint
idle_button_action(gpointer data)775 idle_button_action (gpointer data)
776 {
777 GimvThumbViewButtonAction *act = data;
778 g_return_val_if_fail (act, 0);
779 gimv_thumb_view_button_action (act->tv, act->thumb,
780 &act->event, act->action);
781 return 0;
782 }
783
784
785 gboolean
gimv_thumb_view_thumb_button_press_cb(GtkWidget * widget,GdkEventButton * event,GimvThumb * thumb)786 gimv_thumb_view_thumb_button_press_cb (GtkWidget *widget,
787 GdkEventButton *event,
788 GimvThumb *thumb)
789 {
790 GimvThumbView *tv;
791 GimvThumbWin *tw;
792 gint num;
793
794 g_return_val_if_fail (event, FALSE);
795
796 button = event->button;
797 pressed = TRUE;
798 drag_start_x = event->x;
799 drag_start_y = event->y;
800
801 if (!thumb) goto ERROR;
802 g_return_val_if_fail (GIMV_IS_THUMB (thumb), FALSE);
803
804 tv = gimv_thumb_get_parent_thumbview (thumb);
805 g_return_val_if_fail (GIMV_IS_THUMB_VIEW (tv), FALSE);
806
807 tw = tv->tw;
808 g_return_val_if_fail (GIMV_IS_THUMB_WIN (tw), FALSE);
809
810 gimv_thumb_win_notebook_drag_src_unset (tw); /* FIXMEEEEEEEE!! */
811
812 /* reset selection */
813 if (event->type == GDK_BUTTON_PRESS
814 && (event->button == 2 || event->button == 3))
815 {
816 if (!thumb->selected) {
817 gimv_thumb_view_set_selection_all (tv, FALSE);
818 gimv_thumb_view_set_selection (thumb, TRUE);
819 }
820 }
821
822 while (gtk_events_pending()) gtk_main_iteration();
823
824 num = prefs_mouse_get_num_from_event (event, conf.thumbview_mouse_button);
825 if (event->type == GDK_2BUTTON_PRESS) {
826 tv->priv->button_2pressed_queue = num;
827 } else if (num > 0) {
828 GimvThumbViewButtonAction *act = g_new0 (GimvThumbViewButtonAction, 1);
829
830 act->tv = tv;
831 act->thumb = thumb;
832 act->event = *event;
833 act->action = num;
834 gtk_idle_add_full (GTK_PRIORITY_REDRAW,
835 idle_button_action, NULL, act,
836 (GtkDestroyNotify) g_free);
837 }
838
839 ERROR:
840 if (event->button == 3) /* for avoiding notebook's event */
841 return TRUE;
842 else
843 return FALSE;
844 }
845
846
847 gboolean
gimv_thumb_view_thumb_button_release_cb(GtkWidget * widget,GdkEventButton * event,GimvThumb * thumb)848 gimv_thumb_view_thumb_button_release_cb (GtkWidget *widget,
849 GdkEventButton *event,
850 GimvThumb *thumb)
851 {
852 GimvThumbView *tv;
853 GimvThumbWin *tw;
854 gint num;
855
856 g_return_val_if_fail (event, FALSE);
857
858 if (!thumb) goto ERROR;
859 g_return_val_if_fail (GIMV_IS_THUMB (thumb), FALSE);
860
861 tv = gimv_thumb_get_parent_thumbview (thumb);
862 g_return_val_if_fail (GIMV_IS_THUMB_VIEW (tv), FALSE);
863
864 tw = tv->tw;
865 g_return_val_if_fail (GIMV_IS_THUMB_WIN (tw), FALSE);
866
867 gimv_thumb_win_notebook_drag_src_reset (tw); /* FIXMEEEEEEEEE!!! */
868
869 if(pressed && !dragging) {
870 if (tv->priv->button_2pressed_queue) {
871 num = tv->priv->button_2pressed_queue;
872 if (num > 0)
873 num = 0 - num;
874 tv->priv->button_2pressed_queue = 0;
875 } else {
876 num = prefs_mouse_get_num_from_event (event,
877 conf.thumbview_mouse_button);
878 }
879 if (num < 0) {
880 GimvThumbViewButtonAction *act = g_new0 (GimvThumbViewButtonAction, 1);
881 act->tv = tv;
882 act->thumb = thumb;
883 act->event = *event;
884 act->action = num;
885 gtk_idle_add_full (GTK_PRIORITY_REDRAW,
886 idle_button_action, NULL, act,
887 (GtkDestroyNotify) g_free);
888 }
889 }
890
891 ERROR:
892 button = 0;
893 pressed = FALSE;
894 dragging = FALSE;
895
896 if (event->button == 3) /* for avoiding notebook's callback */
897 return TRUE;
898 else
899 return FALSE;
900 }
901
902
903 gboolean
gimv_thumb_view_thumb_key_press_cb(GtkWidget * widget,GdkEventKey * event,GimvThumb * thumb)904 gimv_thumb_view_thumb_key_press_cb (GtkWidget *widget,
905 GdkEventKey *event,
906 GimvThumb *thumb)
907 {
908 guint keyval, popup_key = 0;
909 GdkModifierType modval, popup_mod = 0;
910
911 g_return_val_if_fail (event, FALSE);
912
913 keyval = event->keyval;
914 modval = event->state;
915
916 if (akey.common_popup_menu || *akey.common_popup_menu)
917 gtk_accelerator_parse (akey.common_popup_menu, &popup_key, &popup_mod);
918
919 if (keyval == popup_key && (!popup_mod || (modval & popup_mod))) {
920 GimvThumbView *tv = gimv_thumb_get_parent_thumbview (thumb);
921 g_return_val_if_fail (GIMV_IS_THUMB_VIEW (tv), FALSE);
922 gimv_thumb_view_popup_menu (tv, NULL, NULL);
923 return TRUE;
924 }
925
926 return FALSE;
927 }
928
929
930 gboolean
gimv_thumb_view_thumb_key_release_cb(GtkWidget * widget,GdkEventKey * event,GimvThumb * thumb)931 gimv_thumb_view_thumb_key_release_cb (GtkWidget *widget,
932 GdkEventKey *event,
933 GimvThumb *thumb)
934 {
935 g_return_val_if_fail (event, FALSE);
936 return FALSE;
937 }
938
939
940 gboolean
gimv_thumb_view_motion_notify_cb(GtkWidget * widget,GdkEventMotion * event,GimvThumb * thumb)941 gimv_thumb_view_motion_notify_cb (GtkWidget *widget,
942 GdkEventMotion *event,
943 GimvThumb *thumb)
944 {
945 GimvThumbView *tv;
946 GimvThumbWin *tw;
947 gint dx, dy;
948
949 g_return_val_if_fail (event, FALSE);
950
951 if (thumb) {
952 tv = gimv_thumb_get_parent_thumbview (thumb);
953 g_return_val_if_fail (GIMV_IS_THUMB_VIEW (tv), FALSE);
954
955 tw = tv->tw;
956 g_return_val_if_fail (GIMV_IS_THUMB_WIN (tw), FALSE);
957 }
958
959 if (!pressed)
960 return FALSE;
961
962 dx = event->x - drag_start_x;
963 dy = event->y - drag_start_y;
964
965 if (!dragging && (abs (dx) > 2 || abs (dy) > 2))
966 dragging = TRUE;
967
968 /* return TRUE; */
969 return FALSE;
970 }
971
972
973 void
gimv_thumb_view_drag_begin_cb(GtkWidget * widget,GdkDragContext * context,gpointer data)974 gimv_thumb_view_drag_begin_cb (GtkWidget *widget,
975 GdkDragContext *context,
976 gpointer data)
977 {
978 GimvThumbView *tv = data;
979 GimvThumb *thumb;
980 GList *thumblist;
981 GdkPixmap *pixmap;
982 GdkBitmap *mask;
983 GdkColormap *colormap;
984
985 g_return_if_fail (GIMV_IS_THUMB_VIEW (tv) && widget);
986
987 thumblist = gimv_thumb_view_get_selection_list (tv);
988 if (!thumblist) return;
989
990 thumb = thumblist->data;
991 gimv_thumb_get_icon (thumb, &pixmap, &mask);
992 if (g_list_length (thumblist) == 1 && pixmap) {
993 colormap = gdk_colormap_get_system ();
994 gtk_drag_set_icon_pixmap (context, colormap, pixmap, mask, -7, -7);
995 }
996 }
997
998
999 void
gimv_thumb_view_drag_data_get_cb(GtkWidget * widget,GdkDragContext * context,GtkSelectionData * seldata,guint info,guint time,gpointer data)1000 gimv_thumb_view_drag_data_get_cb (GtkWidget *widget,
1001 GdkDragContext *context,
1002 GtkSelectionData *seldata,
1003 guint info,
1004 guint time,
1005 gpointer data)
1006 {
1007 GimvThumbView *tv = data;
1008 GList *thumblist;
1009 gchar *uri_list;
1010
1011 g_return_if_fail (GIMV_IS_THUMB_VIEW (tv) && widget);
1012
1013 thumblist = gimv_thumb_view_get_selection_list (tv);
1014
1015 if (!thumblist) {
1016 gtkutil_message_dialog (_("Error!!"), _("No files specified!!"),
1017 GTK_WINDOW (tv->tw));
1018 return;
1019 }
1020
1021 switch (info) {
1022 case TARGET_URI_LIST:
1023 if (!thumblist) return;
1024 uri_list = get_uri_list (thumblist);
1025 gtk_selection_data_set(seldata, seldata->target,
1026 8, uri_list, strlen(uri_list));
1027 g_free (uri_list);
1028 break;
1029 default:
1030 break;
1031 }
1032 }
1033
1034
1035 void
gimv_thumb_view_drag_data_received_cb(GtkWidget * widget,GdkDragContext * context,gint x,gint y,GtkSelectionData * seldata,guint info,guint time,gpointer data)1036 gimv_thumb_view_drag_data_received_cb (GtkWidget *widget,
1037 GdkDragContext *context,
1038 gint x, gint y,
1039 GtkSelectionData *seldata,
1040 guint info,
1041 guint time,
1042 gpointer data)
1043 {
1044 GimvThumbView *tv = data;
1045 FilesLoader *files;
1046 GList *list;
1047 GtkWidget *src_widget;
1048 GimvThumbView *src_tab = NULL, *dest_tab = NULL;
1049
1050 g_return_if_fail (GIMV_IS_THUMB_VIEW (tv) && widget);
1051
1052 src_widget = gtk_drag_get_source_widget (context);
1053 if (src_widget == widget) return;
1054
1055 if (src_widget)
1056 src_tab = gtk_object_get_data (GTK_OBJECT (src_widget), "gimv-tab");
1057 dest_tab = gtk_object_get_data (GTK_OBJECT (widget), "gimv-tab");
1058 if (src_tab == dest_tab) return;
1059
1060 if (tv->mode == GIMV_THUMB_VIEW_MODE_DIR) {
1061 gchar *dirname;
1062
1063 if (tv->dnd_destdir)
1064 dirname = tv->dnd_destdir;
1065 else
1066 dirname = tv->priv->dirname;
1067
1068 if (iswritable (dirname)) {
1069 dnd_file_operation (dirname, context, seldata,
1070 time, tv->tw);
1071 } else {
1072 gchar error_message[BUF_SIZE], *dir_internal;
1073
1074 dir_internal = charset_to_internal (dirname,
1075 conf.charset_filename,
1076 conf.charset_auto_detect_fn,
1077 conf.charset_filename_mode);
1078 g_snprintf (error_message, BUF_SIZE,
1079 _("Permission denied: %s"),
1080 dir_internal);
1081 gtkutil_message_dialog (_("Error!!"), error_message,
1082 GTK_WINDOW (tv->tw));
1083
1084 g_free (dir_internal);
1085 }
1086 tv->dnd_destdir = NULL;
1087
1088 } else if (tv->mode == GIMV_THUMB_VIEW_MODE_COLLECTION) {
1089 list = dnd_get_file_list (seldata->data, seldata->length);
1090 files = files_loader_new ();
1091 files->filelist = list;
1092 gimv_thumb_view_append_thumbnail (tv, files, FALSE);
1093 files_loader_delete (files);
1094 }
1095 }
1096
1097
1098 void
gimv_thumb_view_drag_end_cb(GtkWidget * widget,GdkDragContext * drag_context,gpointer data)1099 gimv_thumb_view_drag_end_cb (GtkWidget *widget, GdkDragContext *drag_context,
1100 gpointer data)
1101 {
1102 GimvThumbView *tv = data;
1103
1104 g_return_if_fail (GIMV_IS_THUMB_VIEW (tv));
1105
1106 if (conf.dnd_refresh_list_always) {
1107 /* gimv_thumb_view_refresh_list (tv); */
1108 /* to avoid gtk's bug, exec redraw after exit this callback function */
1109 gtk_idle_add (gimv_thumb_view_refresh_list_idle, tv);
1110 }
1111 }
1112
1113
1114 void
gimv_thumb_view_drag_data_delete_cb(GtkWidget * widget,GdkDragContext * drag_context,gpointer data)1115 gimv_thumb_view_drag_data_delete_cb (GtkWidget *widget,
1116 GdkDragContext *drag_context,
1117 gpointer data)
1118 {
1119 GimvThumbView *tv = data;
1120
1121 g_return_if_fail (GIMV_IS_THUMB_VIEW (tv));
1122
1123 if (!conf.dnd_refresh_list_always)
1124 gimv_thumb_view_refresh_list (tv);
1125 }
1126
1127
1128
1129 /******************************************************************************
1130 *
1131 * Compare functions.
1132 *
1133 ******************************************************************************/
1134 /* sort by spel */
1135 static int
comp_func_spel(gconstpointer data1,gconstpointer data2)1136 comp_func_spel (gconstpointer data1, gconstpointer data2)
1137 {
1138 GimvThumb *thumb1, *thumb2;
1139 GimvThumbView *tv;
1140 const gchar *filename1, *filename2;
1141 gboolean ignore_dir;
1142 gint comp;
1143 GimvSortItem item;
1144 GimvSortFlag flags;
1145
1146 thumb1 = (GimvThumb *) data1;
1147 thumb2 = (GimvThumb *) data2;
1148
1149 filename1 = gimv_image_info_get_path (thumb1->info);
1150 filename2 = gimv_image_info_get_path (thumb2->info);
1151
1152 tv = gimv_thumb_get_parent_thumbview (thumb1);
1153 g_return_val_if_fail(GIMV_IS_THUMB_VIEW (tv), 0);
1154 item = gimv_thumb_win_get_sort_type (tv->tw, &flags);
1155 ignore_dir = flags & GIMV_SORT_DIR_INSENSITIVE;
1156
1157 if (!filename1 || !*filename1)
1158 return -1;
1159 else if (!filename2 || !*filename2)
1160 return 1;
1161
1162 if (filename1 && !strcmp ("..", g_basename (filename1))) {
1163 comp = -1;
1164 } else if (filename2 && !strcmp ("..", g_basename (filename2))) {
1165 comp = 1;
1166 } else if (!ignore_dir && isdir (filename1) && !isdir (filename2)) {
1167 comp = -1;
1168 } else if (!ignore_dir && !isdir (filename1) && isdir (filename2)) {
1169 comp = 1;
1170 } else {
1171 if (flags & GIMV_SORT_CASE_INSENSITIVE)
1172 comp = g_strcasecmp ((gchar *) filename1, (gchar *) filename2);
1173 else
1174 comp = strcmp ((gchar *) filename1, (gchar *) filename2);
1175 }
1176
1177 return comp;
1178 }
1179
1180
1181 /* sort by file size */
1182 static int
comp_func_size(gconstpointer data1,gconstpointer data2)1183 comp_func_size (gconstpointer data1, gconstpointer data2)
1184 {
1185 GimvThumb *thumb1, *thumb2;
1186 int retval;
1187
1188 thumb1 = (GimvThumb *) data1;
1189 thumb2 = (GimvThumb *) data2;
1190
1191 if (!thumb1)
1192 return -1;
1193 else if (!thumb2)
1194 return 1;
1195
1196 retval = thumb1->info->st.st_size - thumb2->info->st.st_size;
1197
1198 if (retval == 0)
1199 return comp_func_spel (data1, data2);
1200 else
1201 return retval;
1202 }
1203
1204
1205 /* sort by time of las access */
1206 static int
comp_func_atime(gconstpointer data1,gconstpointer data2)1207 comp_func_atime (gconstpointer data1, gconstpointer data2)
1208 {
1209 GimvThumb *thumb1, *thumb2;
1210 int retval;
1211
1212 thumb1 = (GimvThumb *) data1;
1213 thumb2 = (GimvThumb *) data2;
1214
1215 if (!thumb1)
1216 return -1;
1217 else if (!thumb2)
1218 return 1;
1219
1220 retval = thumb1->info->st.st_atime - thumb2->info->st.st_atime;
1221
1222 if (retval == 0)
1223 return comp_func_spel (data1, data2);
1224 else
1225 return retval;
1226 }
1227
1228
1229 /* sort by time of last modification */
1230 static int
comp_func_mtime(gconstpointer data1,gconstpointer data2)1231 comp_func_mtime (gconstpointer data1, gconstpointer data2)
1232 {
1233 GimvThumb *thumb1, *thumb2;
1234 int retval;
1235
1236 thumb1 = (GimvThumb *) data1;
1237 thumb2 = (GimvThumb *) data2;
1238
1239 if (!thumb1)
1240 return -1;
1241 else if (!thumb2)
1242 return 1;
1243
1244 retval = thumb1->info->st.st_mtime - thumb2->info->st.st_mtime;
1245
1246 if (retval == 0)
1247 return comp_func_spel (data1, data2);
1248 else
1249 return retval;
1250 }
1251
1252
1253 /* sort by time of last change */
1254 static int
comp_func_ctime(gconstpointer data1,gconstpointer data2)1255 comp_func_ctime (gconstpointer data1, gconstpointer data2)
1256 {
1257 GimvThumb *thumb1, *thumb2;
1258 int retval;
1259
1260 thumb1 = (GimvThumb *) data1;
1261 thumb2 = (GimvThumb *) data2;
1262
1263 if (!thumb1)
1264 return -1;
1265 else if (!thumb2)
1266 return 1;
1267
1268 retval = thumb1->info->st.st_ctime - thumb2->info->st.st_ctime;
1269
1270 if (retval == 0)
1271 return comp_func_spel (data1, data2);
1272 else
1273 return retval;
1274 }
1275
1276
1277 /* sort by time of file name extension */
1278 static int
comp_func_type(gconstpointer data1,gconstpointer data2)1279 comp_func_type (gconstpointer data1, gconstpointer data2)
1280 {
1281 GimvThumb *thumb1, *thumb2;
1282 const gchar *file1, *file2, *ext1, *ext2;
1283 int retval;
1284
1285 thumb1 = (GimvThumb *) data1;
1286 thumb2 = (GimvThumb *) data2;
1287
1288 if (!thumb1)
1289 return -1;
1290 else if (!thumb2)
1291 return 1;
1292
1293 file1 = gimv_image_info_get_path (thumb1->info);
1294 file2 = gimv_image_info_get_path (thumb2->info);
1295
1296 if (!file1 || !*file1)
1297 return -1;
1298 else if (!file2 || !*file2)
1299 return 1;
1300
1301 ext1 = strrchr (file1, '.');
1302 if (ext1 && *ext1)
1303 ext1++;
1304 else
1305 ext1 = NULL;
1306
1307 ext2 = strrchr (file2, '.');
1308 if (ext2 && *ext2)
1309 ext2++;
1310 else
1311 ext2 = NULL;
1312
1313 if ((!ext1 || !*ext1) && (!ext2 || !*ext2)) {
1314 return g_strcasecmp (file1, file2);
1315 } else if (!ext1 || !*ext1) {
1316 return -1;
1317 } else if (!ext2 || !*ext2) {
1318 return 1;
1319 }
1320
1321 retval = g_strcasecmp (ext1, ext2);
1322
1323 if (retval == 0)
1324 return comp_func_spel (data1, data2);
1325 else
1326 return retval;
1327 }
1328
1329
1330 /* sort by image width */
1331 static int
comp_func_width(gconstpointer data1,gconstpointer data2)1332 comp_func_width (gconstpointer data1, gconstpointer data2)
1333 {
1334 GimvThumb *thumb1, *thumb2;
1335 int retval;
1336
1337 thumb1 = (GimvThumb *) data1;
1338 thumb2 = (GimvThumb *) data2;
1339
1340 if (!thumb1)
1341 return -1;
1342 else if (!thumb2)
1343 return 1;
1344
1345 retval = thumb1->info->width - thumb2->info->width;
1346
1347 if (retval == 0)
1348 return comp_func_spel (data1, data2);
1349 else
1350 return retval;
1351 }
1352
1353
1354 /* sort by image height */
1355 static int
comp_func_height(gconstpointer data1,gconstpointer data2)1356 comp_func_height (gconstpointer data1, gconstpointer data2)
1357 {
1358 GimvThumb *thumb1, *thumb2;
1359 int retval;
1360
1361 thumb1 = (GimvThumb *) data1;
1362 thumb2 = (GimvThumb *) data2;
1363
1364 if (!thumb1)
1365 return -1;
1366 else if (!thumb2)
1367 return 1;
1368
1369 retval = thumb1->info->height - thumb2->info->height;
1370
1371 if (retval == 0)
1372 return comp_func_spel (data1, data2);
1373 else
1374 return retval;
1375 }
1376
1377
1378 /* sort by image width */
1379 static int
comp_func_area(gconstpointer data1,gconstpointer data2)1380 comp_func_area (gconstpointer data1, gconstpointer data2)
1381 {
1382 GimvThumb *thumb1, *thumb2;
1383 int retval, area1, area2;
1384
1385 thumb1 = (GimvThumb *) data1;
1386 thumb2 = (GimvThumb *) data2;
1387
1388 if (!thumb1)
1389 return -1;
1390 else if (!thumb2)
1391 return 1;
1392
1393 area1 = thumb1->info->width * thumb1->info->height;
1394 if (thumb1->info->width < 0 && thumb1->info->height < 0)
1395 area1 = 0 - area1;
1396 area2 = thumb2->info->width * thumb2->info->height;
1397 if (thumb2->info->width < 0 && thumb2->info->height < 0)
1398 area2 = 0 - area2;
1399
1400 retval = area1 - area2;
1401
1402 if (retval == 0)
1403 return comp_func_spel (data1, data2);
1404 else
1405 return retval;
1406 }
1407
1408
1409
1410 /******************************************************************************
1411 *
1412 * Other Private Functions.
1413 *
1414 ******************************************************************************/
1415 static gint
progress_timeout(gpointer data)1416 progress_timeout (gpointer data)
1417 {
1418 gfloat new_val;
1419 GtkAdjustment *adj;
1420
1421 adj = GTK_PROGRESS (data)->adjustment;
1422
1423 new_val = adj->value + 1;
1424 if (new_val > adj->upper)
1425 new_val = adj->lower;
1426
1427 gtk_progress_set_value (GTK_PROGRESS (data), new_val);
1428
1429 return (TRUE);
1430 }
1431
1432
1433 static gboolean
gimv_thumb_view_extract_archive_file(GimvThumb * thumb)1434 gimv_thumb_view_extract_archive_file (GimvThumb *thumb)
1435 {
1436 GimvThumbWin *tw;
1437 GimvThumbView *tv;
1438 FilesLoader *files;
1439 guint timer;
1440 gboolean success;
1441
1442 g_return_val_if_fail (GIMV_IS_THUMB (thumb), FALSE);
1443
1444 tv = gimv_thumb_get_parent_thumbview (thumb);
1445 g_return_val_if_fail (GIMV_IS_THUMB_VIEW (tv), FALSE);
1446
1447 if (tv->mode != GIMV_THUMB_VIEW_MODE_ARCHIVE) return FALSE;
1448
1449 tw = tv->tw;
1450 g_return_val_if_fail (tw, FALSE);
1451
1452 files = files_loader_new ();
1453 tv->status = GIMV_THUMB_VIEW_STATUS_LOADING;
1454 files->archive = gimv_image_info_get_archive (thumb->info);
1455 if (files->archive)
1456 fr_archive_ref (files->archive);
1457
1458 /* set progress bar */
1459 gtk_progress_set_activity_mode (GTK_PROGRESS (tw->progressbar), TRUE);
1460 timer = gtk_timeout_add (50, (GtkFunction)progress_timeout, tw->progressbar);
1461
1462 /* extract */
1463 success = gimv_image_info_extract_archive (thumb->info);
1464
1465 /* unset progress bar */
1466 gtk_timeout_remove (timer);
1467 gtk_progress_set_activity_mode (GTK_PROGRESS (tw->progressbar), FALSE);
1468 gtk_progress_bar_update (GTK_PROGRESS_BAR(tw->progressbar), 0.0);
1469
1470 tv->status = GIMV_THUMB_VIEW_STATUS_NORMAL;
1471 files_loader_delete (files);
1472
1473 return success;
1474 }
1475
1476
1477 static void
gimv_thumb_view_append_thumb_data(GimvThumbView * tv,GimvThumb * thumb)1478 gimv_thumb_view_append_thumb_data (GimvThumbView *tv, GimvThumb *thumb)
1479 {
1480 g_return_if_fail (GIMV_IS_THUMB_VIEW (tv));
1481
1482 tv->thumblist = g_list_append (tv->thumblist, thumb);
1483
1484 /* update file num info */
1485 tv->tw->filenum++;
1486 tv->tw->filesize += thumb->info->st.st_size;
1487 tv->filenum++;
1488 tv->filesize += thumb->info->st.st_size;
1489 }
1490
1491
1492 static void
gimv_thumb_view_remove_thumb_data(GimvThumbView * tv,GimvThumb * thumb)1493 gimv_thumb_view_remove_thumb_data (GimvThumbView *tv, GimvThumb *thumb)
1494 {
1495 g_return_if_fail (GIMV_IS_THUMB_VIEW (tv));
1496 g_return_if_fail (g_list_find (tv->thumblist, thumb));
1497
1498 /* update file num info */
1499 tv->tw->filenum--;
1500 tv->tw->filesize -= thumb->info->st.st_size;
1501 tv->filenum--;
1502 tv->filesize -= thumb->info->st.st_size;
1503
1504 tv->thumblist = g_list_remove (tv->thumblist, thumb);
1505 }
1506
1507
1508 static void
gimv_thumb_view_insert_thumb_frames(GimvThumbView * tv,GList * filelist)1509 gimv_thumb_view_insert_thumb_frames (GimvThumbView *tv, GList *filelist)
1510 {
1511 GimvThumb *thumb;
1512 GList *node, *new_thumb_list = NULL;
1513
1514 g_return_if_fail (GIMV_IS_THUMB_VIEW (tv));
1515 if (!filelist) return;
1516 g_return_if_fail (tv->vfuncs);
1517
1518 for (node = filelist; node; node = g_list_next (node)) {
1519 gchar *filename = node->data;
1520
1521 if (file_exists(node->data)) {
1522 GimvImageInfo *info = gimv_image_info_get (filename);
1523
1524 thumb = gimv_thumb_new (info);
1525 gimv_image_info_unref (info);
1526 gimv_thumb_set_parent_thumbview (thumb, tv);
1527
1528 gimv_thumb_view_append_thumb_data (tv, thumb);
1529
1530 new_thumb_list = g_list_append (new_thumb_list, thumb);
1531 }
1532 }
1533
1534 gimv_thumb_view_sort_data (tv);
1535
1536 for (node = new_thumb_list; node; node = g_list_next (node))
1537 tv->vfuncs->insert_thumb (tv, node->data, tv->summary_mode);
1538 g_list_free(new_thumb_list);
1539 }
1540
1541
1542 static void
gimv_thumb_view_insert_thumb_frames_from_archive(GimvThumbView * tv,FRArchive * archive)1543 gimv_thumb_view_insert_thumb_frames_from_archive (GimvThumbView *tv,
1544 FRArchive *archive)
1545 {
1546 GimvThumb *thumb;
1547 FRCommand *command;
1548 GList *node, *new_thumb_list = NULL;
1549
1550 g_return_if_fail (GIMV_IS_THUMB_VIEW (tv));
1551 if (!archive) return;
1552 g_return_if_fail (tv->vfuncs);
1553
1554 command = archive->command;
1555 g_return_if_fail (command);
1556
1557 for (node = command->file_list; node; node = g_list_next (node)) {
1558 GimvImageInfo *info = node->data;
1559
1560 if (!info) continue;
1561
1562 /* detect filename extension */
1563 if (conf.detect_filetype_by_ext
1564 && !gimv_image_detect_type_by_ext (info->filename)
1565 && !fr_archive_utils_get_file_name_ext (info->filename))
1566 {
1567 continue;
1568 }
1569
1570 thumb = gimv_thumb_new (info);
1571 gimv_thumb_set_parent_thumbview (thumb, tv);
1572
1573 gimv_thumb_view_append_thumb_data (tv, thumb);
1574
1575 new_thumb_list = g_list_append (new_thumb_list, thumb);
1576 }
1577
1578 gimv_thumb_view_sort_data (tv);
1579
1580 for (node = new_thumb_list; node; node = g_list_next (node))
1581 tv->vfuncs->insert_thumb (tv, node->data, tv->summary_mode);
1582 g_list_free(new_thumb_list);
1583 }
1584
1585
1586 static gchar *
get_uri_list(GList * thumblist)1587 get_uri_list (GList *thumblist)
1588 {
1589 gchar *path;
1590 gchar *uri;
1591 GList *node;
1592 GimvThumb *thumb;
1593
1594 if (!thumblist) return NULL;
1595
1596 uri = g_strdup ("");
1597 node = thumblist;
1598 while (node) {
1599 gchar *filename = NULL;
1600
1601 thumb = node->data;
1602
1603 filename = gimv_image_info_get_path_with_archive (thumb->info);
1604 path = g_strconcat (uri, "file://", filename, "\r\n", NULL);
1605 g_free (filename);
1606 g_free (uri);
1607 uri = g_strdup (path);
1608 g_free (path);
1609
1610 node = g_list_next (node);
1611 }
1612
1613 return uri;
1614 }
1615
1616
1617 typedef struct ChangeImageData_Tag
1618 {
1619 GimvThumbWin *tw;
1620 GimvImageWin *iw;
1621 GimvImageView *iv;
1622 GimvThumb *thumb;
1623 } ChangeImageData;
1624
1625
1626 static gboolean
change_image_idle(gpointer user_data)1627 change_image_idle (gpointer user_data)
1628 {
1629 ChangeImageData *data = user_data;
1630
1631 if (data->iw) {
1632 gimv_image_win_change_image (data->iw, data->thumb->info);
1633 } else {
1634 gimv_image_view_change_image (data->iv, data->thumb->info);
1635 }
1636
1637 return FALSE;
1638 }
1639
1640
1641 static GList *
next_image(GimvImageView * iv,gpointer list_owner,GList * current,gpointer data)1642 next_image (GimvImageView *iv, gpointer list_owner,
1643 GList *current, gpointer data)
1644 {
1645 GimvImageWin *iw = data;
1646 GList *next, *node;
1647 GimvThumb *thumb;
1648 GimvThumbView *tv = list_owner;
1649 GimvThumbWin *tw;
1650 ChangeImageData *change_data;
1651
1652 g_return_val_if_fail (GIMV_IS_IMAGE_VIEW (iv), NULL);
1653 g_return_val_if_fail (current, NULL);
1654
1655 node = g_list_find (GimvThumbViewList, tv);
1656 g_return_val_if_fail (node, NULL);
1657
1658 node = g_list_find (tv->thumblist, current->data);
1659 g_return_val_if_fail (node, NULL);
1660
1661 next = g_list_next (current);
1662 if (!next) next = g_list_first (current);
1663 g_return_val_if_fail (next, NULL);
1664
1665 while (next && next != current) {
1666 GimvThumb *nthumb = next->data;
1667 GList *temp;
1668
1669 if (!gimv_image_info_is_dir (nthumb->info)
1670 && !gimv_image_info_is_archive (nthumb->info))
1671 {
1672 break;
1673 }
1674
1675 temp = g_list_next (next);
1676 if (!temp)
1677 next = g_list_first (next);
1678 else
1679 next = temp;
1680 }
1681 if (!next) next = current;
1682
1683 thumb = next->data;
1684 g_return_val_if_fail (GIMV_IS_THUMB (thumb), NULL);
1685
1686 tw = tv->tw;
1687 g_return_val_if_fail (GIMV_IS_THUMB_WIN (tw), NULL);
1688
1689 gimv_thumb_view_set_selection_all (tv, FALSE);
1690 gimv_thumb_view_set_selection (thumb, TRUE);
1691 gimv_thumb_view_adjust (tv, thumb);
1692
1693 if (tv->mode == GIMV_THUMB_VIEW_MODE_ARCHIVE) {
1694 gboolean success = gimv_thumb_view_extract_archive_file (thumb);
1695 g_return_val_if_fail (success, next);
1696 }
1697
1698 change_data = g_new0 (ChangeImageData, 1);
1699 change_data->tw = tw;
1700 change_data->iw = iw;
1701 change_data->iv = iv;
1702 change_data->thumb = thumb;
1703 gtk_idle_add_full (GTK_PRIORITY_DEFAULT,
1704 change_image_idle,
1705 NULL,
1706 change_data,
1707 (GtkDestroyNotify) g_free);
1708
1709 if (!iw)
1710 gimv_comment_view_change_file (tw->cv, thumb->info);
1711
1712 return next;
1713 }
1714
1715
1716 static GList *
prev_image(GimvImageView * iv,gpointer list_owner,GList * current,gpointer data)1717 prev_image (GimvImageView *iv, gpointer list_owner,
1718 GList *current, gpointer data)
1719 {
1720 GimvImageWin *iw = data;
1721 GList *prev, *node;
1722 GimvThumb *thumb;
1723 GimvThumbView *tv = list_owner;
1724 GimvThumbWin *tw;
1725 ChangeImageData *change_data;
1726
1727 g_return_val_if_fail (GIMV_IS_IMAGE_VIEW (iv), NULL);
1728 g_return_val_if_fail (current, NULL);
1729
1730 node = g_list_find (GimvThumbViewList, tv);
1731 g_return_val_if_fail (node, NULL);
1732
1733 node = g_list_find (tv->thumblist, current->data);
1734 g_return_val_if_fail (node, NULL);
1735
1736 prev = g_list_previous (current);
1737 if (!prev) prev = g_list_last (current);
1738 g_return_val_if_fail (prev, NULL);
1739
1740 while (prev && prev != current) {
1741 GimvThumb *nthumb = prev->data;
1742 GList *temp;
1743
1744 if (!gimv_image_info_is_dir (nthumb->info)
1745 && !gimv_image_info_is_archive (nthumb->info))
1746 {
1747 break;
1748 }
1749
1750 temp = g_list_previous (prev);
1751 if (!temp)
1752 prev = g_list_last (prev);
1753 else
1754 prev = temp;
1755 }
1756 if (!prev) prev = current;
1757
1758 thumb = prev->data;
1759 g_return_val_if_fail (GIMV_IS_THUMB (thumb), NULL);
1760
1761 tw = tv->tw;
1762 g_return_val_if_fail (GIMV_IS_THUMB_WIN (tw), NULL);
1763
1764 gimv_thumb_view_set_selection_all (tv, FALSE);
1765 gimv_thumb_view_set_selection (thumb, TRUE);
1766 gimv_thumb_view_adjust (tv, thumb);
1767
1768 if (tv->mode == GIMV_THUMB_VIEW_MODE_ARCHIVE) {
1769 gboolean success = gimv_thumb_view_extract_archive_file (thumb);
1770 g_return_val_if_fail (success, prev);
1771 }
1772
1773 change_data = g_new0 (ChangeImageData, 1);
1774 change_data->tw = tw;
1775 change_data->iw = iw;
1776 change_data->iv = iv;
1777 change_data->thumb = thumb;
1778 gtk_idle_add_full (GTK_PRIORITY_DEFAULT,
1779 change_image_idle,
1780 NULL,
1781 change_data,
1782 (GtkDestroyNotify) g_free);
1783
1784 if (!iw)
1785 gimv_comment_view_change_file (tw->cv, thumb->info);
1786
1787 return prev;
1788 }
1789
1790
1791 static GList *
nth_image(GimvImageView * iv,gpointer list_owner,GList * current,guint nth,gpointer data)1792 nth_image (GimvImageView *iv,
1793 gpointer list_owner,
1794 GList *current,
1795 guint nth,
1796 gpointer data)
1797 {
1798 GimvImageWin *iw = data;
1799 GList *node;
1800 GimvThumb *thumb;
1801 GimvThumbView *tv = list_owner;
1802 GimvThumbWin *tw;
1803 ChangeImageData *change_data;
1804
1805 /* check check chek ... */
1806 g_return_val_if_fail (GIMV_IS_IMAGE_VIEW (iv), NULL);
1807 g_return_val_if_fail (current, NULL);
1808
1809 node = g_list_find (GimvThumbViewList, tv);
1810 g_return_val_if_fail (node, NULL);
1811
1812 node = g_list_find (tv->thumblist, current->data);
1813 g_return_val_if_fail (node, NULL);
1814
1815 tw = tv->tw;
1816 g_return_val_if_fail (tw, NULL);
1817
1818 /* get nth of list */
1819 node = g_list_nth (tv->thumblist, nth);
1820 g_return_val_if_fail (node, NULL);
1821
1822 thumb = node->data;
1823 g_return_val_if_fail (GIMV_IS_THUMB (thumb), NULL);
1824
1825 gimv_thumb_view_set_selection_all (tv, FALSE);
1826 gimv_thumb_view_set_selection (thumb, TRUE);
1827 gimv_thumb_view_adjust (tv, thumb);
1828
1829 /* show image */
1830 if (tv->mode == GIMV_THUMB_VIEW_MODE_ARCHIVE) {
1831 gboolean success = gimv_thumb_view_extract_archive_file (thumb);
1832 g_return_val_if_fail (success, node);
1833 }
1834
1835 change_data = g_new0 (ChangeImageData, 1);
1836 change_data->tw = tw;
1837 change_data->iw = iw;
1838 change_data->iv = iv;
1839 change_data->thumb = thumb;
1840 gtk_idle_add_full (GTK_PRIORITY_DEFAULT,
1841 change_image_idle,
1842 NULL,
1843 change_data,
1844 (GtkDestroyNotify) g_free);
1845
1846 if (!iw)
1847 gimv_comment_view_change_file (tw->cv, thumb->info);
1848
1849 return node;
1850 }
1851
1852
1853 static void
cb_imageview_thumbnail_created(GimvImageView * iv,GimvImageInfo * info,GimvThumbView * tv)1854 cb_imageview_thumbnail_created (GimvImageView *iv,
1855 GimvImageInfo *info,
1856 GimvThumbView *tv)
1857 {
1858 GList *node;
1859 GimvThumb *thumb = NULL;
1860
1861 g_return_if_fail (GIMV_IS_IMAGE_VIEW (iv));
1862 g_return_if_fail (info);
1863 g_return_if_fail (GIMV_IS_THUMB_VIEW (tv));
1864
1865 node = tv->thumblist;
1866 while (node) {
1867 thumb = node->data;
1868 node = g_list_next (node);
1869
1870 if (gimv_image_info_is_same (thumb->info, info))
1871 break;
1872 else
1873 thumb = NULL;
1874 }
1875
1876 if (thumb)
1877 gimv_thumb_view_refresh_thumbnail (tv, thumb, LOAD_CACHE);
1878 }
1879
1880
1881 static void
remove_list(GimvImageView * iv,gpointer list_owner,gpointer data)1882 remove_list (GimvImageView *iv, gpointer list_owner, gpointer data)
1883 {
1884 GimvThumbView *tv = list_owner;
1885 GList *node;
1886
1887 g_return_if_fail (GIMV_IS_IMAGE_VIEW (iv));
1888 g_return_if_fail (GIMV_IS_THUMB_VIEW (tv));
1889
1890 gtk_signal_disconnect_by_func (
1891 GTK_OBJECT (iv),
1892 GTK_SIGNAL_FUNC (cb_imageview_thumbnail_created),
1893 tv);
1894
1895 node = g_list_find (GimvThumbViewList, tv);
1896 if (!node) return;
1897
1898 if (tv->priv)
1899 tv->priv->related_image_view
1900 = g_list_remove (tv->priv->related_image_view, iv);
1901 }
1902
1903
1904 static void
gimv_thumb_view_button_action(GimvThumbView * tv,GimvThumb * thumb,GdkEventButton * event,gint num)1905 gimv_thumb_view_button_action (GimvThumbView *tv,
1906 GimvThumb *thumb,
1907 GdkEventButton *event,
1908 gint num)
1909 {
1910 GimvThumbWin *tw;
1911
1912 g_return_if_fail (GIMV_IS_THUMB_VIEW (tv));
1913
1914 tw = tv->tw;
1915 g_return_if_fail (GIMV_IS_THUMB_WIN (tw));
1916
1917 if (gimv_image_info_is_dir (thumb->info)
1918 || gimv_image_info_is_archive (thumb->info))
1919 {
1920 switch (abs (num)) {
1921 case ACTION_OPEN_AUTO:
1922 num = ACTION_OPEN_AUTO_FORCE;
1923 break;
1924 case ACTION_OPEN_IN_PREVIEW:
1925 num = ACTION_OPEN_IN_PREVIEW_FORCE;
1926 break;
1927 case ACTION_OPEN_IN_SHARED_WIN:
1928 num = ACTION_OPEN_IN_SHARED_WIN_FORCE;
1929 break;
1930 default:
1931 break;
1932 }
1933 }
1934
1935 switch (abs (num)) {
1936 case ACTION_POPUP:
1937 gimv_thumb_view_popup_menu (tv, thumb, event);
1938
1939 /* FIXME */
1940 if (GIMV_IS_SCROLLED (GTK_BIN (tv->container)->child))
1941 gimv_scrolled_stop_auto_scroll (GIMV_SCROLLED (GTK_BIN (tv->container)->child));
1942
1943 break;
1944
1945 case ACTION_OPEN_AUTO:
1946 if (tw->show_preview || gimv_image_win_get_shared_window())
1947 gimv_thumb_view_open_image (tv, thumb,
1948 GIMV_THUMB_VIEW_OPEN_IMAGE_AUTO);
1949 break;
1950
1951 case ACTION_OPEN_AUTO_FORCE:
1952 gimv_thumb_view_open_image (tv, thumb,
1953 GIMV_THUMB_VIEW_OPEN_IMAGE_AUTO);
1954 break;
1955
1956 case ACTION_OPEN_IN_PREVIEW:
1957 if (tw->show_preview)
1958 gimv_thumb_view_open_image (tv, thumb,
1959 GIMV_THUMB_VIEW_OPEN_IMAGE_PREVIEW);
1960 break;
1961
1962 case ACTION_OPEN_IN_PREVIEW_FORCE:
1963 if (!tw->show_preview)
1964 gimv_thumb_win_open_preview (tw);
1965 gimv_thumb_view_open_image (tv, thumb,
1966 GIMV_THUMB_VIEW_OPEN_IMAGE_PREVIEW);
1967 break;
1968
1969 case ACTION_OPEN_IN_NEW_WIN:
1970 gimv_thumb_view_open_image (tv, thumb,
1971 GIMV_THUMB_VIEW_OPEN_IMAGE_NEW_WIN);
1972 break;
1973
1974 case ACTION_OPEN_IN_SHARED_WIN:
1975 if (gimv_image_win_get_shared_window())
1976 gimv_thumb_view_open_image (tv, thumb,
1977 GIMV_THUMB_VIEW_OPEN_IMAGE_SHARED_WIN);
1978 break;
1979
1980 case ACTION_OPEN_IN_SHARED_WIN_FORCE:
1981 gimv_thumb_view_open_image (tv, thumb,
1982 GIMV_THUMB_VIEW_OPEN_IMAGE_SHARED_WIN);
1983 break;
1984
1985 default:
1986 break;
1987 }
1988 }
1989
1990
1991 static GtkWidget *
create_progs_submenu(GimvThumbView * tv)1992 create_progs_submenu (GimvThumbView *tv)
1993 {
1994 GtkWidget *menu;
1995 GtkWidget *menu_item;
1996 gint i, conf_num = sizeof (conf.progs) / sizeof (conf.progs[0]);
1997 gchar **pair;
1998
1999 menu = gtk_menu_new();
2000
2001 /* count items num */
2002 for (i = 0; i < conf_num; i++) {
2003 if (!conf.progs[i]) continue;
2004
2005 pair = g_strsplit (conf.progs[i], ",", 3);
2006
2007 if (pair[0] && pair[1]) {
2008 gchar *label;
2009
2010 if (pair[2] && !strcasecmp (pair[2], "TRUE"))
2011 label = g_strconcat (pair[0], "...", NULL);
2012 else
2013 label = g_strdup (pair[0]);
2014
2015 menu_item = gtk_menu_item_new_with_label (label);
2016 gtk_object_set_data (GTK_OBJECT (menu_item), "num", GINT_TO_POINTER (i));
2017 gtk_signal_connect (GTK_OBJECT (menu_item), "activate",
2018 GTK_SIGNAL_FUNC (cb_open_image_by_external), tv);
2019 gtk_menu_append (GTK_MENU (menu), menu_item);
2020 gtk_widget_show (menu_item);
2021
2022 g_free (label);
2023 }
2024
2025 g_strfreev (pair);
2026 }
2027
2028 return menu;
2029 }
2030
2031
2032 void
gimv_thumb_view_open_image(GimvThumbView * tv,GimvThumb * thumb,gint type)2033 gimv_thumb_view_open_image (GimvThumbView *tv, GimvThumb *thumb, gint type)
2034 {
2035 GimvThumbWin *tw;
2036 GimvImageWin *iw = NULL;
2037 GimvImageView *iv = NULL;
2038 GList *current, *node;
2039 const gchar *image_name, *ext;
2040 gchar *filename, *tmpstr;
2041
2042 g_return_if_fail (GIMV_IS_THUMB_VIEW (tv) && thumb);
2043
2044 tw = tv->tw;
2045 g_return_if_fail (GIMV_IS_THUMB_WIN (tw));
2046
2047 image_name = gimv_image_info_get_path (thumb->info);
2048 g_return_if_fail (image_name && *image_name);
2049 filename = g_strdup (image_name);
2050
2051 if (!strcmp ("..", g_basename (filename))) {
2052 tmpstr = filename;
2053 filename = g_dirname (filename);
2054 g_free (tmpstr);
2055 if (filename) {
2056 tmpstr = filename;
2057 filename = g_dirname (filename);
2058 g_free (tmpstr);
2059 }
2060 tmpstr = NULL;
2061 }
2062
2063 /* open directory */
2064 if (isdir (filename)) {
2065 #warning FIXME!!!! Use this tab?
2066 open_dir_images (filename, tw, NULL, LOAD_CACHE, conf.scan_dir_recursive);
2067 g_free (filename);
2068 return;
2069 }
2070
2071 /* extract image in archive */
2072 if (tv->mode == GIMV_THUMB_VIEW_MODE_ARCHIVE) {
2073 gboolean success = gimv_thumb_view_extract_archive_file (thumb);
2074 if (!success) {
2075 g_free (filename);
2076 return;
2077 }
2078 }
2079
2080 /* open archive */
2081 ext = fr_archive_utils_get_file_name_ext (filename);
2082 if (ext) {
2083 open_archive_images (filename, tw, NULL, LOAD_CACHE);
2084 g_free (filename);
2085 return;
2086 }
2087
2088 /* open the image */
2089 if ((type == GIMV_THUMB_VIEW_OPEN_IMAGE_AUTO && tw->show_preview)
2090 || type == GIMV_THUMB_VIEW_OPEN_IMAGE_PREVIEW)
2091 {
2092 iv = tw->iv;
2093 gimv_comment_view_change_file (tw->cv, thumb->info);
2094 gimv_image_view_change_image (iv, thumb->info);
2095
2096 } else if (gimv_image_win_get_shared_window() &&
2097 ((type == GIMV_THUMB_VIEW_OPEN_IMAGE_AUTO && !conf.imgwin_open_new_win)
2098 ||type == GIMV_THUMB_VIEW_OPEN_IMAGE_SHARED_WIN))
2099 {
2100 iw = gimv_image_win_open_shared_window (thumb->info);
2101 if (iw)
2102 iv = iw->iv;
2103
2104 } else {
2105 if (type == GIMV_THUMB_VIEW_OPEN_IMAGE_SHARED_WIN) {
2106 iw = gimv_image_win_open_shared_window (thumb->info);
2107 } else if (type == GIMV_THUMB_VIEW_OPEN_IMAGE_AUTO) {
2108 iw = gimv_image_win_open_window_auto (thumb->info);
2109 } else {
2110 iw = gimv_image_win_open_window (thumb->info);
2111 }
2112 if (iw)
2113 iv = iw->iv;
2114 }
2115
2116 if (iv && g_list_find (gimv_image_view_get_list(), iv)) {
2117 current = g_list_find (tv->thumblist, thumb);
2118 gimv_image_view_set_list (iv, tv->thumblist, current,
2119 (gpointer) tv,
2120 next_image,
2121 prev_image,
2122 nth_image,
2123 remove_list,
2124 iw);
2125 gtk_signal_connect (GTK_OBJECT (iv), "thumbnail_created",
2126 GTK_SIGNAL_FUNC (cb_imageview_thumbnail_created), tv);
2127 node = g_list_find (tv->priv->related_image_view, iv);
2128 if (!node) {
2129 gint num;
2130 tv->priv->related_image_view
2131 = g_list_append (tv->priv->related_image_view, iv);
2132 num = g_list_length (tv->priv->related_image_view);
2133 }
2134 }
2135
2136 g_free (filename);
2137 }
2138
2139
2140 void
gimv_thumb_view_popup_menu(GimvThumbView * tv,GimvThumb * thumb,GdkEventButton * event)2141 gimv_thumb_view_popup_menu (GimvThumbView *tv, GimvThumb *thumb,
2142 GdkEventButton *event)
2143 {
2144 GtkWidget *popup_menu, *progs_submenu, *scripts_submenu;
2145 GList *thumblist = NULL, *node;
2146 guint n_menu_items;
2147 GtkItemFactory *ifactory;
2148 GtkWidget *menuitem;
2149 gchar *dirname;
2150 guint button;
2151 guint32 time;
2152 GtkMenuPositionFunc pos_fn = NULL;
2153
2154 g_return_if_fail (GIMV_IS_THUMB_VIEW (tv));
2155
2156 if (event) {
2157 button = event->button;
2158 time = gdk_event_get_time ((GdkEvent *) event);
2159 } else {
2160 button = 0;
2161 time = GDK_CURRENT_TIME;
2162 pos_fn = menu_calc_popup_position;
2163 }
2164
2165 if (tv->popup_menu) {
2166 gtk_widget_unref (tv->popup_menu);
2167 tv->popup_menu = NULL;
2168 }
2169
2170 thumblist = node = gimv_thumb_view_get_selection_list (tv);
2171 if (!thumblist) return;
2172
2173 if (!thumb) thumb = thumblist->data;
2174 g_return_if_fail (GIMV_IS_THUMB (thumb));
2175
2176 /* create popup menu */
2177 n_menu_items = sizeof(thumb_button_popup_items)
2178 / sizeof(thumb_button_popup_items[0]) - 1;
2179 popup_menu = menu_create_items(GTK_WIDGET (tv->tw),
2180 thumb_button_popup_items, n_menu_items,
2181 "<ThumbnailButtonPop>", tv);
2182
2183 /* set sensitive */
2184 ifactory = gtk_item_factory_from_widget (popup_menu);
2185
2186 menuitem = gtk_item_factory_get_item (ifactory, "/Open");
2187 if (!gimv_image_info_is_dir (thumb->info)
2188 && !gimv_image_info_is_archive (thumb->info))
2189 {
2190 gtk_widget_hide (menuitem);
2191 }
2192
2193 menuitem = gtk_item_factory_get_item (ifactory, "/Open in New Window");
2194 if (gimv_image_info_is_dir (thumb->info)
2195 || gimv_image_info_is_archive (thumb->info))
2196 {
2197 gtk_widget_hide (menuitem);
2198 }
2199
2200 menuitem = gtk_item_factory_get_item (ifactory, "/Open in Shared Window");
2201 if (gimv_image_info_is_dir (thumb->info)
2202 || gimv_image_info_is_archive (thumb->info))
2203 {
2204 gtk_widget_hide (menuitem);
2205 } else if (g_list_length (thumblist) > 1) {
2206 gtk_widget_set_sensitive (menuitem, FALSE);
2207 }
2208
2209 menuitem = gtk_item_factory_get_item (ifactory, "/Open in External Program");
2210 if (/* thumbnail_is_dir (thumb) || thumbnail_is_archive (thumb) */
2211 gimv_image_info_is_in_archive (thumb->info))
2212 {
2213 gtk_widget_hide (menuitem);
2214 } else {
2215 progs_submenu = create_progs_submenu (tv);
2216 menu_set_submenu (popup_menu, "/Open in External Program", progs_submenu);
2217 }
2218
2219 menuitem = gtk_item_factory_get_item (ifactory, "/Scripts");
2220 if (/* thumbnail_is_dir (thumb) || thumbnail_is_archive (thumb) */
2221 gimv_image_info_is_in_archive (thumb->info))
2222 {
2223 gtk_widget_hide (menuitem);
2224 } else {
2225 scripts_submenu = create_scripts_submenu (tv);
2226 menu_set_submenu (popup_menu, "/Scripts", scripts_submenu);
2227 }
2228
2229 #warning FIXME!!
2230 menuitem = gtk_item_factory_get_item (ifactory, "/Update Thumbnail");
2231 if (gimv_image_info_is_dir (thumb->info)
2232 || gimv_image_info_is_archive (thumb->info)
2233 || gimv_image_info_is_movie (thumb->info))
2234 {
2235 gtk_widget_set_sensitive (menuitem, FALSE);
2236 }
2237
2238 menuitem = gtk_item_factory_get_item (ifactory, "/Remove from List");
2239 if (tv->progress || tv->mode != GIMV_THUMB_VIEW_MODE_COLLECTION) {
2240 gtk_widget_set_sensitive (menuitem, FALSE);
2241 }
2242
2243 dirname = g_dirname (gimv_image_info_get_path (thumb->info));
2244 if (g_list_length (thumblist) < 1 || !iswritable (dirname)
2245 || tv->mode == GIMV_THUMB_VIEW_MODE_ARCHIVE)
2246 {
2247 if (g_list_length (thumblist) < 1) {
2248 menuitem = gtk_item_factory_get_item (ifactory, "/Property...");
2249 gtk_widget_set_sensitive (menuitem, FALSE);
2250 }
2251 menuitem = gtk_item_factory_get_item (ifactory, "/Move Files To...");
2252 gtk_widget_set_sensitive (menuitem, FALSE);
2253 menuitem = gtk_item_factory_get_item (ifactory, "/Rename...");
2254 gtk_widget_set_sensitive (menuitem, FALSE);
2255 menuitem = gtk_item_factory_get_item (ifactory, "/Remove file...");
2256 gtk_widget_set_sensitive (menuitem, FALSE);
2257 }
2258 g_free (dirname);
2259
2260 if (tv->mode == GIMV_THUMB_VIEW_MODE_ARCHIVE) {
2261 menuitem = gtk_item_factory_get_item (ifactory, "/Copy Files To...");
2262 gtk_widget_set_sensitive (menuitem, FALSE);
2263 menuitem = gtk_item_factory_get_item (ifactory, "/Link Files To...");
2264 gtk_widget_set_sensitive (menuitem, FALSE);
2265 }
2266
2267 if (g_list_length (thumblist) > 1) {
2268 menuitem = gtk_item_factory_get_item (ifactory, "/Property...");
2269 gtk_widget_set_sensitive (menuitem, FALSE);
2270 menuitem = gtk_item_factory_get_item (ifactory, "/Rename...");
2271 gtk_widget_set_sensitive (menuitem, FALSE);
2272 }
2273
2274 #ifdef ENABLE_EXIF
2275 {
2276 const gchar *img_name = gimv_image_info_get_path (thumb->info);
2277 const gchar *format = gimv_image_detect_type_by_ext (img_name);
2278 menuitem = gtk_item_factory_get_item (ifactory, "/Scan EXIF Data...");
2279 #warning FIXME!!
2280 if (!format || !*format || g_strcasecmp(format, "image/jpeg")) {
2281 gtk_widget_hide (menuitem);
2282 }
2283 if (g_list_length (thumblist) > 1
2284 || tv->mode == GIMV_THUMB_VIEW_MODE_ARCHIVE)
2285 {
2286 gtk_widget_set_sensitive (menuitem, FALSE);
2287 }
2288 }
2289 #endif /* ENABLE_EXIF */
2290
2291 /* popup */
2292 gtk_menu_popup(GTK_MENU(popup_menu), NULL, NULL,
2293 NULL, NULL, button, time);
2294
2295 tv->popup_menu = popup_menu;
2296 #ifdef USE_GTK2
2297 gtk_object_ref (GTK_OBJECT (tv->popup_menu));
2298 gtk_object_sink (GTK_OBJECT (tv->popup_menu));
2299 #endif
2300
2301 g_list_free (thumblist);
2302 }
2303
2304
2305 void
gimv_thumb_view_file_operate(GimvThumbView * tv,FileOperateType type)2306 gimv_thumb_view_file_operate (GimvThumbView *tv, FileOperateType type)
2307 {
2308 GList *list = NULL;
2309 gboolean success = FALSE;
2310
2311 g_return_if_fail (GIMV_IS_THUMB_VIEW (tv));
2312
2313 /* FIXME!! */
2314 /* not implemented yet */
2315 if (tv->mode == GIMV_THUMB_VIEW_MODE_ARCHIVE) return;
2316
2317 list = gimv_thumb_view_get_selected_file_list (tv);
2318 if (!list) return;
2319
2320 if (!previous_dir && tv->mode == GIMV_THUMB_VIEW_MODE_DIR) {
2321 previous_dir = g_strdup (tv->priv->dirname);
2322 }
2323
2324 success = files2dir_with_dialog (list, &previous_dir, type,
2325 GTK_WINDOW (tv->tw));
2326
2327 if (success && type == FILE_MOVE) {
2328 gimv_thumb_view_refresh_list (tv);
2329 }
2330
2331 /* update dest side file list */
2332 tv = gimv_thumb_view_find_opened_dir (previous_dir);
2333 if (tv) {
2334 gimv_thumb_view_refresh_list (tv);
2335 }
2336
2337 g_list_foreach (list, (GFunc) g_free, NULL);
2338 g_list_free (list);
2339 }
2340
2341
2342 void
gimv_thumb_view_rename_file(GimvThumbView * tv)2343 gimv_thumb_view_rename_file (GimvThumbView *tv)
2344 {
2345 GimvThumb *thumb;
2346 const gchar *cache_type;
2347 GList *thumblist;
2348 const gchar *src_file;
2349 gchar *dest_file, *dest_path;
2350 gchar *src_cache_path, *dest_cache_path;
2351 gchar *src_comment, *dest_comment;
2352 gchar message[BUF_SIZE], *dirname;
2353 ConfirmType confirm;
2354 gboolean exist;
2355 struct stat dest_st;
2356
2357 g_return_if_fail (GIMV_IS_THUMB_VIEW (tv));
2358
2359 /* FIXME!! */
2360 /* not implemented yet */
2361 if (tv->mode == GIMV_THUMB_VIEW_MODE_ARCHIVE) return;
2362
2363 thumblist = gimv_thumb_view_get_selection_list (tv);
2364 if (!thumblist || g_list_length (thumblist) > 1) return;
2365
2366 thumb = thumblist->data;
2367 if (!thumb) return;
2368
2369 { /********** convert charset **********/
2370 gchar *tmpstr, *src_file_internal;
2371
2372 src_file = g_basename(gimv_image_info_get_path (thumb->info));
2373 src_file_internal = charset_to_internal (src_file,
2374 conf.charset_filename,
2375 conf.charset_auto_detect_fn,
2376 conf.charset_filename_mode);
2377
2378 tmpstr = gtkutil_popup_textentry (_("Rename a file"),
2379 _("New file name: "),
2380 src_file_internal, NULL, -1, 0,
2381 GTK_WINDOW (tv->tw));
2382 g_free (src_file_internal);
2383 src_file_internal = NULL;
2384
2385 if (!tmpstr) return;
2386
2387 dest_file = charset_internal_to_locale (tmpstr);
2388 g_free (tmpstr);
2389 }
2390
2391 if (!strcmp (src_file, dest_file)) goto ERROR0;
2392
2393 dirname = g_dirname (gimv_image_info_get_path (thumb->info));
2394 dest_path = g_strconcat (dirname, "/", g_basename (dest_file), NULL);
2395 g_free (dirname);
2396 exist = !lstat(dest_path, &dest_st);
2397 if (exist) {
2398 { /********** convert charset **********/
2399 gchar *tmpstr;
2400
2401 tmpstr = charset_to_internal (src_file,
2402 conf.charset_filename,
2403 conf.charset_auto_detect_fn,
2404 conf.charset_filename_mode);
2405
2406 g_snprintf (message, BUF_SIZE,
2407 _("File exist : %s\n\n"
2408 "Overwrite?"), tmpstr);
2409
2410 g_free (tmpstr);
2411 }
2412
2413 confirm = gtkutil_confirm_dialog (_("File exist!!"), message, 0,
2414 GTK_WINDOW (tv->tw));
2415 if (confirm == CONFIRM_NO) goto ERROR1;
2416 }
2417
2418 /* rename file!! */
2419 if (rename (gimv_image_info_get_path (thumb->info), dest_path) < 0) {
2420 { /********** convert charset **********/
2421 gchar *tmpstr;
2422
2423 tmpstr = charset_to_internal (gimv_image_info_get_path (thumb->info),
2424 conf.charset_filename,
2425 conf.charset_auto_detect_fn,
2426 conf.charset_filename_mode);
2427
2428 g_snprintf (message, BUF_SIZE,
2429 _("Faild to rename file :\n%s"),
2430 tmpstr);
2431
2432 g_free (tmpstr);
2433 }
2434
2435 gtkutil_message_dialog (_("Error!!"), message,
2436 GTK_WINDOW (tv->tw));
2437 }
2438
2439 /* rename cache */
2440 cache_type = gimv_thumb_get_cache_type (thumb);
2441 if (cache_type) {
2442 src_cache_path
2443 = gimv_thumb_cache_get_path (gimv_image_info_get_path (thumb->info),
2444 cache_type);
2445 dest_cache_path
2446 = gimv_thumb_cache_get_path (dest_path, cache_type);
2447 if (rename (src_cache_path, dest_cache_path) < 0)
2448 g_print (_("Faild to rename cache file :%s\n"), dest_path);
2449 g_free (src_cache_path);
2450 g_free (dest_cache_path);
2451 }
2452
2453 /* rename comment */
2454 src_comment = gimv_comment_find_file (gimv_image_info_get_path (thumb->info));
2455 if (src_comment) {
2456 dest_comment = gimv_comment_get_path (dest_path);
2457 if (rename (src_comment, dest_comment) < 0)
2458 g_print (_("Faild to rename comment file :%s\n"), dest_comment);
2459 g_free (src_comment);
2460 g_free (dest_comment);
2461 }
2462
2463 gimv_thumb_view_refresh_list (tv);
2464
2465 ERROR1:
2466 g_free (dest_path);
2467 ERROR0:
2468 g_free (dest_file);
2469 }
2470
2471
2472 gboolean
gimv_thumb_view_delete_files(GimvThumbView * tv)2473 gimv_thumb_view_delete_files (GimvThumbView *tv)
2474 {
2475 GimvThumbWin *tw;
2476 GList *selection;
2477 GList *filelist = NULL, *list;
2478 gboolean retval;
2479
2480 g_return_val_if_fail (GIMV_IS_THUMB_VIEW (tv), FALSE);
2481
2482 /* FIXME!! */
2483 /* not implemented yet */
2484 if (tv->mode == GIMV_THUMB_VIEW_MODE_ARCHIVE) return FALSE;
2485
2486 tw = tv->tw;
2487 g_return_val_if_fail (GIMV_IS_THUMB_WIN (tw), FALSE);
2488
2489 selection = gimv_thumb_view_get_selection_list (tv);
2490 if (!selection) return FALSE;
2491
2492 /* convert to filename list */
2493 for (list = selection; list; list = g_list_next (list)) {
2494 GimvThumb *thumb = list->data;
2495 const gchar *filename;
2496
2497 if (!thumb) continue;
2498 filename = gimv_image_info_get_path (thumb->info);
2499 if (filename && *filename)
2500 filelist = g_list_append (filelist, (gpointer) filename);
2501 }
2502
2503 /* do delete */
2504 retval = delete_files (filelist, CONFIRM_ASK,
2505 GTK_WINDOW (tv->tw));
2506
2507 if (retval) {
2508 gimv_thumb_view_refresh_list (tv);
2509 if (tw->show_dirview)
2510 dirview_refresh_list (tw->dv);
2511 }
2512
2513 g_list_free (filelist);
2514 g_list_free (selection);
2515
2516 return retval;
2517 }
2518
2519
2520 static GtkWidget *
create_scripts_submenu(GimvThumbView * tv)2521 create_scripts_submenu (GimvThumbView *tv)
2522 {
2523 GtkWidget *menu;
2524 GtkWidget *menu_item;
2525 GList *tmplist = NULL, *filelist = NULL, *list;
2526 const gchar *dirlist;
2527 gchar **dirs;
2528 gint i, flags;
2529
2530 menu = gtk_menu_new();
2531
2532 if (conf.scripts_use_default_search_dir_list)
2533 dirlist = SCRIPTS_DEFAULT_SEARCH_DIR_LIST;
2534 else
2535 dirlist = conf.scripts_search_dir_list;
2536
2537 if (!dirlist || !*dirlist) return NULL;
2538
2539 dirs = g_strsplit (dirlist, ",", -1);
2540 if (!dirs) return NULL;
2541
2542 flags = 0 | GETDIR_FOLLOW_SYMLINK;
2543 for (i = 0; dirs[i]; i++) {
2544 if (!*dirs || !isdir (dirs[i])) continue;
2545 get_dir (dirs[i], flags, &tmplist, NULL);
2546 filelist = g_list_concat (filelist, tmplist);
2547 }
2548 g_strfreev (dirs);
2549
2550 for (list = filelist; list; list = g_list_next (list)) {
2551 gchar *filename = list->data;
2552 gchar *label;
2553
2554 if (!filename || !*filename || !isexecutable(filename)) continue;
2555
2556 if (conf.scripts_show_dialog)
2557 label = g_strconcat (g_basename (filename), "...", NULL);
2558 else
2559 label = g_strdup (g_basename (filename));
2560
2561 menu_item = gtk_menu_item_new_with_label (label);
2562 gtk_object_set_data_full (GTK_OBJECT (menu_item),
2563 "script",
2564 g_strdup (filename),
2565 (GtkDestroyNotify) g_free);
2566 gtk_signal_connect (GTK_OBJECT (menu_item),
2567 "activate",
2568 GTK_SIGNAL_FUNC (cb_open_image_by_script),
2569 tv);
2570 gtk_menu_append (GTK_MENU (menu), menu_item);
2571 gtk_widget_show (menu_item);
2572
2573 g_free (label);
2574 }
2575
2576 g_list_foreach (filelist, (GFunc) g_free, NULL);
2577 g_list_free (filelist);
2578
2579 return menu;
2580 }
2581
2582
2583 static void
gimv_thumb_view_reset_load_priority(GimvThumbView * tv)2584 gimv_thumb_view_reset_load_priority (GimvThumbView *tv)
2585 {
2586 GList *node, *tmp_list = NULL;
2587 gboolean in_view;
2588
2589 g_return_if_fail (GIMV_IS_THUMB_VIEW (tv));
2590
2591 if (!tv->load_list) return;
2592 node = g_list_last (tv->load_list);
2593 g_return_if_fail (tv->vfuncs);
2594
2595 if (!tv->vfuncs->is_in_view) return;
2596
2597 while (node) {
2598 GimvThumb *thumb = node->data;
2599 node = g_list_previous (node);
2600
2601 in_view = tv->vfuncs->is_in_view (tv, thumb);
2602 if (in_view) {
2603 tv->load_list = g_list_remove (tv->load_list, thumb);
2604 tmp_list = g_list_prepend (tmp_list, thumb);
2605 }
2606 }
2607
2608 if (tmp_list)
2609 tv->load_list = g_list_concat (tmp_list, tv->load_list);
2610 }
2611
2612
2613 static void
gimv_thumb_view_set_scrollbar_callback(GimvThumbView * tv)2614 gimv_thumb_view_set_scrollbar_callback (GimvThumbView *tv)
2615 {
2616 GtkAdjustment *hadj, *vadj;
2617
2618 g_return_if_fail (GIMV_IS_THUMB_VIEW (tv));
2619
2620 hadj = gtk_scrolled_window_get_hadjustment (
2621 GTK_SCROLLED_WINDOW (tv->container));
2622 vadj = gtk_scrolled_window_get_vadjustment (
2623 GTK_SCROLLED_WINDOW (tv->container));
2624
2625 gtk_signal_connect (GTK_OBJECT (hadj),
2626 "value_changed",
2627 GTK_SIGNAL_FUNC (cb_thumbview_scrollbar_value_changed),
2628 tv);
2629 gtk_signal_connect (GTK_OBJECT (vadj),
2630 "value_changed",
2631 GTK_SIGNAL_FUNC (cb_thumbview_scrollbar_value_changed),
2632 tv);
2633 }
2634
2635
2636 static void
gimv_thumb_view_remove_scrollbar_callback(GimvThumbView * tv)2637 gimv_thumb_view_remove_scrollbar_callback (GimvThumbView *tv)
2638 {
2639 GtkAdjustment *hadj, *vadj;
2640
2641 g_return_if_fail (GIMV_IS_THUMB_VIEW (tv));
2642
2643 hadj = gtk_scrolled_window_get_hadjustment (GTK_SCROLLED_WINDOW (tv->container));
2644 vadj = gtk_scrolled_window_get_vadjustment (GTK_SCROLLED_WINDOW (tv->container));
2645
2646 gtk_signal_disconnect_by_func (GTK_OBJECT (hadj),
2647 GTK_SIGNAL_FUNC (cb_thumbview_scrollbar_value_changed),
2648 tv);
2649 gtk_signal_disconnect_by_func (GTK_OBJECT (vadj),
2650 GTK_SIGNAL_FUNC (cb_thumbview_scrollbar_value_changed),
2651 tv);
2652 }
2653
2654
2655 static GCompareFunc
gimv_thumb_view_get_compare_func(GimvThumbView * tv,gboolean * reverse)2656 gimv_thumb_view_get_compare_func (GimvThumbView *tv, gboolean *reverse)
2657 {
2658 GimvSortItem item;
2659 GimvSortFlag flags;
2660 GCompareFunc func = NULL;
2661
2662 g_return_val_if_fail (GIMV_IS_THUMB_VIEW (tv), NULL);
2663
2664 item = gimv_thumb_win_get_sort_type (tv->tw, &flags);
2665
2666 /* sort thumbnail */
2667 if (item == GIMV_SORT_NAME)
2668 func = comp_func_spel;
2669 else if (item == GIMV_SORT_SIZE)
2670 func = comp_func_size;
2671 else if (item == GIMV_SORT_ATIME)
2672 func = comp_func_atime;
2673 else if (item == GIMV_SORT_MTIME)
2674 func = comp_func_mtime;
2675 else if (item == GIMV_SORT_CTIME)
2676 func = comp_func_ctime;
2677 else if (item == GIMV_SORT_TYPE)
2678 func = comp_func_type;
2679 else if (item == GIMV_SORT_WIDTH)
2680 func = comp_func_width;
2681 else if (item == GIMV_SORT_HEIGHT)
2682 func = comp_func_height;
2683 else if (item == GIMV_SORT_AREA)
2684 func = comp_func_area;
2685
2686 if (reverse) {
2687 if ((flags & GIMV_SORT_REVERSE))
2688 *reverse = TRUE;
2689 else
2690 *reverse = FALSE;
2691 }
2692
2693 return func;
2694 }
2695
2696
2697
2698 /******************************************************************************
2699 *
2700 * Public Functions.
2701 *
2702 ******************************************************************************/
2703 GList *
gimv_thumb_view_get_list(void)2704 gimv_thumb_view_get_list (void)
2705 {
2706 return GimvThumbViewList;
2707 }
2708
2709
2710 static void
gimv_thumb_view_destroy_dupl_win_relation(GimvDuplWin * sw,GimvThumbView * tv)2711 gimv_thumb_view_destroy_dupl_win_relation (GimvDuplWin *sw,GimvThumbView *tv)
2712 {
2713 g_return_if_fail (GIMV_IS_DUPL_WIN (sw));
2714 g_return_if_fail (GIMV_IS_THUMB_VIEW (tv));
2715
2716 gimv_dupl_win_unset_relation (sw);
2717 gtk_signal_disconnect_by_func (GTK_OBJECT (sw),
2718 GTK_SIGNAL_FUNC (cb_dupl_win_destroy),
2719 tv);
2720 }
2721
2722
2723 const gchar *
gimv_thumb_view_get_path(GimvThumbView * tv)2724 gimv_thumb_view_get_path (GimvThumbView *tv)
2725 {
2726 g_return_val_if_fail (GIMV_IS_THUMB_VIEW (tv), NULL);
2727
2728 if (tv->mode == GIMV_THUMB_VIEW_MODE_DIR) {
2729 return tv->priv->dirname;
2730 } else if (tv->mode == GIMV_THUMB_VIEW_MODE_ARCHIVE) {
2731 return tv->priv->archive->filename;
2732 }
2733
2734 return NULL;
2735 }
2736
2737
2738 GimvThumbView *
gimv_thumb_view_find_opened_dir(const gchar * path)2739 gimv_thumb_view_find_opened_dir (const gchar *path)
2740 {
2741 GList *node;
2742
2743 if (!path) return NULL;
2744
2745 for (node = GimvThumbViewList; node; node = g_list_next (node)) {
2746 GimvThumbView *tv = node->data;
2747
2748 if (tv->mode == GIMV_THUMB_VIEW_MODE_DIR &&
2749 tv->priv && tv->priv->dirname &&
2750 !strcmp (path, tv->priv->dirname))
2751 {
2752 return tv;
2753 }
2754 }
2755
2756 return NULL;
2757 }
2758
2759
2760 GimvThumbView *
gimv_thumb_view_find_opened_archive(const gchar * path)2761 gimv_thumb_view_find_opened_archive (const gchar *path)
2762 {
2763 GimvThumbView *tv;
2764 GList *node;
2765
2766 if (!path) return NULL;
2767
2768 node = g_list_first (GimvThumbViewList);
2769 while (node) {
2770 tv = node->data;
2771 if (tv->mode == GIMV_THUMB_VIEW_MODE_ARCHIVE
2772 && tv->priv->archive
2773 && !strcmp (path, tv->priv->archive->filename))
2774 {
2775 return tv;
2776 }
2777 node = g_list_next (node);
2778 }
2779
2780 return NULL;
2781 }
2782
2783
2784 void
gimv_thumb_view_sort_data(GimvThumbView * tv)2785 gimv_thumb_view_sort_data (GimvThumbView *tv)
2786 {
2787 GCompareFunc func;
2788 gboolean reverse = FALSE;
2789
2790 g_return_if_fail (GIMV_IS_THUMB_VIEW (tv));
2791
2792 func = gimv_thumb_view_get_compare_func (tv, &reverse);
2793 g_return_if_fail (func);
2794
2795 tv->thumblist = g_list_sort (tv->thumblist, func);
2796 if (reverse)
2797 tv->thumblist = g_list_reverse (tv->thumblist);
2798 }
2799
2800
2801 /* #define ENABLE_THUMB_LOADER_TIMER 0 */
2802 gboolean
gimv_thumb_view_load_thumbnails(GimvThumbView * tv,GList * loadlist,const gchar * dest_mode)2803 gimv_thumb_view_load_thumbnails (GimvThumbView *tv, GList *loadlist,
2804 const gchar *dest_mode)
2805 {
2806 #ifdef ENABLE_THUMB_LOADER_TIMER
2807 GTimer *timer;
2808 gdouble etime;
2809 gulong mtime;
2810 #endif /* ENABLE_THUMB_LOADER_TIMER */
2811 FilesLoader *files = tv->progress;
2812 gint pos;
2813
2814 g_return_val_if_fail (GIMV_IS_THUMB_VIEW (tv) && loadlist, FALSE);
2815 g_return_val_if_fail (plugin_list, FALSE);
2816
2817 #ifdef ENABLE_THUMB_LOADER_TIMER
2818 timer = g_timer_new ();
2819 g_timer_start (timer);
2820 g_print ("timer started\n");
2821 #endif /* ENABLE_THUMB_LOADER_TIMER */
2822
2823 g_return_val_if_fail (tv->vfuncs, FALSE);
2824
2825 /* load thumbnail!! */
2826 tv->load_list = g_list_copy (loadlist);
2827 gimv_thumb_view_reset_load_priority (tv);
2828
2829 tv->progress->window = GTK_WIDGET (tv->tw);
2830 tv->progress->progressbar = tv->tw->progressbar;
2831 tv->progress->num = g_list_length (loadlist);
2832 tv->progress->pos = 0;
2833 gimv_thumb_win_set_statusbar_page_info (tv->tw,
2834 GIMV_THUMB_WIN_CURRENT_PAGE);
2835
2836 for (pos = 1; tv->load_list && files->status < CANCEL; pos++) {
2837 GimvThumb *thumb;
2838
2839 if (tv->progress->pos % conf.thumbwin_redraw_interval == 0)
2840 while (gtk_events_pending()) gtk_main_iteration();
2841
2842 thumb = tv->load_list->data;
2843
2844 gimv_thumb_load (thumb, tv->thumb_size, files->thumb_load_type);
2845
2846 if (tv->vfuncs->update_thumb)
2847 tv->vfuncs->update_thumb (tv, thumb, dest_mode);
2848
2849 if(files->status < 0) {
2850 GimvThumbViewList = g_list_remove (GimvThumbViewList, tv);
2851 gtk_object_unref (GTK_OBJECT (tv));
2852 break;
2853 } else {
2854 /* update progress info */
2855 tv->progress->now_file = gimv_image_info_get_path (thumb->info);
2856 tv->progress->pos = pos;
2857 gimv_thumb_win_loading_update_progress (tv->tw,
2858 GIMV_THUMB_WIN_CURRENT_PAGE);
2859 }
2860
2861 tv->load_list = g_list_remove (tv->load_list, thumb);
2862 }
2863
2864 if (tv->load_list) {
2865 g_list_free (tv->load_list);
2866 tv->load_list = NULL;
2867 }
2868
2869 gtk_progress_set_show_text(GTK_PROGRESS(files->progressbar), FALSE);
2870 gtk_progress_bar_update (GTK_PROGRESS_BAR(files->progressbar), 0.0);
2871
2872 #ifdef ENABLE_THUMB_LOADER_TIMER
2873 g_timer_stop (timer);
2874 g_print ("timer stopped\n");
2875 etime = g_timer_elapsed (timer, &mtime);
2876 g_print ("elapsed time = %f sec\n", etime);
2877 g_timer_destroy (timer);
2878 #endif /* ENABLE_THUMB_LOADER_TIMER */
2879
2880 return TRUE;
2881 }
2882
2883
2884 gboolean
gimv_thumb_view_append_thumbnail(GimvThumbView * tv,FilesLoader * files,gboolean force)2885 gimv_thumb_view_append_thumbnail (GimvThumbView *tv, FilesLoader *files,
2886 gboolean force)
2887 {
2888 GList *loadlist = NULL;
2889
2890 g_return_val_if_fail (GIMV_IS_THUMB_VIEW (tv) && files, FALSE);
2891 g_return_val_if_fail (tv->vfuncs, FALSE);
2892
2893 if (!tv || !files || (tv->mode == GIMV_THUMB_VIEW_MODE_DIR && !force)) {
2894 return FALSE;
2895 }
2896
2897 tv->progress = files;
2898
2899 gimv_thumb_view_insert_thumb_frames (tv, files->filelist);
2900
2901 if (tv->vfuncs->get_load_list)
2902 loadlist = tv->vfuncs->get_load_list (tv);
2903
2904 if (loadlist) {
2905 gimv_thumb_view_load_thumbnails (tv, loadlist, tv->summary_mode);
2906 g_list_free (loadlist);
2907 }
2908
2909 tv->progress = NULL;
2910
2911 if (files->status >= 0)
2912 gimv_thumb_win_set_statusbar_page_info (tv->tw,
2913 GIMV_THUMB_WIN_CURRENT_PAGE);
2914
2915 return TRUE;
2916 }
2917
2918
2919 void
gimv_thumb_view_clear(GimvThumbView * tv)2920 gimv_thumb_view_clear (GimvThumbView *tv)
2921 {
2922 GimvThumb *thumb;
2923 GList *node;
2924
2925 g_return_if_fail (GIMV_IS_THUMB_VIEW (tv));
2926 g_return_if_fail (tv->vfuncs);
2927 g_return_if_fail (!tv->progress);
2928
2929 if (tv->vfuncs->freeze)
2930 tv->vfuncs->freeze (tv);
2931
2932 node = tv->thumblist;
2933 while (node) {
2934 thumb = node->data;
2935 node = g_list_next (node);
2936 if (!GIMV_IS_THUMB (thumb)) continue;
2937
2938 tv->vfuncs->remove_thumb (tv, thumb);
2939 gimv_thumb_view_remove_thumb_data (tv, thumb);
2940 gtk_object_unref (GTK_OBJECT(thumb));
2941 }
2942
2943 /* destroy relation */
2944 node = tv->priv->related_image_view;
2945 while (node) {
2946 GimvImageView *iv = node->data;
2947 node = g_list_next(node);
2948 gimv_image_view_remove_list (iv, tv);
2949 }
2950 g_list_free (tv->priv->related_image_view);
2951 tv->priv->related_image_view = NULL;
2952
2953 g_list_foreach (tv->priv->related_dupl_win,
2954 (GFunc) gimv_thumb_view_destroy_dupl_win_relation,
2955 tv);
2956 g_list_free (tv->priv->related_dupl_win);
2957 tv->priv->related_dupl_win = NULL;
2958
2959 if (tv->vfuncs->thaw)
2960 tv->vfuncs->thaw (tv);
2961
2962 gimv_thumb_win_set_statusbar_page_info (tv->tw,
2963 GIMV_THUMB_WIN_CURRENT_PAGE);
2964 }
2965
2966
2967 void
gimv_thumb_view_refresh_thumbnail(GimvThumbView * tv,GimvThumb * thumb,ThumbLoadType type)2968 gimv_thumb_view_refresh_thumbnail (GimvThumbView *tv, GimvThumb *thumb,
2969 ThumbLoadType type)
2970 {
2971 g_return_if_fail (GIMV_IS_THUMB_VIEW (tv));
2972 g_return_if_fail (GIMV_IS_THUMB (thumb));
2973 g_return_if_fail (tv->vfuncs);
2974
2975 gimv_thumb_load (thumb, tv->thumb_size, type);
2976
2977 if (tv->vfuncs->update_thumb)
2978 tv->vfuncs->update_thumb (tv, thumb, tv->summary_mode);
2979 }
2980
2981
2982 typedef struct _SetCursorData
2983 {
2984 GimvThumbView *tv;
2985 GimvThumb *cursor;
2986 } SetCursorData;
2987
2988
2989 static gboolean
idle_set_cursor(gpointer user_data)2990 idle_set_cursor(gpointer user_data)
2991 {
2992 SetCursorData *data = user_data;
2993
2994 if (data->cursor) {
2995 gimv_thumb_view_set_focus (data->tv, data->cursor);
2996 gimv_thumb_view_adjust (data->tv, data->cursor);
2997 }
2998
2999 g_free (data);
3000
3001 return FALSE;
3002 }
3003
3004
3005 gboolean
gimv_thumb_view_refresh_list(GimvThumbView * tv)3006 gimv_thumb_view_refresh_list (GimvThumbView *tv)
3007 {
3008 FilesLoader *files;
3009 GList *selection, *thumbnode, *node;
3010 GimvThumb *thumb, *dest_cur[4];
3011 gchar *filename;
3012 gboolean exist = FALSE;
3013 struct stat st;
3014 gint i, flags, n_dest_cur;
3015
3016 g_return_val_if_fail (GIMV_IS_THUMB_VIEW (tv), FALSE);
3017 g_return_val_if_fail (tv->vfuncs, FALSE);
3018
3019 if (tv->progress)
3020 return FALSE;
3021
3022 /* get dest cursor candiates */
3023 n_dest_cur = sizeof (dest_cur) / sizeof (GimvThumb *);
3024 for (i = 0; i < n_dest_cur; i++)
3025 dest_cur[i] = NULL;
3026
3027 dest_cur[0] = gimv_thumb_view_get_focus (tv);
3028 if (dest_cur[0]) {
3029 node = g_list_find (tv->thumblist, dest_cur[0]);
3030 if (node) {
3031 if (g_list_next (node))
3032 dest_cur[1] = g_list_next (node)->data;
3033 else if (g_list_previous (node))
3034 dest_cur[1] = g_list_previous (node)->data;
3035 }
3036 }
3037
3038 selection = gimv_thumb_view_get_selection_list (tv);
3039
3040 if (selection) {
3041 node = g_list_find (tv->thumblist, selection->data);
3042 if (node) {
3043 dest_cur[2] = node->data;
3044 if (g_list_previous (node))
3045 dest_cur[3] = g_list_previous (node)->data;
3046 }
3047
3048 for (; node; node = g_list_next (node)) {
3049 if (!g_list_find (selection, node->data)) {
3050 dest_cur[3] = node->data;
3051 break;
3052 }
3053 }
3054 }
3055
3056 g_list_free (selection);
3057
3058 /* search */
3059 files = files_loader_new ();
3060
3061 if (tv->mode == GIMV_THUMB_VIEW_MODE_DIR) {
3062 if (tv->vfuncs->freeze)
3063 tv->vfuncs->freeze (tv);
3064
3065 flags = GETDIR_FOLLOW_SYMLINK;
3066 if (conf.read_dotfile)
3067 flags = flags | GETDIR_READ_DOT;
3068 if (conf.detect_filetype_by_ext)
3069 flags = flags | GETDIR_DETECT_EXT;
3070 if (conf.thumbview_show_archive)
3071 flags = flags | GETDIR_GET_ARCHIVE;
3072
3073 get_dir (tv->priv->dirname, flags, &files->filelist, &files->dirlist);
3074
3075 if (tv->mode == GIMV_THUMB_VIEW_MODE_DIR && conf.thumbview_show_dir) {
3076 gchar *parent = g_strconcat (tv->priv->dirname, "..", NULL);
3077 files->filelist = g_list_concat (files->dirlist, files->filelist);
3078 files->filelist = g_list_prepend (files->filelist, parent);
3079 files->dirlist = NULL;
3080 }
3081
3082 thumbnode = g_list_first (tv->thumblist);
3083 while (thumbnode) {
3084 thumb = thumbnode->data;
3085 thumbnode = g_list_next (thumbnode);
3086
3087 /* remove same file from files->filelist */
3088 node = g_list_first (files->filelist);
3089 while (node) {
3090 filename = node->data;
3091 if (!strcmp (filename, gimv_image_info_get_path (thumb->info))) {
3092 /* check modification time */
3093 if (!stat (filename, &st) &&
3094 ((thumb->info->st.st_mtime != st.st_mtime) ||
3095 (thumb->info->st.st_ctime != st.st_ctime)))
3096 {
3097 exist = FALSE;
3098 } else {
3099 exist = TRUE;
3100 files->filelist = g_list_remove (files->filelist, filename);
3101 g_free (filename);
3102 }
3103 break;
3104 }
3105 node = g_list_next (node);
3106 }
3107
3108 /* remove obsolete data */
3109 if (!exist) {
3110 tv->vfuncs->remove_thumb (tv, thumb);
3111 gimv_thumb_view_remove_thumb_data (tv, thumb);
3112 gtk_object_unref (GTK_OBJECT (thumb));
3113 }
3114
3115 exist = FALSE;
3116 }
3117
3118 if (tv->vfuncs->thaw)
3119 tv->vfuncs->thaw (tv);
3120
3121 /* append new files */
3122 if (files->filelist)
3123 gimv_thumb_view_append_thumbnail (tv, files, TRUE);
3124
3125 } else if (tv->mode == GIMV_THUMB_VIEW_MODE_COLLECTION) {
3126 }
3127
3128 files_loader_delete (files);
3129
3130 gimv_thumb_win_set_statusbar_page_info (tv->tw,
3131 GIMV_THUMB_WIN_CURRENT_PAGE);
3132
3133 /* set cursor position */
3134 for (i = 0; i < n_dest_cur; i++) {
3135 thumb = dest_cur[i];
3136
3137 if (thumb && g_list_find (tv->thumblist, thumb)) {
3138 SetCursorData *data = g_new0 (SetCursorData, 1);
3139 data->tv = tv;
3140 data->cursor = thumb;
3141 gtk_idle_add (idle_set_cursor, data);
3142 break;
3143 }
3144 }
3145
3146 /* check relation */
3147 node = tv->priv->related_image_view;
3148 while (node) {
3149 GimvImageView *iv = node->data;
3150 GList *lnode;
3151
3152 node = g_list_next (node);
3153
3154 lnode = gimv_image_view_image_list_current (iv);
3155 if (!lnode) continue;
3156
3157 if (!g_list_find (tv->thumblist, lnode->data)) {
3158 gimv_image_view_remove_list (iv, (gpointer) tv);
3159 }
3160 }
3161
3162 return TRUE;
3163 }
3164
3165
3166 gint
gimv_thumb_view_refresh_list_idle(gpointer data)3167 gimv_thumb_view_refresh_list_idle (gpointer data)
3168 {
3169 GimvThumbView *tv = data;
3170 gimv_thumb_view_refresh_list (tv);
3171 return FALSE;
3172 }
3173
3174
3175 void
gimv_thumb_view_change_summary_mode(GimvThumbView * tv,const gchar * mode)3176 gimv_thumb_view_change_summary_mode (GimvThumbView *tv, const gchar *mode)
3177 {
3178 GimvThumbWin *tw;
3179 GList *node, *loadlist = NULL;
3180
3181 g_return_if_fail (GIMV_IS_THUMB_VIEW (tv));
3182
3183 tw = tv->tw;
3184 g_return_if_fail (GIMV_IS_THUMB_WIN (tw));
3185 g_return_if_fail (tv->vfuncs);
3186
3187 node = g_list_find (GimvThumbViewList, tv);
3188 if (!node) return;
3189
3190 gimv_thumb_view_set_widget (tv, tw, tv->container, mode);
3191
3192 if (tv->vfuncs->get_load_list)
3193 loadlist = tv->vfuncs->get_load_list (tv);
3194
3195 /* reload images if needed */
3196 if (loadlist) {
3197 FilesLoader *files;
3198
3199 files = files_loader_new ();
3200 tv->progress = files;
3201
3202 gimv_thumb_view_load_thumbnails (tv, loadlist, tv->summary_mode);
3203
3204 g_list_free (loadlist);
3205 files_loader_delete (files);
3206 tv->progress = NULL;
3207
3208 gimv_thumb_win_set_statusbar_page_info (tw, GIMV_THUMB_WIN_CURRENT_PAGE);
3209 }
3210 }
3211
3212
3213 void
gimv_thumb_view_adjust(GimvThumbView * tv,GimvThumb * thumb)3214 gimv_thumb_view_adjust (GimvThumbView *tv, GimvThumb *thumb)
3215 {
3216 g_return_if_fail (GIMV_IS_THUMB_VIEW (tv));
3217 g_return_if_fail (tv->vfuncs);
3218
3219 if (tv->vfuncs->adjust_position)
3220 tv->vfuncs->adjust_position (tv, thumb);
3221
3222 return;
3223 }
3224
3225
3226 GList *
gimv_thumb_view_get_selection_list(GimvThumbView * tv)3227 gimv_thumb_view_get_selection_list (GimvThumbView *tv)
3228 {
3229 GList *list = NULL, *node;
3230 GimvThumb *thumb;
3231
3232 g_return_val_if_fail (GIMV_IS_THUMB_VIEW (tv), NULL);
3233
3234 node = tv->thumblist;
3235 if (!node) return NULL;
3236
3237 while (node) {
3238 thumb = node->data;
3239
3240 if (thumb->selected)
3241 list = g_list_append (list, thumb);
3242
3243 node = g_list_next (node);
3244 }
3245
3246 return list;
3247 }
3248
3249
3250 GList *
gimv_thumb_view_get_selected_file_list(GimvThumbView * tv)3251 gimv_thumb_view_get_selected_file_list (GimvThumbView *tv)
3252 {
3253 GList *list = NULL, *filelist = NULL, *node;
3254
3255 g_return_val_if_fail (GIMV_IS_THUMB_VIEW (tv), NULL);
3256
3257 list = gimv_thumb_view_get_selection_list (tv);
3258 if (!list) return NULL;
3259
3260 node = list;
3261 while (node) {
3262 GimvThumb *thumb = node->data;
3263
3264 if (thumb->info)
3265 filelist
3266 = g_list_append (filelist,
3267 g_strdup (gimv_image_info_get_path (thumb->info)));
3268
3269 node = g_list_next (node);
3270 }
3271
3272 return filelist;
3273 }
3274
3275
3276 gboolean
gimv_thumb_view_set_selection(GimvThumb * thumb,gboolean select)3277 gimv_thumb_view_set_selection (GimvThumb *thumb, gboolean select)
3278 {
3279 GimvThumbView *tv;
3280
3281 g_return_val_if_fail (GIMV_IS_THUMB (thumb), FALSE);
3282
3283 tv = gimv_thumb_get_parent_thumbview (thumb);
3284 g_return_val_if_fail (GIMV_IS_THUMB_VIEW (tv), FALSE);
3285
3286 if ((thumb->selected && select) || (!thumb->selected && !select))
3287 return TRUE;
3288
3289 g_return_val_if_fail (tv->vfuncs, FALSE);
3290
3291 if (tv->vfuncs->set_selection)
3292 tv->vfuncs->set_selection (tv, thumb, select);
3293 else
3294 return FALSE;
3295
3296 return TRUE;
3297 }
3298
3299
3300 gboolean
gimv_thumb_view_set_selection_all(GimvThumbView * tv,gboolean select)3301 gimv_thumb_view_set_selection_all (GimvThumbView *tv, gboolean select)
3302 {
3303 GimvThumb *thumb;
3304 GList *node;
3305
3306 g_return_val_if_fail (GIMV_IS_THUMB_VIEW (tv), FALSE);
3307 g_return_val_if_fail (tv->thumblist, FALSE);
3308
3309 node = tv->thumblist;
3310 while (node) {
3311 thumb = node->data;
3312 gimv_thumb_view_set_selection (thumb, select);
3313 node = g_list_next (node);
3314 }
3315
3316 return TRUE;
3317 }
3318
3319
3320 void
gimv_thumb_view_set_focus(GimvThumbView * tv,GimvThumb * thumb)3321 gimv_thumb_view_set_focus (GimvThumbView *tv, GimvThumb *thumb)
3322 {
3323 g_return_if_fail (GIMV_IS_THUMB_VIEW (tv));
3324 g_return_if_fail (tv->vfuncs);
3325
3326 if (tv->vfuncs->set_focus)
3327 tv->vfuncs->set_focus (tv, thumb);
3328 }
3329
3330
3331 GimvThumb *
gimv_thumb_view_get_focus(GimvThumbView * tv)3332 gimv_thumb_view_get_focus (GimvThumbView *tv)
3333 {
3334 g_return_val_if_fail (GIMV_IS_THUMB_VIEW (tv), NULL);
3335 g_return_val_if_fail (tv->vfuncs, NULL);
3336
3337 if (tv->vfuncs->get_focus)
3338 return tv->vfuncs->get_focus (tv);
3339
3340 return NULL;
3341 }
3342
3343
3344 gboolean
gimv_thumb_view_set_selection_multiple(GimvThumbView * tv,GimvThumb * thumb,gboolean reverse,gboolean clear)3345 gimv_thumb_view_set_selection_multiple (GimvThumbView *tv, GimvThumb *thumb,
3346 gboolean reverse, gboolean clear)
3347 {
3348 GimvThumb *thumb_tmp;
3349 GList *node, *current_node;
3350 gboolean retval = FALSE;
3351
3352 g_return_val_if_fail (GIMV_IS_THUMB_VIEW (tv), FALSE);
3353 g_return_val_if_fail (GIMV_IS_THUMB (thumb), FALSE);
3354
3355 node = current_node = g_list_find (tv->thumblist, thumb);
3356 if (reverse)
3357 node = g_list_previous (node);
3358 else
3359 node = g_list_next (node);
3360
3361 while (node) {
3362 thumb_tmp = node->data;
3363 if (thumb_tmp->selected) {
3364 if (clear)
3365 gimv_thumb_view_set_selection_all (tv, FALSE);
3366 while (TRUE) {
3367 thumb_tmp = node->data;
3368 gimv_thumb_view_set_selection (thumb_tmp, TRUE);
3369 if (node == current_node) break;
3370 if (reverse)
3371 node = g_list_next (node);
3372 else
3373 node = g_list_previous (node);
3374 }
3375 retval = TRUE;
3376 break;
3377 }
3378 if (reverse)
3379 node = g_list_previous (node);
3380 else
3381 node = g_list_next (node);
3382 }
3383
3384 return retval;
3385 }
3386
3387
3388 void
gimv_thumb_view_grab_focus(GimvThumbView * tv)3389 gimv_thumb_view_grab_focus (GimvThumbView *tv)
3390 {
3391 g_return_if_fail(GIMV_IS_THUMB_VIEW (tv));
3392 g_return_if_fail(GTK_IS_BIN(tv->container));
3393 gtk_widget_grab_focus (GTK_BIN (tv->container)->child);
3394 }
3395
3396
3397 void
gimv_thumb_view_find_duplicates(GimvThumbView * tv,GimvThumb * thumb,const gchar * type)3398 gimv_thumb_view_find_duplicates (GimvThumbView *tv, GimvThumb *thumb,
3399 const gchar *type)
3400 {
3401 GimvDuplFinder *finder;
3402 GimvDuplWin *sw = NULL;
3403 GimvThumbWin *tw;
3404 GList *node;
3405
3406 g_return_if_fail (GIMV_IS_THUMB_VIEW (tv));
3407
3408 tw = tv->tw;
3409 g_return_if_fail (GIMV_IS_THUMB_WIN (tw));
3410
3411 /* create window */
3412 sw = gimv_dupl_win_new (tv->thumb_size);
3413 gtk_signal_connect (GTK_OBJECT (sw), "destroy",
3414 GTK_SIGNAL_FUNC (cb_dupl_win_destroy),
3415 tv);
3416 gimv_dupl_win_set_relation (sw, tv);
3417 tv->priv->related_dupl_win
3418 = g_list_append (tv->priv->related_dupl_win, sw);
3419
3420 /* set finder */
3421 finder = sw->finder;
3422 gimv_dupl_finder_set_algol_type (finder, type);
3423
3424 for (node = tv->thumblist; node; node = g_list_next (node)) {
3425 gimv_dupl_finder_append_dest (finder, node->data);
3426 }
3427
3428 gimv_dupl_finder_start (finder);
3429 }
3430
3431
3432 void
gimv_thumb_view_reset_tab_label(GimvThumbView * tv,const gchar * title)3433 gimv_thumb_view_reset_tab_label (GimvThumbView *tv, const gchar *title)
3434 {
3435 gchar *tmpstr;
3436 const gchar *filename;
3437
3438 g_return_if_fail (GIMV_IS_THUMB_VIEW (tv));
3439
3440 /* set tab title */
3441 if (tv->mode == GIMV_THUMB_VIEW_MODE_COLLECTION) {
3442 if (title) {
3443 g_free (tv->tabtitle);
3444 tv->tabtitle = g_strdup (title);
3445 }
3446
3447 } else {
3448 if (tv->mode == GIMV_THUMB_VIEW_MODE_DIR) {
3449 g_return_if_fail (tv->priv->dirname && *tv->priv->dirname);
3450 filename = tv->priv->dirname;
3451 } else if (tv->mode == GIMV_THUMB_VIEW_MODE_ARCHIVE) {
3452 g_return_if_fail (tv->priv->archive);
3453 g_return_if_fail (tv->priv->archive->filename
3454 && *tv->priv->archive->filename);
3455 filename = tv->priv->archive->filename;
3456 } else {
3457 return;
3458 }
3459
3460 if (conf.thumbwin_tab_fullpath) {
3461 tmpstr = fileutil_home2tilde (filename);
3462 } else {
3463 if (tv->mode == GIMV_THUMB_VIEW_MODE_ARCHIVE) {
3464 tmpstr = g_strdup (g_basename (filename));
3465 } else {
3466 gchar *dirname = g_dirname (filename);
3467 tmpstr = fileutil_dir_basename (dirname);
3468 g_free (dirname);
3469 }
3470 }
3471
3472 g_free (tv->tabtitle);
3473 tv->tabtitle = charset_to_internal (tmpstr,
3474 conf.charset_filename,
3475 conf.charset_auto_detect_fn,
3476 conf.charset_filename_mode);
3477
3478 g_free (tmpstr);
3479
3480 }
3481
3482 gimv_thumb_win_set_tab_label_text (tv->container, tv->tabtitle);
3483 }
3484
3485
3486 GtkType
gimv_thumb_view_get_type(void)3487 gimv_thumb_view_get_type (void)
3488 {
3489 static GtkType gimv_thumb_view_type = 0;
3490
3491 if (!gimv_thumb_view_type) {
3492 static const GtkTypeInfo gimv_thumb_view_info = {
3493 "GimvThumbView",
3494 sizeof (GimvThumbView),
3495 sizeof (GimvThumbViewClass),
3496 (GtkClassInitFunc) gimv_thumb_view_class_init,
3497 (GtkObjectInitFunc) gimv_thumb_view_init,
3498 NULL,
3499 NULL,
3500 (GtkClassInitFunc) NULL,
3501 };
3502
3503 gimv_thumb_view_type = gtk_type_unique (gtk_object_get_type (),
3504 &gimv_thumb_view_info);
3505 }
3506
3507 return gimv_thumb_view_type;
3508 }
3509
3510
3511 static void
gimv_thumb_view_class_init(GimvThumbViewClass * klass)3512 gimv_thumb_view_class_init (GimvThumbViewClass *klass)
3513 {
3514 GtkObjectClass *object_class;
3515
3516 gimv_thumb_view_get_summary_mode_list ();
3517
3518 object_class = (GtkObjectClass *) klass;
3519 parent_class = gtk_type_class (gtk_object_get_type ());
3520
3521 object_class->destroy = gimv_thumb_view_destroy;
3522 }
3523
3524
3525 static void
gimv_thumb_view_init(GimvThumbView * tv)3526 gimv_thumb_view_init (GimvThumbView *tv)
3527 {
3528 tv->thumblist = NULL;
3529
3530 tv->tw = NULL;
3531
3532 tv->container = NULL;
3533 tv->popup_menu = NULL;
3534
3535 tv->tabtitle = NULL;
3536
3537 tv->thumb_size = 96;
3538
3539 tv->mode = 0;
3540
3541 tv->filenum = 0;
3542 tv->filesize = 0;
3543
3544 tv->summary_mode = NULL;
3545 tv->vfuncs = NULL;
3546
3547 tv->dnd_destdir = NULL;
3548
3549 tv->status = 0;
3550 tv->progress = NULL;
3551 tv->load_list = NULL;
3552
3553 tv->priv = g_new0 (GimvThumbViewPriv, 1);
3554 tv->priv->dirname = NULL;
3555 tv->priv->archive = NULL;
3556 tv->priv->related_image_view = NULL;
3557 tv->priv->related_dupl_win = NULL;
3558 tv->priv->button_2pressed_queue = 0;
3559
3560 #ifdef USE_GTK2
3561 gtk_object_ref (GTK_OBJECT (tv));
3562 gtk_object_sink (GTK_OBJECT (tv));
3563 #endif
3564
3565 GimvThumbViewList = g_list_append (GimvThumbViewList, tv);
3566 total_tab_count++;
3567 }
3568
3569
3570 GimvThumbView *
gimv_thumb_view_new(void)3571 gimv_thumb_view_new (void)
3572 {
3573 GimvThumbView *tv;
3574
3575 tv = GIMV_THUMB_VIEW (gtk_type_new (gimv_thumb_view_get_type ()));
3576
3577 return tv;
3578 }
3579
3580
3581 static void
gimv_thumb_view_redraw(GimvThumbView * tv,const gchar * mode,GtkWidget * scroll_win)3582 gimv_thumb_view_redraw (GimvThumbView *tv,
3583 const gchar *mode,
3584 GtkWidget *scroll_win)
3585 {
3586 GList *node;
3587 GtkAdjustment *hadj, *vadj;
3588 GtkWidget *widget;
3589
3590 g_return_if_fail (GIMV_IS_THUMB_VIEW (tv));
3591
3592 node = g_list_find (GimvThumbViewList, tv);
3593 if (!node) return;
3594
3595 if (!scroll_win)
3596 scroll_win = tv->container;
3597
3598 gimv_thumb_view_remove_scrollbar_callback (tv);
3599
3600 hadj = gtk_scrolled_window_get_hadjustment (
3601 GTK_SCROLLED_WINDOW (tv->container));
3602 vadj = gtk_scrolled_window_get_vadjustment (
3603 GTK_SCROLLED_WINDOW (tv->container));
3604 hadj->value = 0.0;
3605 vadj->value = 0.0;
3606 gtk_signal_emit_by_name (GTK_OBJECT(hadj), "value_changed");
3607 gtk_signal_emit_by_name (GTK_OBJECT(vadj), "value_changed");
3608
3609 /* sort thumbnail list */
3610 gimv_thumb_view_sort_data (tv);
3611
3612 /* remove current widget */
3613 if (GTK_BIN (tv->container)->child)
3614 gtk_widget_destroy (GTK_BIN (tv->container)->child);
3615
3616 /* create new widget */
3617 tv->vfuncs = g_hash_table_lookup (modes_table, mode);
3618 tv->summary_mode = mode;
3619 g_return_if_fail (tv->vfuncs);
3620
3621 widget = tv->vfuncs->create (tv, mode);
3622
3623 gtk_container_add (GTK_CONTAINER (scroll_win), widget);
3624 tv->container = scroll_win;
3625
3626 gimv_thumb_view_set_scrollbar_callback (tv);
3627
3628 gimv_thumb_view_reset_load_priority (tv);
3629
3630 gtk_widget_grab_focus (GTK_BIN (tv->container)->child);
3631 }
3632
3633
3634 gboolean
gimv_thumb_view_set_widget(GimvThumbView * tv,GimvThumbWin * tw,GtkWidget * container,const gchar * summary_mode)3635 gimv_thumb_view_set_widget (GimvThumbView *tv, GimvThumbWin *tw,
3636 GtkWidget *container, const gchar *summary_mode)
3637 {
3638 gint page;
3639 gboolean is_newtab = FALSE;
3640
3641 g_return_val_if_fail (GIMV_IS_THUMB_VIEW (tv), FALSE);
3642 g_return_val_if_fail (container || tv->container, FALSE);
3643
3644 /* check parent widget */
3645 page = gtk_notebook_page_num (GTK_NOTEBOOK (tw->notebook), container);
3646 if (page < 0)
3647 return FALSE;
3648
3649 if (!tv->container)
3650 is_newtab = TRUE;
3651
3652 if (is_newtab) {
3653 gchar buf[BUF_SIZE];
3654
3655 tv->tw = tw;
3656 tv->container = container;
3657 tv->summary_mode = summary_mode;
3658 tv->mode = GIMV_THUMB_VIEW_MODE_COLLECTION;
3659 g_snprintf (buf, BUF_SIZE, _("Collection %d"), total_tab_count);
3660 gimv_thumb_view_reset_tab_label (tv, buf);
3661 gimv_thumb_view_set_scrollbar_callback (tv);
3662 gimv_thumb_view_redraw (tv, tv->summary_mode, tv->container);
3663 } else {
3664 gimv_thumb_view_redraw (tv, summary_mode, container);
3665 tv->tw = tw;
3666 }
3667
3668 return TRUE;
3669 }
3670
3671
3672 void
gimv_thumb_view_reload(GimvThumbView * tv,FilesLoader * files,GimvThumbViewMode mode)3673 gimv_thumb_view_reload (GimvThumbView *tv, FilesLoader *files, GimvThumbViewMode mode)
3674 {
3675 gint current_page, this_page;
3676 GList *loadlist = NULL;
3677 gchar buf[BUF_SIZE];
3678
3679 g_return_if_fail (GIMV_IS_THUMB_VIEW (tv));
3680 g_return_if_fail (files);
3681 g_return_if_fail ((mode == GIMV_THUMB_VIEW_MODE_COLLECTION) ||
3682 (mode == GIMV_THUMB_VIEW_MODE_DIR && files->dirname) ||
3683 (mode == GIMV_THUMB_VIEW_MODE_RECURSIVE_DIR && files->dirname) ||
3684 (mode == GIMV_THUMB_VIEW_MODE_ARCHIVE && files->archive));
3685 g_return_if_fail (!tv->progress);
3686
3687 gimv_thumb_view_clear (tv);
3688 g_free (tv->priv->dirname);
3689 tv->priv->dirname = NULL;
3690 if (tv->priv->archive)
3691 fr_archive_unref (tv->priv->archive);
3692 tv->priv->archive = NULL;
3693
3694 /* set mode specific data */
3695 if (mode == GIMV_THUMB_VIEW_MODE_DIR ||
3696 mode == GIMV_THUMB_VIEW_MODE_RECURSIVE_DIR)
3697 {
3698 if (files->dirname[strlen (files->dirname) - 1] != '/')
3699 tv->priv->dirname = g_strconcat (files->dirname, "/", NULL);
3700 else
3701 tv->priv->dirname = g_strdup (files->dirname);
3702
3703 } else if (mode == GIMV_THUMB_VIEW_MODE_ARCHIVE) {
3704 fr_archive_ref (FR_ARCHIVE (files->archive));
3705 tv->priv->archive = files->archive;
3706
3707 } else if (mode == GIMV_THUMB_VIEW_MODE_COLLECTION) {
3708 }
3709
3710 /* set struct member */
3711 tv->progress = files;
3712
3713 if (mode == GIMV_THUMB_VIEW_MODE_RECURSIVE_DIR)
3714 tv->mode = GIMV_THUMB_VIEW_MODE_COLLECTION;
3715 else
3716 tv->mode = mode;
3717
3718 tv->thumb_size =
3719 gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON(tv->tw->button.size_spin));
3720
3721 /* set tab label */
3722 if (mode == GIMV_THUMB_VIEW_MODE_RECURSIVE_DIR) {
3723 gchar *tmpstr, *dirname_internal;
3724 tmpstr = fileutil_home2tilde (tv->priv->dirname);
3725 dirname_internal = charset_to_internal (tmpstr,
3726 conf.charset_filename,
3727 conf.charset_auto_detect_fn,
3728 conf.charset_filename_mode);
3729 g_snprintf (buf, BUF_SIZE, _("%s (Collection)"), dirname_internal);
3730 g_free (dirname_internal);
3731 g_free (tmpstr);
3732 gimv_thumb_view_reset_tab_label (tv, buf);
3733 } else if (mode == GIMV_THUMB_VIEW_MODE_COLLECTION) {
3734 if (!tv->tabtitle) {
3735 g_snprintf (buf, BUF_SIZE, _("Collection %d"), total_tab_count);
3736 gimv_thumb_view_reset_tab_label (tv, buf);
3737 }
3738 } else {
3739 gimv_thumb_view_reset_tab_label (tv, NULL);
3740 }
3741 gimv_thumb_win_set_tab_label_state (tv->container, GTK_STATE_SELECTED);
3742
3743 gimv_thumb_win_location_entry_set_text (tv->tw, NULL);
3744
3745 /* fetch infomation about image files */
3746 if (tv->mode == GIMV_THUMB_VIEW_MODE_ARCHIVE) {
3747 gimv_thumb_view_insert_thumb_frames_from_archive (tv, files->archive);
3748 } else {
3749 if (tv->mode == GIMV_THUMB_VIEW_MODE_DIR && conf.thumbview_show_dir) {
3750 gchar *parent = g_strconcat (tv->priv->dirname, "..", NULL);
3751 GList *dirlist = g_list_copy (files->dirlist);
3752
3753 dirlist = g_list_prepend (dirlist, parent);
3754 gimv_thumb_view_insert_thumb_frames (tv, dirlist);
3755 g_list_free(dirlist);
3756 g_free (parent);
3757 }
3758 gimv_thumb_view_insert_thumb_frames (tv, files->filelist);
3759 }
3760
3761 /* set window status */
3762 if (tv->mode == GIMV_THUMB_VIEW_MODE_DIR && tv->priv->dirname)
3763 dirview_set_opened_mark (tv->tw->dv, tv->priv->dirname);
3764
3765 current_page = gtk_notebook_get_current_page (GTK_NOTEBOOK (tv->tw->notebook));
3766 this_page = gtk_notebook_page_num (GTK_NOTEBOOK (tv->tw->notebook),
3767 tv->container);
3768
3769 if (current_page == this_page) {
3770 tv->tw->status = GIMV_THUMB_WIN_STATUS_LOADING;
3771 gimv_thumb_win_set_sensitive (tv->tw, GIMV_THUMB_WIN_STATUS_LOADING);
3772 if (tv->mode == GIMV_THUMB_VIEW_MODE_DIR && tv->priv->dirname)
3773 dirview_change_dir (tv->tw->dv, tv->priv->dirname);
3774
3775 } else {
3776 tv->tw->status = GIMV_THUMB_WIN_STATUS_LOADING_BG;
3777 gimv_thumb_win_set_sensitive (tv->tw, GIMV_THUMB_WIN_STATUS_LOADING_BG);
3778 }
3779
3780 /* load thumbnails */
3781 if (tv->vfuncs->get_load_list)
3782 loadlist = tv->vfuncs->get_load_list (tv);
3783 if (loadlist) {
3784 gimv_thumb_view_load_thumbnails (tv, loadlist, tv->summary_mode);
3785 g_list_free (loadlist);
3786 }
3787
3788 /* reset window status */
3789 if (files->status > 0 && files->status < CANCEL) {
3790 files->status = THUMB_LOAD_DONE;
3791 }
3792
3793 if (files->status > 0) {
3794 tv->progress = NULL;
3795 /* reset status bar and tab label */
3796 tv->tw->status = GIMV_THUMB_WIN_STATUS_NORMAL;
3797 gimv_thumb_win_set_statusbar_page_info (tv->tw, GIMV_THUMB_WIN_CURRENT_PAGE);
3798 }
3799
3800 gimv_thumb_win_set_tab_label_state (tv->container, GTK_STATE_NORMAL);
3801 }
3802
3803
3804 static void
gimv_thumb_view_destroy(GtkObject * object)3805 gimv_thumb_view_destroy (GtkObject *object)
3806 {
3807 GimvThumbView *tv;
3808 GList *node;
3809
3810 g_return_if_fail (GIMV_IS_THUMB_VIEW (object));
3811
3812 tv = GIMV_THUMB_VIEW (object);
3813
3814 gimv_thumb_view_remove_scrollbar_callback (tv);
3815
3816 GimvThumbViewList = g_list_remove (GimvThumbViewList, tv);
3817
3818 if (GTK_BIN (tv->container)->child) {
3819 gtk_widget_destroy (GTK_BIN (tv->container)->child);
3820 GTK_BIN (tv->container)->child = NULL;
3821 }
3822
3823 if (tv->priv) {
3824 if (tv->tw && tv->tw->dv &&
3825 tv->mode == GIMV_THUMB_VIEW_MODE_DIR && tv->priv->dirname) {
3826 dirview_unset_opened_mark (tv->tw->dv, tv->priv->dirname);
3827 }
3828
3829 g_free (tv->priv->dirname);
3830 tv->priv->dirname = NULL;
3831
3832 /* remove archive */
3833 if (tv->mode == GIMV_THUMB_VIEW_MODE_ARCHIVE && tv->priv->archive) {
3834 fr_archive_unref (FR_ARCHIVE (tv->priv->archive));
3835 tv->priv->archive = NULL;
3836 }
3837
3838 /* destroy relation */
3839 node = tv->priv->related_image_view;
3840 while (node) {
3841 GimvImageView *iv = node->data;
3842 node = g_list_next(node);
3843 gimv_image_view_remove_list(iv, tv);
3844 }
3845 g_list_free (tv->priv->related_image_view);
3846 tv->priv->related_image_view = NULL;
3847
3848 g_list_foreach (tv->priv->related_dupl_win,
3849 (GFunc) gimv_thumb_view_destroy_dupl_win_relation,
3850 tv);
3851 g_list_free (tv->priv->related_dupl_win);
3852 tv->priv->related_dupl_win = NULL;
3853
3854 g_free (tv->priv);
3855 tv->priv = NULL;
3856 }
3857
3858 if (tv->tw) {
3859 tv->tw->filenum -= tv->filenum;
3860 tv->tw->filesize -= tv->filesize;
3861 tv->tw = NULL;
3862 }
3863
3864 if (tv->progress && tv->progress->status != WINDOW_DESTROYED) {
3865 tv->progress->status = CONTAINER_DESTROYED;
3866 tv->progress = NULL;
3867 }
3868
3869 /* remove thumbnails */
3870 g_list_foreach (tv->thumblist, (GFunc) gtk_object_unref, NULL);
3871 g_list_free(tv->thumblist);
3872 tv->thumblist = NULL;
3873
3874 /* remove popup menu */
3875 if (tv->popup_menu) {
3876 gtk_widget_unref (tv->popup_menu);
3877 tv->popup_menu = NULL;
3878 }
3879
3880 g_free (tv->tabtitle);
3881 tv->tabtitle = NULL;
3882 }
3883