4 * Copyright (C) 2008 The Geeqie Team
8 * This software is released under the GNU General Public License (GNU GPL).
9 * Please read the included file COPYING for more information.
10 * This software comes with no warranty of any kind, use at your own risk!
14 #include "view_file_list.h"
16 #include "cache_maint.h"
22 #include "layout_image.h"
26 #include "ui_bookmark.h"
27 #include "ui_fileops.h"
29 #include "ui_tree_edit.h"
30 #include "view_file.h"
32 #include <gdk/gdkkeysyms.h> /* for keyboard values */
36 FILE_COLUMN_POINTER = 0,
45 FILE_COLUMN_MARKS_LAST = FILE_COLUMN_MARKS + FILEDATA_MARKS_SIZE - 1,
50 static gint vflist_row_is_selected(ViewFile *vf, FileData *fd);
51 static gint vflist_row_rename_cb(TreeEditData *td, const gchar *old, const gchar *new, gpointer data);
52 static void vflist_populate_view(ViewFile *vf);
56 *-----------------------------------------------------------------------------
58 *-----------------------------------------------------------------------------
65 } ViewFileFindRowData;
67 static gboolean vflist_find_row_cb(GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, gpointer data)
69 ViewFileFindRowData *find = data;
71 gtk_tree_model_get(model, iter, FILE_COLUMN_POINTER, &fd, -1);
82 static gint vflist_find_row(ViewFile *vf, FileData *fd, GtkTreeIter *iter)
85 ViewFileFindRowData data = {fd, iter, 0, 0};
87 store = gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview));
88 gtk_tree_model_foreach(store, vflist_find_row_cb, &data);
100 static gint vflist_find_sidecar_list_idx(GList *work, FileData *fd)
105 FileData *fd_p = work->data;
106 if (fd == fd_p) return i;
110 GList *work2 = fd_p->sidecar_files;
114 if (fd == fd_p) return i;
125 static gint vflist_sidecar_list_count(GList *work)
130 FileData *fd = work->data;
133 GList *work2 = fd->sidecar_files;
144 static gboolean vflist_store_clear_cb(GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, gpointer data)
147 gtk_tree_model_get(model, iter, FILE_COLUMN_POINTER, &fd, -1);
152 static void vflist_store_clear(ViewFile *vf)
155 store = gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview));
156 gtk_tree_model_foreach(store, vflist_store_clear_cb, NULL);
157 gtk_tree_store_clear(GTK_TREE_STORE(store));
160 void vflist_color_set(ViewFile *vf, FileData *fd, gint color_set)
165 if (vflist_find_row(vf, fd, &iter) < 0) return;
166 store = gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview));
167 gtk_tree_store_set(GTK_TREE_STORE(store), &iter, FILE_COLUMN_COLOR, color_set, -1);
170 static void vflist_move_cursor(ViewFile *vf, GtkTreeIter *iter)
175 store = gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview));
177 tpath = gtk_tree_model_get_path(store, iter);
178 gtk_tree_view_set_cursor(GTK_TREE_VIEW(vf->listview), tpath, NULL, FALSE);
179 gtk_tree_path_free(tpath);
183 static gint vflist_column_idx(ViewFile *vf, gint store_idx)
185 GList *columns, *work;
188 columns = gtk_tree_view_get_columns(GTK_TREE_VIEW(vf->listview));
192 GtkTreeViewColumn *column = work->data;
193 if (store_idx == GPOINTER_TO_INT(g_object_get_data (G_OBJECT(column), "column_store_idx")))
199 g_list_free(columns);
205 *-----------------------------------------------------------------------------
207 *-----------------------------------------------------------------------------
210 static void vflist_dnd_get(GtkWidget *widget, GdkDragContext *context,
211 GtkSelectionData *selection_data, guint info,
212 guint time, gpointer data)
216 gchar *uri_text = NULL;
219 if (!VFLIST_INFO(vf, click_fd)) return;
221 if (vflist_row_is_selected(vf, VFLIST_INFO(vf, click_fd)))
223 list = vf_selection_get_list(vf);
227 list = g_list_append(NULL, file_data_ref(VFLIST_INFO(vf, click_fd)));
232 uri_text = uri_text_from_filelist(list, &total, (info == TARGET_TEXT_PLAIN));
237 gtk_selection_data_set(selection_data, selection_data->target,
238 8, (guchar *)uri_text, total);
242 static void vflist_dnd_begin(GtkWidget *widget, GdkDragContext *context, gpointer data)
246 vflist_color_set(vf, VFLIST_INFO(vf, click_fd), TRUE);
248 if (VFLIST_INFO(vf, thumbs_enabled) &&
249 VFLIST_INFO(vf, click_fd) && VFLIST_INFO(vf, click_fd)->pixbuf)
253 if (vflist_row_is_selected(vf, VFLIST_INFO(vf, click_fd)))
254 items = vf_selection_count(vf, NULL);
258 dnd_set_drag_icon(widget, context, VFLIST_INFO(vf, click_fd)->pixbuf, items);
262 static void vflist_dnd_end(GtkWidget *widget, GdkDragContext *context, gpointer data)
266 vflist_color_set(vf, VFLIST_INFO(vf, click_fd), FALSE);
268 if (context->action == GDK_ACTION_MOVE)
274 void vflist_dnd_init(ViewFile *vf)
276 gtk_drag_source_set(vf->listview, GDK_BUTTON1_MASK | GDK_BUTTON2_MASK,
277 dnd_file_drag_types, dnd_file_drag_types_count,
278 GDK_ACTION_COPY | GDK_ACTION_MOVE | GDK_ACTION_LINK);
279 g_signal_connect(G_OBJECT(vf->listview), "drag_data_get",
280 G_CALLBACK(vflist_dnd_get), vf);
281 g_signal_connect(G_OBJECT(vf->listview), "drag_begin",
282 G_CALLBACK(vflist_dnd_begin), vf);
283 g_signal_connect(G_OBJECT(vf->listview), "drag_end",
284 G_CALLBACK(vflist_dnd_end), vf);
288 *-----------------------------------------------------------------------------
290 *-----------------------------------------------------------------------------
293 GList *vflist_pop_menu_file_list(ViewFile *vf)
295 if (!VFLIST_INFO(vf, click_fd)) return NULL;
297 if (vflist_row_is_selected(vf, VFLIST_INFO(vf, click_fd)))
299 return vf_selection_get_list(vf);
302 return g_list_append(NULL, file_data_ref(VFLIST_INFO(vf, click_fd)));
305 void vflist_pop_menu_view_cb(GtkWidget *widget, gpointer data)
309 if (vflist_row_is_selected(vf, VFLIST_INFO(vf, click_fd)))
313 list = vf_selection_get_list(vf);
314 view_window_new_from_list(list);
319 view_window_new(VFLIST_INFO(vf, click_fd));
323 void vflist_pop_menu_rename_cb(GtkWidget *widget, gpointer data)
328 list = vf_pop_menu_file_list(vf);
329 if (options->file_ops.enable_in_place_rename &&
330 list && !list->next && VFLIST_INFO(vf, click_fd))
337 store = gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview));
338 if (vflist_find_row(vf, VFLIST_INFO(vf, click_fd), &iter) >= 0)
342 tpath = gtk_tree_model_get_path(store, &iter);
343 tree_edit_by_path(GTK_TREE_VIEW(vf->listview), tpath,
344 vflist_column_idx(vf, FILE_COLUMN_NAME), VFLIST_INFO(vf, click_fd)->name,
345 vflist_row_rename_cb, vf);
346 gtk_tree_path_free(tpath);
351 file_util_rename(NULL, list, vf->listview);
354 void vflist_pop_menu_thumbs_cb(GtkWidget *widget, gpointer data)
358 vflist_color_set(vf, VFLIST_INFO(vf, click_fd), FALSE);
361 layout_thumb_set(vf->layout, !VFLIST_INFO(vf, thumbs_enabled));
365 vflist_thumb_set(vf, !VFLIST_INFO(vf, thumbs_enabled));
369 void vflist_pop_menu_refresh_cb(GtkWidget *widget, gpointer data)
373 vflist_color_set(vf, VFLIST_INFO(vf, click_fd), FALSE);
377 void vflist_popup_destroy_cb(GtkWidget *widget, gpointer data)
380 vflist_color_set(vf, VFLIST_INFO(vf, click_fd), FALSE);
381 VFLIST_INFO(vf, click_fd) = NULL;
387 *-----------------------------------------------------------------------------
389 *-----------------------------------------------------------------------------
392 static gint vflist_row_rename_cb(TreeEditData *td, const gchar *old, const gchar *new, gpointer data)
398 if (strlen(new) == 0) return FALSE;
400 old_path = g_build_filename(vf->dir_fd->path, old, NULL);
401 new_path = g_build_filename(vf->dir_fd->path, new, NULL);
403 if (strchr(new, G_DIR_SEPARATOR) != NULL)
405 gchar *text = g_strdup_printf(_("Invalid file name:\n%s"), new);
406 file_util_warning_dialog(_("Error renaming file"), text, GTK_STOCK_DIALOG_ERROR, vf->listview);
409 else if (isfile(new_path))
411 gchar *text = g_strdup_printf(_("A file with name %s already exists."), new);
412 file_util_warning_dialog(_("Error renaming file"), text, GTK_STOCK_DIALOG_ERROR, vf->listview);
417 gint row = vf_index_by_path(vf, old_path);
420 GList *work = g_list_nth(vf->list, row);
421 FileData *fd = work->data;
423 file_util_rename_simple(fd, new_path, vf->listview);
434 static void vflist_menu_position_cb(GtkMenu *menu, gint *x, gint *y, gboolean *push_in, gpointer data)
442 if (vflist_find_row(vf, VFLIST_INFO(vf, click_fd), &iter) < 0) return;
443 store = gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview));
444 tpath = gtk_tree_model_get_path(store, &iter);
445 tree_view_get_cell_clamped(GTK_TREE_VIEW(vf->listview), tpath, FILE_COLUMN_NAME - 1, TRUE, x, y, &cw, &ch);
446 gtk_tree_path_free(tpath);
448 popup_menu_position_clamp(menu, x, y, 0);
451 gint vflist_press_key_cb(GtkWidget *widget, GdkEventKey *event, gpointer data)
456 if (event->keyval != GDK_Menu) return FALSE;
458 gtk_tree_view_get_cursor(GTK_TREE_VIEW(vf->listview), &tpath, NULL);
464 store = gtk_tree_view_get_model(GTK_TREE_VIEW(widget));
465 gtk_tree_model_get_iter(store, &iter, tpath);
466 gtk_tree_model_get(store, &iter, FILE_COLUMN_POINTER, &VFLIST_INFO(vf, click_fd), -1);
467 gtk_tree_path_free(tpath);
471 VFLIST_INFO(vf, click_fd) = NULL;
474 vf->popup = vf_pop_menu(vf);
475 gtk_menu_popup(GTK_MENU(vf->popup), NULL, NULL, vflist_menu_position_cb, vf, 0, GDK_CURRENT_TIME);
480 gint vflist_press_cb(GtkWidget *widget, GdkEventButton *bevent, gpointer data)
486 GtkTreeViewColumn *column;
488 vf->clicked_mark = 0;
490 if (gtk_tree_view_get_path_at_pos(GTK_TREE_VIEW(widget), bevent->x, bevent->y,
491 &tpath, &column, NULL, NULL))
494 gint col_idx = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(column), "column_store_idx"));
496 if (bevent->button == MOUSE_BUTTON_LEFT &&
497 col_idx >= FILE_COLUMN_MARKS && col_idx <= FILE_COLUMN_MARKS_LAST)
500 if (col_idx >= FILE_COLUMN_MARKS && col_idx <= FILE_COLUMN_MARKS_LAST)
501 vf->clicked_mark = 1 + (col_idx - FILE_COLUMN_MARKS);
503 store = gtk_tree_view_get_model(GTK_TREE_VIEW(widget));
505 gtk_tree_model_get_iter(store, &iter, tpath);
506 gtk_tree_model_get(store, &iter, FILE_COLUMN_POINTER, &fd, -1);
508 gtk_tree_view_set_cursor(GTK_TREE_VIEW(widget), tpath, NULL, FALSE);
510 gtk_tree_path_free(tpath);
513 VFLIST_INFO(vf, click_fd) = fd;
515 if (bevent->button == MOUSE_BUTTON_RIGHT)
517 vf->popup = vf_pop_menu(vf);
518 gtk_menu_popup(GTK_MENU(vf->popup), NULL, NULL, NULL, NULL,
519 bevent->button, bevent->time);
523 if (!fd) return FALSE;
525 if (bevent->button == MOUSE_BUTTON_MIDDLE)
527 if (!vflist_row_is_selected(vf, fd))
529 vflist_color_set(vf, fd, TRUE);
535 if (bevent->button == MOUSE_BUTTON_LEFT && bevent->type == GDK_BUTTON_PRESS &&
536 !(bevent->state & GDK_SHIFT_MASK ) &&
537 !(bevent->state & GDK_CONTROL_MASK ) &&
538 vflist_row_is_selected(vf, fd))
540 GtkTreeSelection *selection;
542 gtk_widget_grab_focus(widget);
545 /* returning FALSE and further processing of the event is needed for
546 correct operation of the expander, to show the sidecar files.
547 It however resets the selection of multiple files. With this condition
548 it should work for both cases */
549 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(widget));
550 return (gtk_tree_selection_count_selected_rows(selection) > 1);
554 if (bevent->button == MOUSE_BUTTON_LEFT && bevent->type == GDK_2BUTTON_PRESS)
556 if (vf->layout) layout_image_full_screen_start(vf->layout);
563 gint vflist_release_cb(GtkWidget *widget, GdkEventButton *bevent, gpointer data)
570 if (bevent->button == MOUSE_BUTTON_MIDDLE)
572 vflist_color_set(vf, VFLIST_INFO(vf, click_fd), FALSE);
575 if (bevent->button != MOUSE_BUTTON_LEFT && bevent->button != MOUSE_BUTTON_MIDDLE)
580 if ((bevent->x != 0 || bevent->y != 0) &&
581 gtk_tree_view_get_path_at_pos(GTK_TREE_VIEW(widget), bevent->x, bevent->y,
582 &tpath, NULL, NULL, NULL))
586 store = gtk_tree_view_get_model(GTK_TREE_VIEW(widget));
587 gtk_tree_model_get_iter(store, &iter, tpath);
588 gtk_tree_model_get(store, &iter, FILE_COLUMN_POINTER, &fd, -1);
589 gtk_tree_path_free(tpath);
592 if (bevent->button == MOUSE_BUTTON_MIDDLE)
594 if (fd && VFLIST_INFO(vf, click_fd) == fd)
596 GtkTreeSelection *selection;
598 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(widget));
599 if (vflist_row_is_selected(vf, fd))
601 gtk_tree_selection_unselect_iter(selection, &iter);
605 gtk_tree_selection_select_iter(selection, &iter);
611 if (fd && VFLIST_INFO(vf, click_fd) == fd &&
612 !(bevent->state & GDK_SHIFT_MASK ) &&
613 !(bevent->state & GDK_CONTROL_MASK ) &&
614 vflist_row_is_selected(vf, fd))
616 GtkTreeSelection *selection;
618 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(widget));
619 gtk_tree_selection_unselect_all(selection);
620 gtk_tree_selection_select_iter(selection, &iter);
621 vflist_move_cursor(vf, &iter);
622 // return TRUE;// FIXME - expand
628 static void vflist_select_image(ViewFile *vf, FileData *sel_fd)
630 FileData *read_ahead_fd = NULL;
635 cur_fd = layout_image_get_fd(vf->layout);
636 if (sel_fd == cur_fd) return; /* no change */
638 row = g_list_index(vf->list, sel_fd);
639 // FIXME sidecar data
641 if (sel_fd && options->image.enable_read_ahead && row >= 0)
643 if (row > g_list_index(vf->list, cur_fd) &&
644 (guint) (row + 1) < vf_count(vf, NULL))
646 read_ahead_fd = vf_index_get_data(vf, row + 1);
650 read_ahead_fd = vf_index_get_data(vf, row - 1);
654 layout_image_set_with_ahead(vf->layout, sel_fd, read_ahead_fd);
657 static gint vflist_select_idle_cb(gpointer data)
663 VFLIST_INFO(vf, select_idle_id) = -1;
669 if (VFLIST_INFO(vf, select_fd))
671 vflist_select_image(vf, VFLIST_INFO(vf, select_fd));
672 VFLIST_INFO(vf, select_fd) = NULL;
675 VFLIST_INFO(vf, select_idle_id) = -1;
679 static void vflist_select_idle_cancel(ViewFile *vf)
681 if (VFLIST_INFO(vf, select_idle_id) != -1) g_source_remove(VFLIST_INFO(vf, select_idle_id));
682 VFLIST_INFO(vf, select_idle_id) = -1;
685 static gboolean vflist_select_cb(GtkTreeSelection *selection, GtkTreeModel *store, GtkTreePath *tpath,
686 gboolean path_currently_selected, gpointer data)
691 if (!path_currently_selected &&
692 gtk_tree_model_get_iter(store, &iter, tpath))
694 gtk_tree_model_get(store, &iter, FILE_COLUMN_POINTER, &VFLIST_INFO(vf, select_fd), -1);
698 VFLIST_INFO(vf, select_fd) = NULL;
702 VFLIST_INFO(vf, select_idle_id) == -1)
704 VFLIST_INFO(vf, select_idle_id) = g_idle_add(vflist_select_idle_cb, vf);
711 *-----------------------------------------------------------------------------
713 *-----------------------------------------------------------------------------
717 static gboolean vflist_dummy_select_cb(GtkTreeSelection *selection, GtkTreeModel *store, GtkTreePath *tpath,
718 gboolean path_currently_selected, gpointer data)
724 static void vflist_setup_iter(ViewFile *vf, GtkTreeStore *store, GtkTreeIter *iter, FileData *fd)
727 gchar *sidecars = NULL;
729 if (fd->sidecar_files)
730 sidecars = file_data_sc_list_to_string(fd);
731 size = text_from_size(fd->size);
733 gtk_tree_store_set(store, iter, FILE_COLUMN_POINTER, fd,
734 FILE_COLUMN_VERSION, fd->version,
735 FILE_COLUMN_THUMB, fd->pixbuf,
736 FILE_COLUMN_NAME, fd->name,
737 FILE_COLUMN_SIDECARS, sidecars,
738 FILE_COLUMN_SIZE, size,
739 FILE_COLUMN_DATE, text_from_time(fd->date),
740 #define STORE_SET_IS_SLOW 1
741 #if STORE_SET_IS_SLOW
742 /* this is 3x faster on a directory with 20000 files */
743 FILE_COLUMN_MARKS + 0, file_data_get_mark(fd, 0),
744 FILE_COLUMN_MARKS + 1, file_data_get_mark(fd, 1),
745 FILE_COLUMN_MARKS + 2, file_data_get_mark(fd, 2),
746 FILE_COLUMN_MARKS + 3, file_data_get_mark(fd, 3),
747 FILE_COLUMN_MARKS + 4, file_data_get_mark(fd, 4),
748 FILE_COLUMN_MARKS + 5, file_data_get_mark(fd, 5),
749 #if FILEDATA_MARKS_SIZE != 6
750 #error this needs to be updated
753 FILE_COLUMN_COLOR, FALSE, -1);
755 #if !STORE_SET_IS_SLOW
758 for (i = 0; i < FILEDATA_MARKS_SIZE; i++)
759 gtk_tree_store_set(store, iter, FILE_COLUMN_MARKS + i, file_data_get_mark(fd, i), -1);
767 static void vflist_setup_iter_recursive(ViewFile *vf, GtkTreeStore *store, GtkTreeIter *parent_iter, GList *list, GList *selected)
773 valid = gtk_tree_model_iter_children(GTK_TREE_MODEL(store), &iter, parent_iter);
779 FileData *fd = work->data;
784 FileData *old_fd = NULL;
785 gint old_version = 0;
789 gtk_tree_model_get(GTK_TREE_MODEL(store), &iter,
790 FILE_COLUMN_POINTER, &old_fd,
791 FILE_COLUMN_VERSION, &old_version,
801 match = filelist_sort_compare_filedata_full(fd, old_fd, SORT_NAME, TRUE); /* always sort sidecars by name */
803 match = filelist_sort_compare_filedata_full(fd, old_fd, vf->sort_method, vf->sort_ascend);
805 if (match == 0) g_warning("multiple fd for the same path");
820 gtk_tree_store_insert_before(store, &new, parent_iter, &iter);
824 gtk_tree_store_append(store, &new, parent_iter);
827 vflist_setup_iter(vf, store, &new, file_data_ref(fd));
828 vflist_setup_iter_recursive(vf, store, &new, fd->sidecar_files, selected);
830 if (g_list_find(selected, fd))
832 /* renamed files - the same fd appears at different position - select it again*/
833 GtkTreeSelection *selection;
834 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(vf->listview));
835 gtk_tree_selection_select_iter(selection, &new);
842 file_data_unref(old_fd);
843 valid = gtk_tree_store_remove(store, &iter);
847 if (fd->version != old_version)
849 vflist_setup_iter(vf, store, &iter, fd);
850 vflist_setup_iter_recursive(vf, store, &iter, fd->sidecar_files, selected);
853 if (valid) valid = gtk_tree_model_iter_next(GTK_TREE_MODEL(store), &iter);
864 gtk_tree_model_get(GTK_TREE_MODEL(store), &iter, FILE_COLUMN_POINTER, &old_fd, -1);
865 file_data_unref(old_fd);
867 valid = gtk_tree_store_remove(store, &iter);
871 void vflist_sort_set(ViewFile *vf, SortType type, gint ascend)
874 GHashTable *fd_idx_hash = g_hash_table_new(NULL, NULL);
879 if (vf->sort_method == type && vf->sort_ascend == ascend) return;
880 if (!vf->list) return;
886 FileData *fd = work->data;
887 g_hash_table_insert(fd_idx_hash, fd, GINT_TO_POINTER(i));
892 vf->sort_method = type;
893 vf->sort_ascend = ascend;
895 vf->list = filelist_sort(vf->list, vf->sort_method, vf->sort_ascend);
897 new_order = g_malloc(i * sizeof(gint));
903 FileData *fd = work->data;
904 new_order[i] = GPOINTER_TO_INT(g_hash_table_lookup(fd_idx_hash, fd));
909 store = GTK_TREE_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview)));
910 gtk_tree_store_reorder(store, NULL, new_order);
913 g_hash_table_destroy(fd_idx_hash);
917 *-----------------------------------------------------------------------------
919 *-----------------------------------------------------------------------------
922 static gint vflist_thumb_next(ViewFile *vf);
924 static void vflist_thumb_status(ViewFile *vf, gdouble val, const gchar *text)
926 if (vf->func_thumb_status)
928 vf->func_thumb_status(vf, val, text, vf->data_thumb_status);
932 static void vflist_thumb_cleanup(ViewFile *vf)
934 vflist_thumb_status(vf, 0.0, NULL);
936 vf->thumbs_count = 0;
937 vf->thumbs_running = FALSE;
939 thumb_loader_free(vf->thumbs_loader);
940 vf->thumbs_loader = NULL;
942 vf->thumbs_filedata = NULL;
945 static void vflist_thumb_stop(ViewFile *vf)
947 if (vf->thumbs_running) vflist_thumb_cleanup(vf);
950 static void vflist_thumb_do(ViewFile *vf, ThumbLoader *tl, FileData *fd)
955 if (!fd || vflist_find_row(vf, fd, &iter) < 0) return;
957 if (fd->pixbuf) g_object_unref(fd->pixbuf);
958 fd->pixbuf = thumb_loader_get_pixbuf(tl, TRUE);
960 store = GTK_TREE_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview)));
961 gtk_tree_store_set(store, &iter, FILE_COLUMN_THUMB, fd->pixbuf, -1);
963 vflist_thumb_status(vf, (gdouble)(vf->thumbs_count) / vflist_sidecar_list_count(vf->list), _("Loading thumbs..."));
966 static void vflist_thumb_error_cb(ThumbLoader *tl, gpointer data)
970 if (vf->thumbs_filedata && vf->thumbs_loader == tl)
972 vflist_thumb_do(vf, tl, vf->thumbs_filedata);
975 while (vflist_thumb_next(vf));
978 static void vflist_thumb_done_cb(ThumbLoader *tl, gpointer data)
982 if (vf->thumbs_filedata && vf->thumbs_loader == tl)
984 vflist_thumb_do(vf, tl, vf->thumbs_filedata);
987 while (vflist_thumb_next(vf));
990 static gint vflist_thumb_next(ViewFile *vf)
995 /* first check the visible files */
997 if (GTK_WIDGET_REALIZED(vf->listview) &&
998 gtk_tree_view_get_path_at_pos(GTK_TREE_VIEW(vf->listview), 0, 0, &tpath, NULL, NULL, NULL))
1000 GtkTreeModel *store;
1004 store = gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview));
1005 gtk_tree_model_get_iter(store, &iter, tpath);
1006 gtk_tree_path_free(tpath);
1008 while (!fd && valid && tree_view_row_get_visibility(GTK_TREE_VIEW(vf->listview), &iter, FALSE) == 0)
1010 gtk_tree_model_get(store, &iter, FILE_COLUMN_POINTER, &fd, -1);
1011 if (fd->pixbuf) fd = NULL;
1013 valid = gtk_tree_model_iter_next(store, &iter);
1017 /* then find first undone */
1021 GList *work = vf->list;
1024 FileData *fd_p = work->data;
1029 GList *work2 = fd_p->sidecar_files;
1031 while (work2 && !fd)
1034 if (!fd_p->pixbuf) fd = fd_p;
1035 work2 = work2->next;
1045 vflist_thumb_cleanup(vf);
1051 vf->thumbs_filedata = fd;
1053 thumb_loader_free(vf->thumbs_loader);
1055 vf->thumbs_loader = thumb_loader_new(options->thumbnails.max_width, options->thumbnails.max_height);
1056 thumb_loader_set_callbacks(vf->thumbs_loader,
1057 vflist_thumb_done_cb,
1058 vflist_thumb_error_cb,
1062 if (!thumb_loader_start(vf->thumbs_loader, fd->path))
1064 /* set icon to unknown, continue */
1065 DEBUG_1("thumb loader start failed %s", vf->thumbs_loader->path);
1066 vflist_thumb_do(vf, vf->thumbs_loader, fd);
1074 static void vflist_thumb_update(ViewFile *vf)
1076 vflist_thumb_stop(vf);
1077 if (!VFLIST_INFO(vf, thumbs_enabled)) return;
1079 vflist_thumb_status(vf, 0.0, _("Loading thumbs..."));
1080 vf->thumbs_running = TRUE;
1082 while (vflist_thumb_next(vf));
1086 *-----------------------------------------------------------------------------
1088 *-----------------------------------------------------------------------------
1091 FileData *vflist_index_get_data(ViewFile *vf, gint row)
1093 return g_list_nth_data(vf->list, row);
1096 gint vflist_index_by_path(ViewFile *vf, const gchar *path)
1101 if (!path) return -1;
1106 FileData *fd = work->data;
1107 if (strcmp(path, fd->path) == 0) return p;
1116 guint vflist_count(ViewFile *vf, gint64 *bytes)
1126 FileData *fd = work->data;
1134 return g_list_length(vf->list);
1137 GList *vflist_get_list(ViewFile *vf)
1145 FileData *fd = work->data;
1148 list = g_list_prepend(list, file_data_ref(fd));
1151 return g_list_reverse(list);
1155 *-----------------------------------------------------------------------------
1157 *-----------------------------------------------------------------------------
1160 static gint vflist_row_is_selected(ViewFile *vf, FileData *fd)
1162 GtkTreeModel *store;
1163 GtkTreeSelection *selection;
1168 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(vf->listview));
1169 slist = gtk_tree_selection_get_selected_rows(selection, &store);
1171 while (!found && work)
1173 GtkTreePath *tpath = work->data;
1177 gtk_tree_model_get_iter(store, &iter, tpath);
1178 gtk_tree_model_get(store, &iter, FILE_COLUMN_POINTER, &fd_n, -1);
1179 if (fd_n == fd) found = TRUE;
1182 g_list_foreach(slist, (GFunc)gtk_tree_path_free, NULL);
1188 gint vflist_index_is_selected(ViewFile *vf, gint row)
1192 fd = vf_index_get_data(vf, row);
1193 return vflist_row_is_selected(vf, fd);
1196 guint vflist_selection_count(ViewFile *vf, gint64 *bytes)
1198 GtkTreeModel *store;
1199 GtkTreeSelection *selection;
1203 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(vf->listview));
1204 slist = gtk_tree_selection_get_selected_rows(selection, &store);
1214 GtkTreePath *tpath = work->data;
1218 gtk_tree_model_get_iter(store, &iter, tpath);
1219 gtk_tree_model_get(store, &iter, FILE_COLUMN_POINTER, &fd, -1);
1228 count = g_list_length(slist);
1229 g_list_foreach(slist, (GFunc)gtk_tree_path_free, NULL);
1235 GList *vflist_selection_get_list(ViewFile *vf)
1237 GtkTreeModel *store;
1238 GtkTreeSelection *selection;
1243 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(vf->listview));
1244 slist = gtk_tree_selection_get_selected_rows(selection, &store);
1248 GtkTreePath *tpath = work->data;
1252 gtk_tree_model_get_iter(store, &iter, tpath);
1253 gtk_tree_model_get(store, &iter, FILE_COLUMN_POINTER, &fd, -1);
1255 list = g_list_prepend(list, file_data_ref(fd));
1259 g_list_foreach(slist, (GFunc)gtk_tree_path_free, NULL);
1262 return g_list_reverse(list);
1265 GList *vflist_selection_get_list_by_index(ViewFile *vf)
1267 GtkTreeModel *store;
1268 GtkTreeSelection *selection;
1273 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(vf->listview));
1274 slist = gtk_tree_selection_get_selected_rows(selection, &store);
1278 GtkTreePath *tpath = work->data;
1282 gtk_tree_model_get_iter(store, &iter, tpath);
1283 gtk_tree_model_get(store, &iter, FILE_COLUMN_POINTER, &fd, -1);
1285 list = g_list_prepend(list, GINT_TO_POINTER(g_list_index(vf->list, fd)));
1289 g_list_foreach(slist, (GFunc)gtk_tree_path_free, NULL);
1292 return g_list_reverse(list);
1295 void vflist_select_all(ViewFile *vf)
1297 GtkTreeSelection *selection;
1299 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(vf->listview));
1300 gtk_tree_selection_select_all(selection);
1302 VFLIST_INFO(vf, select_fd) = NULL;
1305 void vflist_select_none(ViewFile *vf)
1307 GtkTreeSelection *selection;
1309 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(vf->listview));
1310 gtk_tree_selection_unselect_all(selection);
1313 static gboolean tree_model_iter_prev(GtkTreeModel *store, GtkTreeIter *iter)
1318 tpath = gtk_tree_model_get_path(store, iter);
1319 result = gtk_tree_path_prev(tpath);
1321 gtk_tree_model_get_iter(store, iter, tpath);
1323 gtk_tree_path_free(tpath);
1328 static gboolean tree_model_get_iter_last(GtkTreeModel *store, GtkTreeIter *iter)
1330 if (!gtk_tree_model_get_iter_first(store, iter))
1335 GtkTreeIter next = *iter;
1337 if (gtk_tree_model_iter_next(store, &next))
1346 void vflist_select_invert(ViewFile *vf)
1349 GtkTreeSelection *selection;
1350 GtkTreeModel *store;
1353 store = gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview));
1354 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(vf->listview));
1356 /* Backward iteration prevents scrolling to the end of the list,
1357 * it scrolls to the first selected row instead. */
1358 valid = tree_model_get_iter_last(store, &iter);
1362 gint selected = gtk_tree_selection_iter_is_selected(selection, &iter);
1365 gtk_tree_selection_unselect_iter(selection, &iter);
1367 gtk_tree_selection_select_iter(selection, &iter);
1369 valid = tree_model_iter_prev(store, &iter);
1373 void vflist_select_by_fd(ViewFile *vf, FileData *fd)
1377 if (vflist_find_row(vf, fd, &iter) < 0) return;
1379 tree_view_row_make_visible(GTK_TREE_VIEW(vf->listview), &iter, TRUE);
1381 if (!vflist_row_is_selected(vf, fd))
1383 GtkTreeSelection *selection;
1384 GtkTreeModel *store;
1387 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(vf->listview));
1388 gtk_tree_selection_unselect_all(selection);
1389 gtk_tree_selection_select_iter(selection, &iter);
1390 vflist_move_cursor(vf, &iter);
1392 store = gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview));
1393 tpath = gtk_tree_model_get_path(store, &iter);
1394 gtk_tree_view_set_cursor(GTK_TREE_VIEW(vf->listview), tpath, NULL, FALSE);
1395 gtk_tree_path_free(tpath);
1399 static void vflist_select_closest(ViewFile *vf, FileData *sel_fd)
1403 if (sel_fd->parent) sel_fd = sel_fd->parent;
1409 FileData *fd = work->data;
1413 match = filelist_sort_compare_filedata_full(fd, sel_fd, vf->sort_method, vf->sort_ascend);
1417 vflist_select_by_fd(vf, fd);
1424 void vflist_mark_to_selection(ViewFile *vf, gint mark, MarkToSelectionMode mode)
1426 GtkTreeModel *store;
1428 GtkTreeSelection *selection;
1432 g_assert(mark >= 1 && mark <= FILEDATA_MARKS_SIZE);
1434 store = gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview));
1435 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(vf->listview));
1437 valid = gtk_tree_model_get_iter_first(store, &iter);
1441 gboolean mark_val, selected;
1442 gtk_tree_model_get(GTK_TREE_MODEL(store), &iter, FILE_COLUMN_POINTER, &fd, -1);
1444 mark_val = file_data_get_mark(fd, n);
1445 selected = gtk_tree_selection_iter_is_selected(selection, &iter);
1449 case MTS_MODE_SET: selected = mark_val;
1451 case MTS_MODE_OR: selected = mark_val | selected;
1453 case MTS_MODE_AND: selected = mark_val & selected;
1455 case MTS_MODE_MINUS: selected = !mark_val & selected;
1460 gtk_tree_selection_select_iter(selection, &iter);
1462 gtk_tree_selection_unselect_iter(selection, &iter);
1464 valid = gtk_tree_model_iter_next(GTK_TREE_MODEL(store), &iter);
1468 void vflist_selection_to_mark(ViewFile *vf, gint mark, SelectionToMarkMode mode)
1470 GtkTreeModel *store;
1471 GtkTreeSelection *selection;
1476 g_assert(mark >= 1 && mark <= FILEDATA_MARKS_SIZE);
1478 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(vf->listview));
1479 slist = gtk_tree_selection_get_selected_rows(selection, &store);
1483 GtkTreePath *tpath = work->data;
1487 gtk_tree_model_get_iter(store, &iter, tpath);
1488 gtk_tree_model_get(store, &iter, FILE_COLUMN_POINTER, &fd, -1);
1490 file_data_unregister_notify_func(vf_notify_cb, vf); /* we don't need the notification */
1494 case STM_MODE_SET: file_data_set_mark(fd, n, 1);
1496 case STM_MODE_RESET: file_data_set_mark(fd, n, 0);
1498 case STM_MODE_TOGGLE: file_data_set_mark(fd, n, !file_data_get_mark(fd, n));
1502 file_data_register_notify_func(vf_notify_cb, vf, NOTIFY_PRIORITY_MEDIUM);
1504 gtk_tree_store_set(GTK_TREE_STORE(store), &iter, FILE_COLUMN_MARKS + n, file_data_get_mark(fd, n), -1);
1508 g_list_foreach(slist, (GFunc)gtk_tree_path_free, NULL);
1513 *-----------------------------------------------------------------------------
1515 *-----------------------------------------------------------------------------
1518 static void vflist_listview_set_height(GtkWidget *listview, gint thumb)
1520 GtkTreeViewColumn *column;
1521 GtkCellRenderer *cell;
1524 column = gtk_tree_view_get_column(GTK_TREE_VIEW(listview), 0); /* first column is thumbnail */
1525 if (!column) return;
1527 gtk_tree_view_column_set_visible(column, thumb);
1529 gtk_tree_view_column_set_fixed_width(column, options->thumbnails.max_width + 40);
1531 list = gtk_tree_view_column_get_cell_renderers(column);
1536 g_object_set(G_OBJECT(cell), "height", options->thumbnails.max_height, NULL);
1537 gtk_tree_view_columns_autosize(GTK_TREE_VIEW(listview));
1540 static void vflist_populate_view(ViewFile *vf)
1542 GtkTreeStore *store;
1544 GtkTreeRowReference *visible_row = NULL;
1548 store = GTK_TREE_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview)));
1549 thumbs = VFLIST_INFO(vf, thumbs_enabled);
1551 vflist_thumb_stop(vf);
1555 vflist_store_clear(vf);
1560 if (GTK_WIDGET_REALIZED(vf->listview) &&
1561 gtk_tree_view_get_path_at_pos(GTK_TREE_VIEW(vf->listview), 0, 0, &tpath, NULL, NULL, NULL))
1563 visible_row = gtk_tree_row_reference_new(GTK_TREE_MODEL(store), tpath);
1564 gtk_tree_path_free(tpath);
1567 vflist_listview_set_height(vf->listview, thumbs);
1569 selected = vflist_selection_get_list(vf);
1571 vflist_setup_iter_recursive(vf, store, NULL, vf->list, selected);
1573 if (selected && vflist_selection_count(vf, NULL) == 0)
1575 /* all selected files disappeared */
1576 vflist_select_closest(vf, selected->data);
1579 filelist_free(selected);
1583 if (gtk_tree_row_reference_valid(visible_row))
1585 tpath = gtk_tree_row_reference_get_path(visible_row);
1586 gtk_tree_view_scroll_to_cell(GTK_TREE_VIEW(vf->listview), tpath, NULL, TRUE, 0.0, 0.0);
1587 gtk_tree_path_free(tpath);
1589 gtk_tree_row_reference_free(visible_row);
1593 vflist_thumb_update(vf);
1596 gint vflist_refresh(ViewFile *vf)
1601 old_list = vf->list;
1604 DEBUG_1("%s vflist_refresh: read dir", get_exec_time());
1607 file_data_unregister_notify_func(vf_notify_cb, vf); /* we don't need the notification of changes detected by filelist_read */
1609 ret = filelist_read(vf->dir_fd, &vf->list, NULL);
1611 file_data_register_notify_func(vf_notify_cb, vf, NOTIFY_PRIORITY_MEDIUM);
1613 DEBUG_1("%s vflist_refresh: sort", get_exec_time());
1614 vf->list = filelist_sort(vf->list, vf->sort_method, vf->sort_ascend);
1617 DEBUG_1("%s vflist_refresh: populate view", get_exec_time());
1619 vflist_populate_view(vf);
1621 filelist_free(old_list);
1622 DEBUG_1("%s vflist_refresh: done", get_exec_time());
1629 /* this overrides the low default of a GtkCellRenderer from 100 to CELL_HEIGHT_OVERRIDE, something sane for our purposes */
1631 #define CELL_HEIGHT_OVERRIDE 512
1633 static void cell_renderer_height_override(GtkCellRenderer *renderer)
1637 spec = g_object_class_find_property(G_OBJECT_GET_CLASS(G_OBJECT(renderer)), "height");
1638 if (spec && G_IS_PARAM_SPEC_INT(spec))
1640 GParamSpecInt *spec_int;
1642 spec_int = G_PARAM_SPEC_INT(spec);
1643 if (spec_int->maximum < CELL_HEIGHT_OVERRIDE) spec_int->maximum = CELL_HEIGHT_OVERRIDE;
1647 static GdkColor *vflist_listview_color_shifted(GtkWidget *widget)
1649 static GdkColor color;
1650 static GtkWidget *done = NULL;
1656 style = gtk_widget_get_style(widget);
1657 memcpy(&color, &style->base[GTK_STATE_NORMAL], sizeof(color));
1658 shift_color(&color, -1, 0);
1665 static void vflist_listview_color_cb(GtkTreeViewColumn *tree_column, GtkCellRenderer *cell,
1666 GtkTreeModel *tree_model, GtkTreeIter *iter, gpointer data)
1668 ViewFile *vf = data;
1671 gtk_tree_model_get(tree_model, iter, FILE_COLUMN_COLOR, &set, -1);
1672 g_object_set(G_OBJECT(cell),
1673 "cell-background-gdk", vflist_listview_color_shifted(vf->listview),
1674 "cell-background-set", set, NULL);
1677 static void vflist_listview_add_column(ViewFile *vf, gint n, const gchar *title, gint image, gint right_justify, gint expand)
1679 GtkTreeViewColumn *column;
1680 GtkCellRenderer *renderer;
1682 column = gtk_tree_view_column_new();
1683 gtk_tree_view_column_set_title(column, title);
1684 gtk_tree_view_column_set_min_width(column, 4);
1688 gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_GROW_ONLY);
1689 renderer = gtk_cell_renderer_text_new();
1692 g_object_set(G_OBJECT(renderer), "xalign", 1.0, NULL);
1694 gtk_tree_view_column_pack_start(column, renderer, TRUE);
1695 gtk_tree_view_column_add_attribute(column, renderer, "text", n);
1697 gtk_tree_view_column_set_expand(column, TRUE);
1701 gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_FIXED);
1702 renderer = gtk_cell_renderer_pixbuf_new();
1703 cell_renderer_height_override(renderer);
1704 gtk_tree_view_column_pack_start(column, renderer, TRUE);
1705 gtk_tree_view_column_add_attribute(column, renderer, "pixbuf", n);
1708 gtk_tree_view_column_set_cell_data_func(column, renderer, vflist_listview_color_cb, vf, NULL);
1709 g_object_set_data(G_OBJECT(column), "column_store_idx", GUINT_TO_POINTER(n));
1710 g_object_set_data(G_OBJECT(renderer), "column_store_idx", GUINT_TO_POINTER(n));
1712 gtk_tree_view_append_column(GTK_TREE_VIEW(vf->listview), column);
1715 static void vflist_listview_mark_toggled_cb(GtkCellRendererToggle *cell, gchar *path_str, gpointer data)
1717 ViewFile *vf = data;
1718 GtkTreeStore *store;
1719 GtkTreePath *path = gtk_tree_path_new_from_string(path_str);
1725 store = GTK_TREE_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview)));
1726 if (!path || !gtk_tree_model_get_iter(GTK_TREE_MODEL(store), &iter, path))
1729 col_idx = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(cell), "column_store_idx"));
1731 g_assert(col_idx >= FILE_COLUMN_MARKS && col_idx <= FILE_COLUMN_MARKS_LAST);
1733 gtk_tree_model_get(GTK_TREE_MODEL(store), &iter, FILE_COLUMN_POINTER, &fd, col_idx, &mark, -1);
1735 file_data_unregister_notify_func(vf_notify_cb, vf); /* we don't need the notification */
1736 file_data_set_mark(fd, col_idx - FILE_COLUMN_MARKS, mark);
1737 file_data_register_notify_func(vf_notify_cb, vf, NOTIFY_PRIORITY_MEDIUM);
1739 gtk_tree_store_set(store, &iter, col_idx, mark, -1);
1740 gtk_tree_path_free(path);
1743 static void vflist_listview_add_column_toggle(ViewFile *vf, gint n, const gchar *title)
1745 GtkTreeViewColumn *column;
1746 GtkCellRenderer *renderer;
1747 GtkTreeStore *store;
1750 store = GTK_TREE_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(vf->listview)));
1752 renderer = gtk_cell_renderer_toggle_new();
1753 column = gtk_tree_view_column_new_with_attributes(title, renderer, "active", n, NULL);
1755 gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_FIXED);
1756 g_object_set_data(G_OBJECT(column), "column_store_idx", GUINT_TO_POINTER(n));
1757 g_object_set_data(G_OBJECT(renderer), "column_store_idx", GUINT_TO_POINTER(n));
1759 index = gtk_tree_view_append_column(GTK_TREE_VIEW(vf->listview), column);
1760 gtk_tree_view_column_set_fixed_width(column, 16);
1761 gtk_tree_view_column_set_visible(column, vf->marks_enabled);
1764 g_signal_connect(G_OBJECT(renderer), "toggled", G_CALLBACK(vflist_listview_mark_toggled_cb), vf);
1768 *-----------------------------------------------------------------------------
1770 *-----------------------------------------------------------------------------
1773 gint vflist_set_fd(ViewFile *vf, FileData *dir_fd)
1775 if (!dir_fd) return FALSE;
1776 if (vf->dir_fd == dir_fd) return TRUE;
1778 file_data_unref(vf->dir_fd);
1779 vf->dir_fd = file_data_ref(dir_fd);
1781 /* force complete reload */
1782 vflist_store_clear(vf);
1784 filelist_free(vf->list);
1787 return vf_refresh(vf);
1790 void vflist_destroy_cb(GtkWidget *widget, gpointer data)
1792 ViewFile *vf = data;
1794 file_data_unregister_notify_func(vf_notify_cb, vf);
1796 vflist_select_idle_cancel(vf);
1797 vf_refresh_idle_cancel(vf);
1798 vflist_thumb_stop(vf);
1800 filelist_free(vf->list);
1803 ViewFile *vflist_new(ViewFile *vf, FileData *dir_fd)
1805 GtkTreeStore *store;
1806 GtkTreeSelection *selection;
1808 GType flist_types[FILE_COLUMN_COUNT];
1811 vf->info = g_new0(ViewFileInfoList, 1);
1813 VFLIST_INFO(vf, click_fd) = NULL;
1814 VFLIST_INFO(vf, select_fd) = NULL;
1815 VFLIST_INFO(vf, thumbs_enabled) = FALSE;
1817 VFLIST_INFO(vf, select_idle_id) = -1;
1819 flist_types[FILE_COLUMN_POINTER] = G_TYPE_POINTER;
1820 flist_types[FILE_COLUMN_VERSION] = G_TYPE_INT;
1821 flist_types[FILE_COLUMN_THUMB] = GDK_TYPE_PIXBUF;
1822 flist_types[FILE_COLUMN_NAME] = G_TYPE_STRING;
1823 flist_types[FILE_COLUMN_SIDECARS] = G_TYPE_STRING;
1824 flist_types[FILE_COLUMN_SIZE] = G_TYPE_STRING;
1825 flist_types[FILE_COLUMN_DATE] = G_TYPE_STRING;
1826 flist_types[FILE_COLUMN_COLOR] = G_TYPE_BOOLEAN;
1827 for (i = FILE_COLUMN_MARKS; i < FILE_COLUMN_MARKS + FILEDATA_MARKS_SIZE; i++)
1828 flist_types[i] = G_TYPE_BOOLEAN;
1830 store = gtk_tree_store_newv(FILE_COLUMN_COUNT, flist_types);
1832 vf->listview = gtk_tree_view_new_with_model(GTK_TREE_MODEL(store));
1833 g_object_unref(store);
1835 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(vf->listview));
1836 gtk_tree_selection_set_mode(GTK_TREE_SELECTION(selection), GTK_SELECTION_MULTIPLE);
1837 gtk_tree_selection_set_select_function(selection, vflist_select_cb, vf, NULL);
1839 gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(vf->listview), FALSE);
1840 gtk_tree_view_set_enable_search(GTK_TREE_VIEW(vf->listview), FALSE);
1842 vflist_listview_add_column(vf, FILE_COLUMN_THUMB, "", TRUE, FALSE, FALSE);
1844 for (i = 0; i < FILEDATA_MARKS_SIZE; i++)
1845 vflist_listview_add_column_toggle(vf, i + FILE_COLUMN_MARKS, "");
1847 vflist_listview_add_column(vf, FILE_COLUMN_NAME, _("Name"), FALSE, FALSE, FALSE);
1848 vflist_listview_add_column(vf, FILE_COLUMN_SIDECARS, _("SC"), FALSE, FALSE, FALSE);
1850 vflist_listview_add_column(vf, FILE_COLUMN_SIZE, _("Size"), FALSE, TRUE, FALSE);
1851 vflist_listview_add_column(vf, FILE_COLUMN_DATE, _("Date"), FALSE, TRUE, FALSE);
1853 file_data_register_notify_func(vf_notify_cb, vf, NOTIFY_PRIORITY_MEDIUM);
1857 void vflist_thumb_set(ViewFile *vf, gint enable)
1859 if (VFLIST_INFO(vf, thumbs_enabled) == enable) return;
1861 VFLIST_INFO(vf, thumbs_enabled) = enable;
1862 if (vf->layout) vf_refresh(vf);
1865 void vflist_marks_set(ViewFile *vf, gint enable)
1867 GList *columns, *work;
1869 if (vf->marks_enabled == enable) return;
1871 vf->marks_enabled = enable;
1873 columns = gtk_tree_view_get_columns(GTK_TREE_VIEW(vf->listview));
1878 GtkTreeViewColumn *column = work->data;
1879 gint col_idx = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(column), "column_store_idx"));
1882 if (col_idx <= FILE_COLUMN_MARKS_LAST && col_idx >= FILE_COLUMN_MARKS)
1883 gtk_tree_view_column_set_visible(column, enable);
1886 g_list_free(columns);